SEBSERV-301 implementation
This commit is contained in:
parent
a141eccfa1
commit
71ae9fc755
12 changed files with 471 additions and 108 deletions
|
@ -270,4 +270,14 @@ public class POSTMapper {
|
||||||
this.params.putIfAbsent(name, Arrays.asList(value));
|
this.params.putIfAbsent(name, Arrays.asList(value));
|
||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("POSTMapper [params=");
|
||||||
|
builder.append(this.params);
|
||||||
|
builder.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,8 @@ public final class LmsSetup implements GrantEntity, Activatable {
|
||||||
OPEN_EDX(Features.COURSE_API, Features.SEB_RESTRICTION),
|
OPEN_EDX(Features.COURSE_API, Features.SEB_RESTRICTION),
|
||||||
/** The Moodle binding features only the course access API so far */
|
/** The Moodle binding features only the course access API so far */
|
||||||
MOODLE(Features.COURSE_API /* , Features.SEB_RESTRICTION */),
|
MOODLE(Features.COURSE_API /* , Features.SEB_RESTRICTION */),
|
||||||
|
/** The Moodle binding features with SEB Server integration plugin for fully featured */
|
||||||
|
MOODLE_PLUGIN(Features.COURSE_API, Features.SEB_RESTRICTION),
|
||||||
/** The Ans Delft binding is on the way */
|
/** The Ans Delft binding is on the way */
|
||||||
ANS_DELFT(Features.COURSE_API, Features.SEB_RESTRICTION),
|
ANS_DELFT(Features.COURSE_API, Features.SEB_RESTRICTION),
|
||||||
/** The OpenOLAT binding is on the way */
|
/** The OpenOLAT binding is on the way */
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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 org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public interface MoodleAPIRestTemplate {
|
||||||
|
|
||||||
|
String URI_VAR_USER_NAME = "username";
|
||||||
|
String URI_VAR_PASSWORD = "pwd";
|
||||||
|
String URI_VAR_SERVICE = "service";
|
||||||
|
|
||||||
|
String MOODLE_DEFAULT_TOKEN_REQUEST_PATH =
|
||||||
|
"/login/token.php?username={" + URI_VAR_USER_NAME +
|
||||||
|
"}&password={" + URI_VAR_PASSWORD + "}&service={" + URI_VAR_SERVICE + "}";
|
||||||
|
|
||||||
|
String MOODLE_DEFAULT_REST_API_PATH = "/webservice/rest/server.php";
|
||||||
|
String REST_REQUEST_TOKEN_NAME = "wstoken";
|
||||||
|
String REST_REQUEST_FUNCTION_NAME = "wsfunction";
|
||||||
|
String REST_REQUEST_FORMAT_NAME = "moodlewsrestformat";
|
||||||
|
|
||||||
|
String getService();
|
||||||
|
|
||||||
|
void setService(String service);
|
||||||
|
|
||||||
|
CharSequence getAccessToken();
|
||||||
|
|
||||||
|
void testAPIConnection(String... functions);
|
||||||
|
|
||||||
|
String callMoodleAPIFunction(String functionName);
|
||||||
|
|
||||||
|
String callMoodleAPIFunction(
|
||||||
|
final String functionName,
|
||||||
|
final MultiValueMap<String, String> queryAttributes);
|
||||||
|
|
||||||
|
String callMoodleAPIFunction(
|
||||||
|
final String functionName,
|
||||||
|
final MultiValueMap<String, String> queryParams,
|
||||||
|
final MultiValueMap<String, String> queryAttributes);
|
||||||
|
|
||||||
|
/** This maps a Moodle warning JSON object */
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
static final class Warning {
|
||||||
|
final String item;
|
||||||
|
final String itemid;
|
||||||
|
final String warningcode;
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Warning(
|
||||||
|
@JsonProperty(value = "item") final String item,
|
||||||
|
@JsonProperty(value = "itemid") final String itemid,
|
||||||
|
@JsonProperty(value = "warningcode") final String warningcode,
|
||||||
|
@JsonProperty(value = "message") final String message) {
|
||||||
|
|
||||||
|
this.item = item;
|
||||||
|
this.itemid = itemid;
|
||||||
|
this.warningcode = warningcode;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("Warning [item=");
|
||||||
|
builder.append(this.item);
|
||||||
|
builder.append(", itemid=");
|
||||||
|
builder.append(this.itemid);
|
||||||
|
builder.append(", warningcode=");
|
||||||
|
builder.append(this.warningcode);
|
||||||
|
builder.append(", message=");
|
||||||
|
builder.append(this.message);
|
||||||
|
builder.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -57,11 +57,11 @@ public class MoodleRestTemplateFactory {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MoodleRestTemplateFactory.class);
|
private static final Logger log = LoggerFactory.getLogger(MoodleRestTemplateFactory.class);
|
||||||
|
|
||||||
final JSONMapper jsonMapper;
|
public final JSONMapper jsonMapper;
|
||||||
final APITemplateDataSupplier apiTemplateDataSupplier;
|
public final APITemplateDataSupplier apiTemplateDataSupplier;
|
||||||
final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
|
public final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
|
||||||
final ClientCredentialService clientCredentialService;
|
public final ClientCredentialService clientCredentialService;
|
||||||
final Set<String> knownTokenAccessPaths;
|
public final Set<String> knownTokenAccessPaths;
|
||||||
|
|
||||||
public MoodleRestTemplateFactory(
|
public MoodleRestTemplateFactory(
|
||||||
final JSONMapper jsonMapper,
|
final JSONMapper jsonMapper,
|
||||||
|
@ -75,11 +75,12 @@ public class MoodleRestTemplateFactory {
|
||||||
this.clientCredentialService = clientCredentialService;
|
this.clientCredentialService = clientCredentialService;
|
||||||
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
|
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
|
||||||
|
|
||||||
this.knownTokenAccessPaths = new HashSet<>();
|
final Set<String> paths = new HashSet<>();
|
||||||
this.knownTokenAccessPaths.add(MoodleAPIRestTemplate.MOODLE_DEFAULT_TOKEN_REQUEST_PATH);
|
paths.add(MoodleAPIRestTemplate.MOODLE_DEFAULT_TOKEN_REQUEST_PATH);
|
||||||
if (alternativeTokenRequestPaths != null) {
|
if (alternativeTokenRequestPaths != null) {
|
||||||
this.knownTokenAccessPaths.addAll(Arrays.asList(alternativeTokenRequestPaths));
|
paths.addAll(Arrays.asList(alternativeTokenRequestPaths));
|
||||||
}
|
}
|
||||||
|
this.knownTokenAccessPaths = Utils.immutableSetOf(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
APITemplateDataSupplier getApiTemplateDataSupplier() {
|
APITemplateDataSupplier getApiTemplateDataSupplier() {
|
||||||
|
@ -125,7 +126,7 @@ public class MoodleRestTemplateFactory {
|
||||||
return LmsSetupTestResult.ofOkay(LmsType.MOODLE);
|
return LmsSetupTestResult.ofOkay(LmsType.MOODLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<MoodleAPIRestTemplate> createRestTemplate() {
|
public Result<MoodleAPIRestTemplate> createRestTemplate() {
|
||||||
|
|
||||||
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ public class MoodleRestTemplateFactory {
|
||||||
") on paths: " + this.knownTokenAccessPaths));
|
") on paths: " + this.knownTokenAccessPaths));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<MoodleAPIRestTemplate> createRestTemplate(final String accessTokenPath) {
|
public Result<MoodleAPIRestTemplate> createRestTemplate(final String accessTokenPath) {
|
||||||
|
|
||||||
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
||||||
|
|
||||||
|
@ -162,8 +163,9 @@ public class MoodleRestTemplateFactory {
|
||||||
.getPlainClientSecret(credentials)
|
.getPlainClientSecret(credentials)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
final MoodleAPIRestTemplate restTemplate = new MoodleAPIRestTemplate(
|
final MoodleAPIRestTemplateImpl restTemplate = new MoodleAPIRestTemplateImpl(
|
||||||
this.jsonMapper,
|
this.jsonMapper,
|
||||||
|
this.apiTemplateDataSupplier,
|
||||||
lmsSetup.lmsApiUrl,
|
lmsSetup.lmsApiUrl,
|
||||||
accessTokenPath,
|
accessTokenPath,
|
||||||
lmsSetup.lmsRestApiToken,
|
lmsSetup.lmsRestApiToken,
|
||||||
|
@ -187,22 +189,13 @@ public class MoodleRestTemplateFactory {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MoodleAPIRestTemplate extends RestTemplate {
|
public static class MoodleAPIRestTemplateImpl extends RestTemplate implements MoodleAPIRestTemplate {
|
||||||
|
|
||||||
public static final String URI_VAR_USER_NAME = "username";
|
|
||||||
public static final String URI_VAR_PASSWORD = "pwd";
|
|
||||||
public static final String URI_VAR_SERVICE = "service";
|
|
||||||
|
|
||||||
private static final String MOODLE_DEFAULT_TOKEN_REQUEST_PATH =
|
|
||||||
"/login/token.php?username={" + URI_VAR_USER_NAME +
|
|
||||||
"}&password={" + URI_VAR_PASSWORD + "}&service={" + URI_VAR_SERVICE + "}";
|
|
||||||
|
|
||||||
private static final String MOODLE_DEFAULT_REST_API_PATH = "/webservice/rest/server.php";
|
|
||||||
private static final String REST_REQUEST_TOKEN_NAME = "wstoken";
|
|
||||||
private static final String REST_REQUEST_FUNCTION_NAME = "wsfunction";
|
|
||||||
private static final String REST_REQUEST_FORMAT_NAME = "moodlewsrestformat";
|
|
||||||
private static final String REST_API_TEST_FUNCTION = "core_webservice_get_site_info";
|
private static final String REST_API_TEST_FUNCTION = "core_webservice_get_site_info";
|
||||||
|
|
||||||
|
final JSONMapper jsonMapper;
|
||||||
|
final APITemplateDataSupplier apiTemplateDataSupplier;
|
||||||
|
|
||||||
private final String serverURL;
|
private final String serverURL;
|
||||||
private final String tokenPath;
|
private final String tokenPath;
|
||||||
|
|
||||||
|
@ -211,14 +204,18 @@ public class MoodleRestTemplateFactory {
|
||||||
private final Map<String, String> tokenReqURIVars;
|
private final Map<String, String> tokenReqURIVars;
|
||||||
private final HttpEntity<?> tokenReqEntity = new HttpEntity<>(new LinkedMultiValueMap<>());
|
private final HttpEntity<?> tokenReqEntity = new HttpEntity<>(new LinkedMultiValueMap<>());
|
||||||
|
|
||||||
protected MoodleAPIRestTemplate(
|
protected MoodleAPIRestTemplateImpl(
|
||||||
final JSONMapper jsonMapper,
|
final JSONMapper jsonMapper,
|
||||||
|
final APITemplateDataSupplier apiTemplateDataSupplier,
|
||||||
final String serverURL,
|
final String serverURL,
|
||||||
final String tokenPath,
|
final String tokenPath,
|
||||||
final CharSequence accessToken,
|
final CharSequence accessToken,
|
||||||
final CharSequence username,
|
final CharSequence username,
|
||||||
final CharSequence password) {
|
final CharSequence password) {
|
||||||
|
|
||||||
|
this.jsonMapper = jsonMapper;
|
||||||
|
this.apiTemplateDataSupplier = apiTemplateDataSupplier;
|
||||||
|
|
||||||
this.serverURL = serverURL;
|
this.serverURL = serverURL;
|
||||||
this.tokenPath = tokenPath;
|
this.tokenPath = tokenPath;
|
||||||
this.accessToken = StringUtils.isNotBlank(accessToken) ? accessToken : null;
|
this.accessToken = StringUtils.isNotBlank(accessToken) ? accessToken : null;
|
||||||
|
@ -230,14 +227,17 @@ public class MoodleRestTemplateFactory {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getService() {
|
public String getService() {
|
||||||
return this.tokenReqURIVars.get(URI_VAR_SERVICE);
|
return this.tokenReqURIVars.get(URI_VAR_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setService(final String service) {
|
public void setService(final String service) {
|
||||||
this.tokenReqURIVars.put(URI_VAR_SERVICE, service);
|
this.tokenReqURIVars.put(URI_VAR_SERVICE, service);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public CharSequence getAccessToken() {
|
public CharSequence getAccessToken() {
|
||||||
if (this.accessToken == null) {
|
if (this.accessToken == null) {
|
||||||
requestAccessToken();
|
requestAccessToken();
|
||||||
|
@ -246,22 +246,27 @@ public class MoodleRestTemplateFactory {
|
||||||
return this.accessToken;
|
return this.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void testAPIConnection(final String... functions) {
|
public void testAPIConnection(final String... functions) {
|
||||||
try {
|
try {
|
||||||
final String apiInfo = this.callMoodleAPIFunction(REST_API_TEST_FUNCTION);
|
final String apiInfo = this.callMoodleAPIFunction(REST_API_TEST_FUNCTION);
|
||||||
final WebserviceInfo webserviceInfo =
|
final WebserviceInfo webserviceInfo = this.jsonMapper.readValue(
|
||||||
MoodleRestTemplateFactory.this.jsonMapper.readValue(apiInfo, WebserviceInfo.class);
|
apiInfo,
|
||||||
|
WebserviceInfo.class);
|
||||||
|
|
||||||
if (StringUtils.isBlank(webserviceInfo.username) || StringUtils.isBlank(webserviceInfo.userid)) {
|
if (StringUtils.isBlank(webserviceInfo.username) || StringUtils.isBlank(webserviceInfo.userid)) {
|
||||||
throw new RuntimeException("Invalid WebserviceInfo: " + webserviceInfo);
|
throw new RuntimeException("Invalid WebserviceInfo: " + webserviceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> missingAPIFunctions = Arrays.stream(functions)
|
if (functions != null) {
|
||||||
.filter(f -> !webserviceInfo.functions.containsKey(f))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (!missingAPIFunctions.isEmpty()) {
|
final List<String> missingAPIFunctions = Arrays.stream(functions)
|
||||||
throw new RuntimeException("Missing Moodle Webservice API functions: " + missingAPIFunctions);
|
.filter(f -> !webserviceInfo.functions.containsKey(f))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (!missingAPIFunctions.isEmpty()) {
|
||||||
|
throw new RuntimeException("Missing Moodle Webservice API functions: " + missingAPIFunctions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (final RuntimeException re) {
|
} catch (final RuntimeException re) {
|
||||||
|
@ -271,16 +276,19 @@ public class MoodleRestTemplateFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String callMoodleAPIFunction(final String functionName) {
|
public String callMoodleAPIFunction(final String functionName) {
|
||||||
return callMoodleAPIFunction(functionName, null, null);
|
return callMoodleAPIFunction(functionName, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String callMoodleAPIFunction(
|
public String callMoodleAPIFunction(
|
||||||
final String functionName,
|
final String functionName,
|
||||||
final MultiValueMap<String, String> queryAttributes) {
|
final MultiValueMap<String, String> queryAttributes) {
|
||||||
return callMoodleAPIFunction(functionName, null, queryAttributes);
|
return callMoodleAPIFunction(functionName, null, queryAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String callMoodleAPIFunction(
|
public String callMoodleAPIFunction(
|
||||||
final String functionName,
|
final String functionName,
|
||||||
final MultiValueMap<String, String> queryParams,
|
final MultiValueMap<String, String> queryParams,
|
||||||
|
@ -319,9 +327,7 @@ public class MoodleRestTemplateFactory {
|
||||||
functionReqEntity,
|
functionReqEntity,
|
||||||
String.class);
|
String.class);
|
||||||
|
|
||||||
final LmsSetup lmsSetup = MoodleRestTemplateFactory.this.apiTemplateDataSupplier
|
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
||||||
.getLmsSetup();
|
|
||||||
|
|
||||||
if (response.getStatusCode() != HttpStatus.OK) {
|
if (response.getStatusCode() != HttpStatus.OK) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Failed to call Moodle webservice API function: " + functionName + " lms setup: " +
|
"Failed to call Moodle webservice API function: " + functionName + " lms setup: " +
|
||||||
|
@ -347,9 +353,7 @@ public class MoodleRestTemplateFactory {
|
||||||
|
|
||||||
private void requestAccessToken() {
|
private void requestAccessToken() {
|
||||||
|
|
||||||
final LmsSetup lmsSetup = MoodleRestTemplateFactory.this.apiTemplateDataSupplier
|
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
||||||
.getLmsSetup();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final ResponseEntity<String> response = super.exchange(
|
final ResponseEntity<String> response = super.exchange(
|
||||||
|
@ -369,7 +373,7 @@ public class MoodleRestTemplateFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final MoodleToken moodleToken = MoodleRestTemplateFactory.this.jsonMapper.readValue(
|
final MoodleToken moodleToken = this.jsonMapper.readValue(
|
||||||
response.getBody(),
|
response.getBody(),
|
||||||
MoodleToken.class);
|
MoodleToken.class);
|
||||||
|
|
|
@ -48,9 +48,11 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.CourseAccessAPI;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.CourseAccessAPI;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||||
|
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.MoodleRestTemplateFactory;
|
||||||
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.CourseDataShort;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseDataAsyncLoader.CourseQuizShort;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseDataAsyncLoader.CourseQuizShort;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleRestTemplateFactory.MoodleAPIRestTemplate;
|
|
||||||
|
|
||||||
/** Implements the LmsAPITemplate for Open edX LMS Course API access.
|
/** Implements the LmsAPITemplate for Open edX LMS Course API access.
|
||||||
*
|
*
|
||||||
|
@ -885,40 +887,4 @@ public class MoodleCourseAccess implements CourseAccessAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
|
||||||
static final class Warning {
|
|
||||||
final String item;
|
|
||||||
final String itemid;
|
|
||||||
final String warningcode;
|
|
||||||
final String message;
|
|
||||||
|
|
||||||
@JsonCreator
|
|
||||||
public Warning(
|
|
||||||
@JsonProperty(value = "item") final String item,
|
|
||||||
@JsonProperty(value = "itemid") final String itemid,
|
|
||||||
@JsonProperty(value = "warningcode") final String warningcode,
|
|
||||||
@JsonProperty(value = "message") final String message) {
|
|
||||||
|
|
||||||
this.item = item;
|
|
||||||
this.itemid = itemid;
|
|
||||||
this.warningcode = warningcode;
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append("Warning [item=");
|
|
||||||
builder.append(this.item);
|
|
||||||
builder.append(", itemid=");
|
|
||||||
builder.append(this.itemid);
|
|
||||||
builder.append(", warningcode=");
|
|
||||||
builder.append(this.warningcode);
|
|
||||||
builder.append(", message=");
|
|
||||||
builder.append(this.message);
|
|
||||||
builder.append("]");
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ import ch.ethz.seb.sebserver.gbl.async.AsyncService;
|
||||||
import ch.ethz.seb.sebserver.gbl.async.CircuitBreaker;
|
import ch.ethz.seb.sebserver.gbl.async.CircuitBreaker;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseAccess.Warning;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleRestTemplateFactory.MoodleAPIRestTemplate;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate.Warning;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
|
|
|
@ -30,7 +30,8 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionAPI;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionAPI;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleRestTemplateFactory.MoodleAPIRestTemplate;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory;
|
||||||
|
|
||||||
/** GET:
|
/** GET:
|
||||||
* http://yourmoodle.org/webservice/rest/server.php?wstoken={token}&moodlewsrestformat=json&wsfunction=seb_restriction&courseId=123
|
* http://yourmoodle.org/webservice/rest/server.php?wstoken={token}&moodlewsrestformat=json&wsfunction=seb_restriction&courseId=123
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
@ -28,10 +29,7 @@ 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.LmsAPITemplate;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory;
|
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.LmsAPITemplateAdapter;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseAccess;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseDataAsyncLoader;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseRestriction;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleRestTemplateFactory;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCheck;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCheck;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseAccess;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseAccess;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseRestriction;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseRestriction;
|
||||||
|
@ -43,6 +41,7 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
||||||
|
|
||||||
private final MoodlePluginCheck moodlePluginCheck;
|
private final MoodlePluginCheck moodlePluginCheck;
|
||||||
private final JSONMapper jsonMapper;
|
private final JSONMapper jsonMapper;
|
||||||
|
private final CacheManager cacheManager;
|
||||||
private final AsyncService asyncService;
|
private final AsyncService asyncService;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
private final ClientCredentialService clientCredentialService;
|
private final ClientCredentialService clientCredentialService;
|
||||||
|
@ -53,6 +52,7 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
||||||
protected MoodleLmsAPITemplateFactory(
|
protected MoodleLmsAPITemplateFactory(
|
||||||
final MoodlePluginCheck moodlePluginCheck,
|
final MoodlePluginCheck moodlePluginCheck,
|
||||||
final JSONMapper jsonMapper,
|
final JSONMapper jsonMapper,
|
||||||
|
final CacheManager cacheManager,
|
||||||
final AsyncService asyncService,
|
final AsyncService asyncService,
|
||||||
final Environment environment,
|
final Environment environment,
|
||||||
final ClientCredentialService clientCredentialService,
|
final ClientCredentialService clientCredentialService,
|
||||||
|
@ -62,6 +62,7 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
||||||
|
|
||||||
this.moodlePluginCheck = moodlePluginCheck;
|
this.moodlePluginCheck = moodlePluginCheck;
|
||||||
this.jsonMapper = jsonMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
|
this.cacheManager = cacheManager;
|
||||||
this.asyncService = asyncService;
|
this.asyncService = asyncService;
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.clientCredentialService = clientCredentialService;
|
this.clientCredentialService = clientCredentialService;
|
||||||
|
@ -87,9 +88,19 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
||||||
.getBean(MoodleCourseDataAsyncLoader.class);
|
.getBean(MoodleCourseDataAsyncLoader.class);
|
||||||
asyncLoaderPrototype.init(lmsSetup.getModelId());
|
asyncLoaderPrototype.init(lmsSetup.getModelId());
|
||||||
|
|
||||||
|
final MoodleRestTemplateFactory moodleRestTemplateFactory = new MoodleRestTemplateFactory(
|
||||||
|
this.jsonMapper,
|
||||||
|
apiTemplateDataSupplier,
|
||||||
|
this.clientCredentialService,
|
||||||
|
this.clientHttpRequestFactoryService,
|
||||||
|
this.alternativeTokenRequestPaths);
|
||||||
|
|
||||||
if (this.moodlePluginCheck.checkPluginAvailable(lmsSetup)) {
|
if (this.moodlePluginCheck.checkPluginAvailable(lmsSetup)) {
|
||||||
|
|
||||||
final MoodlePluginCourseAccess moodlePluginCourseAccess = new MoodlePluginCourseAccess();
|
final MoodlePluginCourseAccess moodlePluginCourseAccess = new MoodlePluginCourseAccess(
|
||||||
|
this.jsonMapper,
|
||||||
|
moodleRestTemplateFactory,
|
||||||
|
this.cacheManager);
|
||||||
final MoodlePluginCourseRestriction moodlePluginCourseRestriction = new MoodlePluginCourseRestriction();
|
final MoodlePluginCourseRestriction moodlePluginCourseRestriction = new MoodlePluginCourseRestriction();
|
||||||
|
|
||||||
return new LmsAPITemplateAdapter(
|
return new LmsAPITemplateAdapter(
|
||||||
|
@ -101,13 +112,6 @@ public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
final MoodleRestTemplateFactory moodleRestTemplateFactory = new MoodleRestTemplateFactory(
|
|
||||||
this.jsonMapper,
|
|
||||||
apiTemplateDataSupplier,
|
|
||||||
this.clientCredentialService,
|
|
||||||
this.clientHttpRequestFactoryService,
|
|
||||||
this.alternativeTokenRequestPaths);
|
|
||||||
|
|
||||||
final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess(
|
final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess(
|
||||||
this.jsonMapper,
|
this.jsonMapper,
|
||||||
moodleRestTemplateFactory,
|
moodleRestTemplateFactory,
|
|
@ -8,30 +8,96 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
||||||
|
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;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
|
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.CourseAccessAPI;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.CourseAccessAPI;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.AbstractCachedCourseAccess;
|
||||||
|
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.MoodleRestTemplateFactory;
|
||||||
|
|
||||||
public class MoodlePluginCourseAccess implements CourseAccessAPI {
|
public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess implements CourseAccessAPI {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MoodlePluginCourseAccess.class);
|
||||||
|
|
||||||
|
static final String COURSES_API_FUNCTION_NAME = "local_sebserver_get_courses";
|
||||||
|
static final String QUIZZES_BY_COURSES_API_FUNCTION_NAME = "local_sebserver_get_quizzes_by_courses";
|
||||||
|
static final String USERS_API_FUNCTION_NAME = "local_sebserver_get_users";
|
||||||
|
|
||||||
|
static final String CRITERIA_FROM_DATE = "from_date";
|
||||||
|
static final String CRITERIA_TO_DATE = "to_date";
|
||||||
|
static final String CRITERIA_LIMIT_FROM = "limitfrom";
|
||||||
|
static final String CRITERIA_LIMIT_NUM = "limitnum";
|
||||||
|
|
||||||
|
private final JSONMapper jsonMapper;
|
||||||
|
private final MoodleRestTemplateFactory moodleRestTemplateFactory;
|
||||||
|
|
||||||
|
private MoodleAPIRestTemplate restTemplate;
|
||||||
|
|
||||||
|
public MoodlePluginCourseAccess(
|
||||||
|
final JSONMapper jsonMapper,
|
||||||
|
final MoodleRestTemplateFactory moodleRestTemplateFactory,
|
||||||
|
final CacheManager cacheManager) {
|
||||||
|
super(cacheManager);
|
||||||
|
this.jsonMapper = jsonMapper;
|
||||||
|
this.moodleRestTemplateFactory = moodleRestTemplateFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LmsSetupTestResult testCourseAccessAPI() {
|
public LmsSetupTestResult testCourseAccessAPI() {
|
||||||
// TODO Auto-generated method stub
|
final LmsSetupTestResult attributesCheck = this.moodleRestTemplateFactory.test();
|
||||||
return null;
|
if (!attributesCheck.isOk()) {
|
||||||
|
return attributesCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Result<MoodleAPIRestTemplate> restTemplateRequest = getRestTemplate();
|
||||||
|
if (restTemplateRequest.hasError()) {
|
||||||
|
final String message = "Failed to gain access token from Moodle Rest API:\n tried token endpoints: " +
|
||||||
|
this.moodleRestTemplateFactory.knownTokenAccessPaths;
|
||||||
|
log.error(message + " cause: {}", restTemplateRequest.getError().getMessage());
|
||||||
|
return LmsSetupTestResult.ofTokenRequestError(LmsType.MOODLE_PLUGIN, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
final MoodleAPIRestTemplate restTemplate = restTemplateRequest.get();
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// restTemplate.testAPIConnection(
|
||||||
|
// COURSES_API_FUNCTION_NAME,
|
||||||
|
// QUIZZES_BY_COURSES_API_FUNCTION_NAME,
|
||||||
|
// 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());
|
||||||
|
// }
|
||||||
|
|
||||||
|
return LmsSetupTestResult.ofOkay(LmsType.MOODLE_PLUGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<List<QuizData>> getQuizzes(final FilterMap filterMap) {
|
public Result<List<QuizData>> getQuizzes(final FilterMap filterMap) {
|
||||||
|
System.out.println("***************** filterMap: " + filterMap);
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return null;
|
return Result.of(Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,12 +112,6 @@ public class MoodlePluginCourseAccess implements CourseAccessAPI {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearCourseCache() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeUserId) {
|
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeUserId) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
@ -70,4 +130,119 @@ public class MoodlePluginCourseAccess implements CourseAccessAPI {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Long getLmsSetupId() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<MoodleAPIRestTemplate> getRestTemplate() {
|
||||||
|
if (this.restTemplate == null) {
|
||||||
|
final Result<MoodleAPIRestTemplate> templateRequest = this.moodleRestTemplateFactory
|
||||||
|
.createRestTemplate();
|
||||||
|
if (templateRequest.hasError()) {
|
||||||
|
return templateRequest;
|
||||||
|
} else {
|
||||||
|
this.restTemplate = templateRequest.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.of(this.restTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Mapping Classes ---
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
private static final class Courses {
|
||||||
|
final Collection<CourseData> courses;
|
||||||
|
final Collection<Warning> warnings;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
protected Courses(
|
||||||
|
@JsonProperty(value = "courses") final Collection<CourseData> courses,
|
||||||
|
@JsonProperty(value = "warnings") final Collection<Warning> warnings) {
|
||||||
|
this.courses = courses;
|
||||||
|
this.warnings = warnings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Maps the Moodle course API course data */
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
private static final class CourseData {
|
||||||
|
final String id;
|
||||||
|
final String short_name;
|
||||||
|
final String idnumber;
|
||||||
|
final String full_name;
|
||||||
|
final String display_name;
|
||||||
|
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<CourseQuiz> quizzes = new ArrayList<>();
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
protected CourseData(
|
||||||
|
@JsonProperty(value = "id") final String id,
|
||||||
|
@JsonProperty(value = "shortname") final String short_name,
|
||||||
|
@JsonProperty(value = "idnumber") final String idnumber,
|
||||||
|
@JsonProperty(value = "fullname") final String full_name,
|
||||||
|
@JsonProperty(value = "displayname") final String display_name,
|
||||||
|
@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.full_name = full_name;
|
||||||
|
this.display_name = display_name;
|
||||||
|
this.start_date = start_date;
|
||||||
|
this.end_date = end_date;
|
||||||
|
this.time_created = time_created;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
private static final class CourseQuizData {
|
||||||
|
final Collection<CourseQuiz> quizzes;
|
||||||
|
final Collection<Warning> warnings;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
protected CourseQuizData(
|
||||||
|
@JsonProperty(value = "quizzes") final Collection<CourseQuiz> quizzes,
|
||||||
|
@JsonProperty(value = "warnings") final Collection<Warning> warnings) {
|
||||||
|
this.quizzes = quizzes;
|
||||||
|
this.warnings = warnings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
static final class CourseQuiz {
|
||||||
|
final String id;
|
||||||
|
final String course;
|
||||||
|
final String course_module;
|
||||||
|
final String name;
|
||||||
|
final String intro; // HTML
|
||||||
|
final Long time_open; // unix-time seconds UTC
|
||||||
|
final Long time_close; // unix-time seconds UTC
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
protected CourseQuiz(
|
||||||
|
@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 = "intro") final String intro,
|
||||||
|
@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.intro = intro;
|
||||||
|
this.time_open = time_open;
|
||||||
|
this.time_close = time_close;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction;
|
import ch.ethz.seb.sebserver.gbl.model.exam.SEBRestriction;
|
||||||
|
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;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionAPI;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.SEBRestrictionAPI;
|
||||||
|
@ -19,7 +20,7 @@ public class MoodlePluginCourseRestriction implements SEBRestrictionAPI {
|
||||||
@Override
|
@Override
|
||||||
public LmsSetupTestResult testCourseRestrictionAPI() {
|
public LmsSetupTestResult testCourseRestrictionAPI() {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return null;
|
return LmsSetupTestResult.ofOkay(LmsType.MOODLE_PLUGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
||||||
|
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;
|
||||||
|
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.MoodleRestTemplateFactory;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleCourseDataAsyncLoader;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Service
|
||||||
|
@WebServiceProfile
|
||||||
|
public class MooldePluginLmsAPITemplateFactory 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 ApplicationContext applicationContext;
|
||||||
|
private final String[] alternativeTokenRequestPaths;
|
||||||
|
|
||||||
|
protected MooldePluginLmsAPITemplateFactory(
|
||||||
|
final MoodlePluginCheck moodlePluginCheck,
|
||||||
|
final JSONMapper jsonMapper,
|
||||||
|
final CacheManager cacheManager,
|
||||||
|
final AsyncService asyncService,
|
||||||
|
final Environment environment,
|
||||||
|
final ClientCredentialService clientCredentialService,
|
||||||
|
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.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
this.alternativeTokenRequestPaths = (alternativeTokenRequestPaths != null)
|
||||||
|
? StringUtils.split(alternativeTokenRequestPaths, Constants.LIST_SEPARATOR)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LmsType lmsType() {
|
||||||
|
return LmsType.MOODLE_PLUGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<LmsAPITemplate> create(final APITemplateDataSupplier apiTemplateDataSupplier) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
final LmsSetup lmsSetup = apiTemplateDataSupplier.getLmsSetup();
|
||||||
|
final MoodleCourseDataAsyncLoader asyncLoaderPrototype = this.applicationContext
|
||||||
|
.getBean(MoodleCourseDataAsyncLoader.class);
|
||||||
|
asyncLoaderPrototype.init(lmsSetup.getModelId());
|
||||||
|
|
||||||
|
final MoodleRestTemplateFactory moodleRestTemplateFactory = new MoodleRestTemplateFactory(
|
||||||
|
this.jsonMapper,
|
||||||
|
apiTemplateDataSupplier,
|
||||||
|
this.clientCredentialService,
|
||||||
|
this.clientHttpRequestFactoryService,
|
||||||
|
this.alternativeTokenRequestPaths);
|
||||||
|
|
||||||
|
final MoodlePluginCourseAccess moodlePluginCourseAccess = new MoodlePluginCourseAccess(
|
||||||
|
this.jsonMapper,
|
||||||
|
moodleRestTemplateFactory,
|
||||||
|
this.cacheManager);
|
||||||
|
|
||||||
|
final MoodlePluginCourseRestriction moodlePluginCourseRestriction = new MoodlePluginCourseRestriction();
|
||||||
|
|
||||||
|
return new LmsAPITemplateAdapter(
|
||||||
|
this.asyncService,
|
||||||
|
this.environment,
|
||||||
|
apiTemplateDataSupplier,
|
||||||
|
moodlePluginCourseAccess,
|
||||||
|
moodlePluginCourseRestriction);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -27,7 +27,8 @@ 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.model.institution.LmsSetupTestResult.ErrorType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
|
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.legacy.MoodleRestTemplateFactory.MoodleAPIRestTemplate;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory.MoodleAPIRestTemplateImpl;
|
||||||
|
|
||||||
public class MoodleCourseAccessTest {
|
public class MoodleCourseAccessTest {
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ public class MoodleCourseAccessTest {
|
||||||
public void testGetExamineeAccountDetails() {
|
public void testGetExamineeAccountDetails() {
|
||||||
|
|
||||||
final MoodleRestTemplateFactory moodleRestTemplateFactory = mock(MoodleRestTemplateFactory.class);
|
final MoodleRestTemplateFactory moodleRestTemplateFactory = mock(MoodleRestTemplateFactory.class);
|
||||||
final MoodleAPIRestTemplate moodleAPIRestTemplate = mock(MoodleAPIRestTemplate.class);
|
final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class);
|
||||||
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate));
|
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate));
|
||||||
when(moodleAPIRestTemplate.callMoodleAPIFunction(
|
when(moodleAPIRestTemplate.callMoodleAPIFunction(
|
||||||
anyString(),
|
anyString(),
|
||||||
|
@ -132,7 +133,7 @@ public class MoodleCourseAccessTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInitAPIAccessError2() {
|
public void testInitAPIAccessError2() {
|
||||||
final MoodleRestTemplateFactory moodleRestTemplateFactory = mock(MoodleRestTemplateFactory.class);
|
final MoodleRestTemplateFactory moodleRestTemplateFactory = mock(MoodleRestTemplateFactory.class);
|
||||||
final MoodleAPIRestTemplate moodleAPIRestTemplate = mock(MoodleAPIRestTemplate.class);
|
final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class);
|
||||||
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate));
|
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate));
|
||||||
doThrow(RuntimeException.class).when(moodleAPIRestTemplate).testAPIConnection(any());
|
doThrow(RuntimeException.class).when(moodleAPIRestTemplate).testAPIConnection(any());
|
||||||
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
|
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
|
||||||
|
@ -153,7 +154,7 @@ public class MoodleCourseAccessTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInitAPIAccessOK() {
|
public void testInitAPIAccessOK() {
|
||||||
final MoodleRestTemplateFactory moodleRestTemplateFactory = mock(MoodleRestTemplateFactory.class);
|
final MoodleRestTemplateFactory moodleRestTemplateFactory = mock(MoodleRestTemplateFactory.class);
|
||||||
final MoodleAPIRestTemplate moodleAPIRestTemplate = mock(MoodleAPIRestTemplate.class);
|
final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class);
|
||||||
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate));
|
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate));
|
||||||
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
|
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue