added full name resolving also for Open edX

This commit is contained in:
anhefti 2020-07-23 11:47:06 +02:00
parent d85fd1b1d7
commit cfaaf964fe
4 changed files with 105 additions and 13 deletions

View file

@ -108,7 +108,7 @@ public abstract class CourseAccess {
public String getExamineeName(final String examineeSessionId) { public String getExamineeName(final String examineeSessionId) {
return getExamineeAccountDetails(examineeSessionId) return getExamineeAccountDetails(examineeSessionId)
.map(ExamineeAccountDetails::getDisplayName) .map(ExamineeAccountDetails::getDisplayName)
.onError(error -> log.warn("Failed to request Moodle user-name for ID: {}", error.getMessage(), error)) .onError(error -> log.warn("Failed to request user-name for ID: {}", error.getMessage(), error))
.getOr(examineeSessionId); .getOr(examineeSessionId);
} }

View file

@ -34,13 +34,17 @@ import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode; import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.Constants; 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.async.AsyncService;
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; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
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.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
@ -58,7 +62,9 @@ final class OpenEdxCourseAccess extends CourseAccess {
"/api/courses/v1/blocks/?depth=1&all_blocks=true&course_id="; "/api/courses/v1/blocks/?depth=1&all_blocks=true&course_id=";
private static final String OPEN_EDX_DEFAULT_BLOCKS_TYPE_CHAPTER = "chapter"; private static final String OPEN_EDX_DEFAULT_BLOCKS_TYPE_CHAPTER = "chapter";
private static final String OPEN_EDX_DEFAULT_COURSE_START_URL_PREFIX = "/courses/"; private static final String OPEN_EDX_DEFAULT_COURSE_START_URL_PREFIX = "/courses/";
private static final String OPEN_EDX_DEFAULT_USER_PROFILE_ENDPOINT = "/api/user/v1/accounts?username=";
private final JSONMapper jsonMapper;
private final LmsSetup lmsSetup; private final LmsSetup lmsSetup;
private final OpenEdxRestTemplateFactory openEdxRestTemplateFactory; private final OpenEdxRestTemplateFactory openEdxRestTemplateFactory;
private final WebserviceInfo webserviceInfo; private final WebserviceInfo webserviceInfo;
@ -66,12 +72,14 @@ final class OpenEdxCourseAccess extends CourseAccess {
private OAuth2RestTemplate restTemplate; private OAuth2RestTemplate restTemplate;
public OpenEdxCourseAccess( public OpenEdxCourseAccess(
final JSONMapper jsonMapper,
final LmsSetup lmsSetup, final LmsSetup lmsSetup,
final OpenEdxRestTemplateFactory openEdxRestTemplateFactory, final OpenEdxRestTemplateFactory openEdxRestTemplateFactory,
final WebserviceInfo webserviceInfo, final WebserviceInfo webserviceInfo,
final AsyncService asyncService) { final AsyncService asyncService) {
super(asyncService); super(asyncService);
this.jsonMapper = jsonMapper;
this.lmsSetup = lmsSetup; this.lmsSetup = lmsSetup;
this.openEdxRestTemplateFactory = openEdxRestTemplateFactory; this.openEdxRestTemplateFactory = openEdxRestTemplateFactory;
this.webserviceInfo = webserviceInfo; this.webserviceInfo = webserviceInfo;
@ -111,6 +119,51 @@ final class OpenEdxCourseAccess extends CourseAccess {
return LmsSetupTestResult.ofOkay(); return LmsSetupTestResult.ofOkay();
} }
@Override
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeSessionId) {
return Result.tryCatch(() -> {
final OAuth2RestTemplate template = getRestTemplate()
.getOrThrow();
final String externalStartURI = this.webserviceInfo.getLmsExternalAddressAlias(this.lmsSetup.lmsApiUrl);
final String uri = (externalStartURI != null)
? externalStartURI + OPEN_EDX_DEFAULT_USER_PROFILE_ENDPOINT + examineeSessionId
: this.lmsSetup.lmsApiUrl + OPEN_EDX_DEFAULT_USER_PROFILE_ENDPOINT + examineeSessionId;
final HttpHeaders httpHeaders = new HttpHeaders();
final String responseJSON = template.exchange(
uri,
HttpMethod.GET,
new HttpEntity<>(httpHeaders),
String.class)
.getBody();
final EdxUserDetails[] userDetails = this.jsonMapper.<EdxUserDetails[]> readValue(
responseJSON,
new TypeReference<EdxUserDetails[]>() {
});
if (userDetails == null || userDetails.length <= 0) {
throw new RuntimeException("No user details on Open edX API request");
}
final Map<String, String> additionalAttributes = new HashMap<>();
additionalAttributes.put("bio", userDetails[0].bio);
additionalAttributes.put("country", userDetails[0].country);
additionalAttributes.put("date_joined", userDetails[0].date_joined);
additionalAttributes.put("gender", userDetails[0].gender);
additionalAttributes.put("is_active", String.valueOf(userDetails[0].is_active));
additionalAttributes.put("mailing_address", userDetails[0].mailing_address);
additionalAttributes.put("secondary_email", userDetails[0].secondary_email);
return new ExamineeAccountDetails(
userDetails[0].username,
userDetails[0].name,
userDetails[0].username,
userDetails[0].email,
additionalAttributes);
});
}
@Override @Override
protected Supplier<List<QuizData>> allQuizzesSupplier() { protected Supplier<List<QuizData>> allQuizzesSupplier() {
return () -> getRestTemplate() return () -> getRestTemplate()
@ -266,6 +319,44 @@ final class OpenEdxCourseAccess extends CourseAccess {
public String type; public String type;
} }
@JsonIgnoreProperties(ignoreUnknown = true)
static final class EdxUserDetails {
final String username;
final String bio;
final String name;
final String secondary_email;
final String country;
final Boolean is_active;
final String gender;
final String mailing_address;
final String email;
final String date_joined;
protected EdxUserDetails(
@JsonProperty(value = "username") final String username,
@JsonProperty(value = "bio") final String bio,
@JsonProperty(value = "name") final String name,
@JsonProperty(value = "secondary_email") final String secondary_email,
@JsonProperty(value = "country") final String country,
@JsonProperty(value = "is_active") final Boolean is_active,
@JsonProperty(value = "gender") final String gender,
@JsonProperty(value = "mailing_address") final String mailing_address,
@JsonProperty(value = "email") final String email,
@JsonProperty(value = "date_joined") final String date_joined) {
this.username = username;
this.bio = bio;
this.name = name;
this.secondary_email = secondary_email;
this.country = country;
this.is_active = is_active;
this.gender = gender;
this.mailing_address = mailing_address;
this.email = email;
this.date_joined = date_joined;
}
}
private static final class EdxOAuth2RequestAuthenticator implements OAuth2RequestAuthenticator { private static final class EdxOAuth2RequestAuthenticator implements OAuth2RequestAuthenticator {
@Override @Override

View file

@ -74,6 +74,7 @@ public class OpenEdxLmsAPITemplateFactory {
this.alternativeTokenRequestPaths); this.alternativeTokenRequestPaths);
final OpenEdxCourseAccess openEdxCourseAccess = new OpenEdxCourseAccess( final OpenEdxCourseAccess openEdxCourseAccess = new OpenEdxCourseAccess(
this.jsonMapper,
lmsSetup, lmsSetup,
openEdxRestTemplateFactory, openEdxRestTemplateFactory,
this.webserviceInfo, this.webserviceInfo,

View file

@ -58,6 +58,18 @@ public class MoodleCourseAccess extends CourseAccess {
private MoodleAPIRestTemplate restTemplate; private MoodleAPIRestTemplate restTemplate;
protected MoodleCourseAccess(
final JSONMapper jsonMapper,
final LmsSetup lmsSetup,
final MoodleRestTemplateFactory moodleRestTemplateFactory,
final AsyncService asyncService) {
super(asyncService);
this.jsonMapper = jsonMapper;
this.lmsSetup = lmsSetup;
this.moodleRestTemplateFactory = moodleRestTemplateFactory;
}
@Override @Override
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeSessionId) { public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeSessionId) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
@ -105,18 +117,6 @@ public class MoodleCourseAccess extends CourseAccess {
}); });
} }
protected MoodleCourseAccess(
final JSONMapper jsonMapper,
final LmsSetup lmsSetup,
final MoodleRestTemplateFactory moodleRestTemplateFactory,
final AsyncService asyncService) {
super(asyncService);
this.jsonMapper = jsonMapper;
this.lmsSetup = lmsSetup;
this.moodleRestTemplateFactory = moodleRestTemplateFactory;
}
LmsSetupTestResult initAPIAccess() { LmsSetupTestResult initAPIAccess() {
final LmsSetupTestResult attributesCheck = this.moodleRestTemplateFactory.test(); final LmsSetupTestResult attributesCheck = this.moodleRestTemplateFactory.test();