improved LMS Setup API

This commit is contained in:
anhefti 2021-03-15 13:34:22 +01:00
parent bbcbc318a9
commit 7f2b662244
6 changed files with 120 additions and 34 deletions

View file

@ -152,7 +152,7 @@ public interface LmsAPITemplate {
* @return Result refer to the given Exam if successful or to an error if not */ * @return Result refer to the given Exam if successful or to an error if not */
Result<Exam> releaseSEBClientRestriction(Exam exam); Result<Exam> releaseSEBClientRestriction(Exam exam);
/** This is used th verify if a given LMS Setup URL is available (valid) /** This is used to verify if a given LMS Setup URL is available (valid)
* *
* @param urlString the URL string given by the LMS Setup attribute * @param urlString the URL string given by the LMS Setup attribute
* @return true if SEB Server was able to ping the address. */ * @return true if SEB Server was able to ping the address. */

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 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;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.client.ProxyData;
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.util.Result;
public interface LmsAPITemplateFactory {
LmsType lmsType();
Result<LmsAPITemplate> create(
final LmsSetup lmsSetup,
final ClientCredentials credentials,
final ProxyData proxyData);
}

View file

@ -9,10 +9,13 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl; package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -29,16 +32,15 @@ import ch.ethz.seb.sebserver.gbl.client.ProxyData;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
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; 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;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; 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.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO;
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.LmsAPITemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.edx.OpenEdxLmsAPITemplateFactory; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleLmsAPITemplateFactory;
@Lazy @Lazy
@Service @Service
@ -49,24 +51,23 @@ public class LmsAPIServiceImpl implements LmsAPIService {
private final LmsSetupDAO lmsSetupDAO; private final LmsSetupDAO lmsSetupDAO;
private final ClientCredentialService clientCredentialService; private final ClientCredentialService clientCredentialService;
private final WebserviceInfo webserviceInfo; private final EnumMap<LmsType, LmsAPITemplateFactory> templateFactories;
private final OpenEdxLmsAPITemplateFactory openEdxLmsAPITemplateFactory;
private final MoodleLmsAPITemplateFactory moodleLmsAPITemplateFactory;
private final Map<CacheKey, LmsAPITemplate> cache = new ConcurrentHashMap<>(); private final Map<CacheKey, LmsAPITemplate> cache = new ConcurrentHashMap<>();
public LmsAPIServiceImpl( public LmsAPIServiceImpl(
final OpenEdxLmsAPITemplateFactory openEdxLmsAPITemplateFactory,
final MoodleLmsAPITemplateFactory moodleLmsAPITemplateFactory,
final LmsSetupDAO lmsSetupDAO, final LmsSetupDAO lmsSetupDAO,
final ClientCredentialService clientCredentialService, final ClientCredentialService clientCredentialService,
final WebserviceInfo webserviceInfo) { final Collection<LmsAPITemplateFactory> lmsAPITemplateFactories) {
this.openEdxLmsAPITemplateFactory = openEdxLmsAPITemplateFactory;
this.moodleLmsAPITemplateFactory = moodleLmsAPITemplateFactory;
this.lmsSetupDAO = lmsSetupDAO; this.lmsSetupDAO = lmsSetupDAO;
this.clientCredentialService = clientCredentialService; this.clientCredentialService = clientCredentialService;
this.webserviceInfo = webserviceInfo;
this.templateFactories = new EnumMap<>(lmsAPITemplateFactories
.stream()
.collect(Collectors.toMap(
t -> t.lmsType(),
Function.identity())));
} }
/** Listen to LmsSetupChangeEvent to release an affected LmsAPITemplate from cache /** Listen to LmsSetupChangeEvent to release an affected LmsAPITemplate from cache
@ -237,24 +238,13 @@ public class LmsAPIServiceImpl implements LmsAPIService {
final ClientCredentials credentials, final ClientCredentials credentials,
final ProxyData proxyData) { final ProxyData proxyData) {
switch (lmsSetup.lmsType) { if (!this.templateFactories.containsKey(lmsSetup.lmsType)) {
case MOCKUP: throw new UnsupportedOperationException("No support for LMS Type: " + lmsSetup.lmsType);
return new MockupLmsAPITemplate(
lmsSetup,
credentials,
this.webserviceInfo);
case OPEN_EDX:
return this.openEdxLmsAPITemplateFactory
.create(lmsSetup, credentials, proxyData)
.getOrThrow();
case MOODLE:
return this.moodleLmsAPITemplateFactory
.create(lmsSetup, credentials, proxyData)
.getOrThrow();
default:
throw new UnsupportedOperationException("No support for LMS Type: " + lmsSetup.lmsType);
} }
final LmsAPITemplateFactory lmsAPITemplateFactory = this.templateFactories.get(lmsSetup.lmsType);
return lmsAPITemplateFactory.create(lmsSetup, credentials, proxyData)
.getOrThrow();
} }
private static final class CacheKey { private static final class CacheKey {

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 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;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.client.ProxyData;
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.WebserviceInfo;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory;
@Lazy
@Service
@WebServiceProfile
public class MockLmsAPITemplateFactory implements LmsAPITemplateFactory {
private final WebserviceInfo webserviceInfo;
public MockLmsAPITemplateFactory(final WebserviceInfo webserviceInfo) {
this.webserviceInfo = webserviceInfo;
}
@Override
public LmsType lmsType() {
return LmsType.MOCKUP;
}
@Override
public Result<LmsAPITemplate> create(
final LmsSetup lmsSetup,
final ClientCredentials credentials,
final ProxyData proxyData) {
return Result.tryCatch(() -> new MockupLmsAPITemplate(
lmsSetup,
credentials,
this.webserviceInfo));
}
}

View file

@ -22,14 +22,17 @@ import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.client.ProxyData; import ch.ethz.seb.sebserver.gbl.client.ProxyData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; 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.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory;
@Lazy @Lazy
@Service @Service
@WebServiceProfile @WebServiceProfile
public class OpenEdxLmsAPITemplateFactory { public class OpenEdxLmsAPITemplateFactory implements LmsAPITemplateFactory {
private final JSONMapper jsonMapper; private final JSONMapper jsonMapper;
private final WebserviceInfo webserviceInfo; private final WebserviceInfo webserviceInfo;
@ -62,7 +65,13 @@ public class OpenEdxLmsAPITemplateFactory {
this.restrictionAPIPushCount = restrictionAPIPushCount; this.restrictionAPIPushCount = restrictionAPIPushCount;
} }
public Result<OpenEdxLmsAPITemplate> create( @Override
public LmsType lmsType() {
return LmsType.OPEN_EDX;
}
@Override
public Result<LmsAPITemplate> create(
final LmsSetup lmsSetup, final LmsSetup lmsSetup,
final ClientCredentials credentials, final ClientCredentials credentials,
final ProxyData proxyData) { final ProxyData proxyData) {

View file

@ -23,13 +23,16 @@ import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.client.ProxyData; import ch.ethz.seb.sebserver.gbl.client.ProxyData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; 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.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory;
@Lazy @Lazy
@Service @Service
@WebServiceProfile @WebServiceProfile
public class MoodleLmsAPITemplateFactory { public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
private final JSONMapper jsonMapper; private final JSONMapper jsonMapper;
private final AsyncService asyncService; private final AsyncService asyncService;
@ -59,7 +62,13 @@ public class MoodleLmsAPITemplateFactory {
: null; : null;
} }
public Result<MoodleLmsAPITemplate> create( @Override
public LmsType lmsType() {
return LmsType.MOODLE;
}
@Override
public Result<LmsAPITemplate> create(
final LmsSetup lmsSetup, final LmsSetup lmsSetup,
final ClientCredentials credentials, final ClientCredentials credentials,
final ProxyData proxyData) { final ProxyData proxyData) {