diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java index 595ca273..87be7b36 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java @@ -61,7 +61,7 @@ public final class LmsSetup implements GrantEntity, Activatable { /** The Moodle binding features only the course access API so far */ MOODLE(Features.COURSE_API /* , Features.SEB_RESTRICTION */), /** 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 */ OPEN_OLAT(/* Features.COURSE_API , Features.SEB_RESTRICTION */); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java index 0d6d50a2..c8e9fa16 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplate.java @@ -20,10 +20,16 @@ import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.springframework.cache.CacheManager; import org.springframework.core.env.Environment; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; +import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.async.AsyncService; +import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; +import ch.ethz.seb.sebserver.gbl.client.ProxyData; import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; import ch.ethz.seb.sebserver.gbl.model.exam.Chapters; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; @@ -45,11 +51,18 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.AbstractCachedCour public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements LmsAPITemplate { // TODO add needed dependencies here + + private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; + private final ClientCredentialService clientCredentialService; private final APITemplateDataSupplier apiTemplateDataSupplier; private final Long lmsSetupId; protected AnsLmsAPITemplate( + // TODO if you need more dependencies inject them here and set the reference + + final ClientHttpRequestFactoryService clientHttpRequestFactoryService, + final ClientCredentialService clientCredentialService, final APITemplateDataSupplier apiTemplateDataSupplier, final AsyncService asyncService, final Environment environment, @@ -57,6 +70,8 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms super(asyncService, environment, cacheManager); + this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; + this.clientCredentialService = clientCredentialService; this.apiTemplateDataSupplier = apiTemplateDataSupplier; this.lmsSetupId = apiTemplateDataSupplier.getLmsSetup().id; } @@ -191,38 +206,41 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms @Override protected Supplier> allQuizzesSupplier(final FilterMap filterMap) { + @SuppressWarnings("unused") final String quizName = filterMap.getString(QuizData.FILTER_ATTR_QUIZ_NAME); + @SuppressWarnings("unused") final DateTime quizFromTime = (filterMap != null) ? filterMap.getQuizFromTime() : null; - // TODO get all course / quiz data from remote LMS that matches the filter criteria. - // put loaded QuizData to the cache: super.putToCache(quizDataCollection); - // before returning it. - return () -> { + + // TODO get all course / quiz data from remote LMS that matches the filter criteria. + // put loaded QuizData to the cache: super.putToCache(quizDataCollection); + // before returning it. + throw new RuntimeException("TODO"); }; } @Override protected Supplier> quizzesSupplier(final Set ids) { - - // TODO get all quiz / course data for specified identifiers from remote LMS - // and put it to the cache: super.putToCache(quizDataCollection); - // before returning it. - return () -> { + + // TODO get all quiz / course data for specified identifiers from remote LMS + // and put it to the cache: super.putToCache(quizDataCollection); + // before returning it. + throw new RuntimeException("TODO"); }; } @Override protected Supplier quizSupplier(final String id) { - - // TODO get the specified quiz / course data for specified identifier from remote LMS - // and put it to the cache: super.putToCache(quizDataCollection); - // before returning it. - return () -> { + + // TODO get the specified quiz / course data for specified identifier from remote LMS + // and put it to the cache: super.putToCache(quizDataCollection); + // before returning it. + throw new RuntimeException("TODO"); }; } @@ -230,10 +248,11 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms @Override protected Supplier accountDetailsSupplier(final String examineeSessionId) { - // TODO get the examinee's account details by the given examineeSessionId from remote LMS. - // Currently only the name is needed to display on monitoring view. - return () -> { + + // TODO get the examinee's account details by the given examineeSessionId from remote LMS. + // Currently only the name is needed to display on monitoring view. + throw new RuntimeException("TODO"); }; } @@ -247,13 +266,17 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms @Override public Result getSEBClientRestriction(final Exam exam) { - + @SuppressWarnings("unused") final String quizId = exam.externalId; - // TODO get the SEB client restrictions that are currently set on the remote LMS for - // the given quiz / course derived from the given exam + return Result.tryCatch(() -> { - return Result.ofRuntimeError("TODO"); + // TODO get the SEB client restrictions that are currently set on the remote LMS for + // the given quiz / course derived from the given exam + + throw new RuntimeException("TODO"); + + }); } @Override @@ -261,22 +284,61 @@ public class AnsLmsAPITemplate extends AbstractCachedCourseAccess implements Lms final String externalExamId, final SEBRestriction sebRestrictionData) { - // TODO apply the given sebRestrictionData settings as current SEB client restriction setting - // to the remote LMS for the given quiz / course. - // Mainly SEBRestriction.configKeys and SEBRestriction.browserExamKeys + return Result.tryCatch(() -> { - return Result.ofRuntimeError("TODO"); + // TODO apply the given sebRestrictionData settings as current SEB client restriction setting + // to the remote LMS for the given quiz / course. + // Mainly SEBRestriction.configKeys and SEBRestriction.browserExamKeys + + throw new RuntimeException("TODO"); + + }); } @Override public Result releaseSEBClientRestriction(final Exam exam) { - + @SuppressWarnings("unused") final String quizId = exam.externalId; - // TODO Release respectively delete all SEB client restrictions for the given - // course / quize on the remote LMS. + return Result.tryCatch(() -> { - return Result.ofRuntimeError("TODO"); + // TODO Release respectively delete all SEB client restrictions for the given + // course / quize on the remote LMS. + + throw new RuntimeException("TODO"); + + }); + } + + // TODO: This is an example of how to create a RestTemplate for the service to access the LMS API + // The example deals with a Http based API that is secured by an OAuth2 client-credential flow. + // You might need some different template, then you have to adapt this code + // To your needs. + @SuppressWarnings("unused") + private OAuth2RestTemplate createRestTemplate(final String accessTokenRequestPath) { + + final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup(); + final ClientCredentials credentials = this.apiTemplateDataSupplier.getLmsClientCredentials(); + final ProxyData proxyData = this.apiTemplateDataSupplier.getProxyData(); + + final CharSequence plainClientId = credentials.clientId; + final CharSequence plainClientSecret = this.clientCredentialService + .getPlainClientSecret(credentials) + .getOrThrow(); + + final ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails(); + details.setAccessTokenUri(lmsSetup.lmsApiUrl + accessTokenRequestPath); + details.setClientId(plainClientId.toString()); + details.setClientSecret(plainClientSecret.toString()); + + final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService + .getClientHttpRequestFactory(proxyData) + .getOrThrow(); + + final OAuth2RestTemplate template = new OAuth2RestTemplate(details); + template.setRequestFactory(clientHttpRequestFactory); + + return template; } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplateFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplateFactory.java index 67c9a98d..549bf5a5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplateFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/ans/AnsLmsAPITemplateFactory.java @@ -13,7 +13,9 @@ 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.async.AsyncService; +import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; 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; @@ -33,15 +35,21 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory; * as usual. Just add the additionally needed dependencies used to build a AnsLmsAPITemplateFactory */ public class AnsLmsAPITemplateFactory implements LmsAPITemplateFactory { + private final ClientHttpRequestFactoryService clientHttpRequestFactoryService; + private final ClientCredentialService clientCredentialService; private final AsyncService asyncService; private final Environment environment; private final CacheManager cacheManager; public AnsLmsAPITemplateFactory( + final ClientHttpRequestFactoryService clientHttpRequestFactoryService, + final ClientCredentialService clientCredentialService, final AsyncService asyncService, final Environment environment, final CacheManager cacheManager) { + this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; + this.clientCredentialService = clientCredentialService; this.asyncService = asyncService; this.environment = environment; this.cacheManager = cacheManager; @@ -56,6 +64,8 @@ public class AnsLmsAPITemplateFactory implements LmsAPITemplateFactory { public Result create(final APITemplateDataSupplier apiTemplateDataSupplier) { return Result.tryCatch(() -> { return new AnsLmsAPITemplate( + this.clientHttpRequestFactoryService, + this.clientCredentialService, apiTemplateDataSupplier, this.asyncService, this.environment,