GitLab wurde aktualisiert. Dank regelmäßiger Updates bleibt das THM GitLab sicher und Sie profitieren von den neuesten Funktionen. Vielen Dank für Ihre Geduld.

Commit e288bfce authored by Daniel Gerhardt's avatar Daniel Gerhardt
Browse files

Merge branch 'studip-rest-api'

parents d33ad05f 2eee5e87
......@@ -17,6 +17,7 @@ repositories {
dependencies {
compile project (':connector-model')
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
compile group: 'commons-codec', name: 'commons-codec', version: '1.7'
compile group: 'org.springframework', name: 'spring-context', version: springVersion
compile group: 'org.springframework', name: 'spring-webmvc', version: springVersion
compile group: 'org.springframework', name: 'spring-jdbc', version: springVersion
......
package de.thm.arsnova.connector.dao;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import de.thm.arsnova.connector.model.Course;
import de.thm.arsnova.connector.model.Membership;
import de.thm.arsnova.connector.model.UserRole;
import de.thm.arsnova.connector.model.studip_rest.StudipCourse;
import de.thm.arsnova.connector.model.studip_rest.StudipCoursesWrapper;
import de.thm.arsnova.connector.model.studip_rest.StudipUser;
import de.thm.arsnova.connector.model.studip_rest.StudipUsersWrapper;
public class StudipRestConnectorDaoImpl implements ConnectorDao {
private static final String TYPE = "studip";
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
private static final Logger logger = LoggerFactory.getLogger(StudipRestConnectorDaoImpl.class);
private final RestTemplate restTemplate = new RestTemplate();
private String userMembershipUri = "/user/{userid}/courses";
private String userSearchUri = "/users?needle={username}";
@Value("${lms.http.serverUrl}") private String uriHostPart;
@Value("${lms.http.username}") private String httpUsername;
@Value("${lms.http.password}") private String httpPassword;
@PostConstruct
public void initialize() {
logger.info("Initializing {}", StudipRestConnectorDaoImpl.class.getName());
userMembershipUri = uriHostPart + userMembershipUri;
userSearchUri = uriHostPart + userSearchUri;
logger.debug("Using userMembershipUri={}, userSearchUri={}", userMembershipUri, userSearchUri);
}
@Override
public List<String> getCourseUsers(final String courseid) {
throw new UnsupportedOperationException();
}
@Override
public Membership getMembership(final String username, final String courseid) {
logger.trace("Retrieve membership status for user {} in course {}", username, courseid);
Membership membership = new Membership();
StudipUser user = getUserByName(username);
if (null == user) {
return membership;
}
try {
ResponseEntity<StudipCoursesWrapper> courseWrapperEntity = restTemplate.exchange(
userMembershipUri,
HttpMethod.GET,
new HttpEntity<Void>(getAuthorizationHeader()),
StudipCoursesWrapper.class,
user.getId()
);
List<StudipCourse> courses;
if (null != (courses = courseWrapperEntity.getBody().getStudy())) {
for (StudipCourse course : courses) {
if (courseid.equals(course.getId())) {
membership.setMember(true);
membership.setUserrole(UserRole.MEMBER);
logger.trace("User {} is a member of course {}", username, courseid);
return membership;
}
}
}
if (null != (courses = courseWrapperEntity.getBody().getWork())) {
for (StudipCourse course : courses) {
if (courseid.equals(course.getId())) {
membership.setMember(true);
membership.setUserrole(UserRole.TEACHER);
logger.trace("User {} is a teacher of course {}", username, courseid);
return membership;
}
}
}
} catch (RestClientException | HttpMessageNotReadableException e) {
/* Stud.IP sends an empty array instead of an object if no courses are found */
}
membership.setMember(false);
logger.trace("User {} is not a member of course {}", username, courseid);
return membership;
}
@Override
public List<Course> getMembersCourses(final String username) {
logger.trace("Retrieve courses for {}", username);
List<Course> courses = new ArrayList<>();
StudipUser user = getUserByName(username);
if (null == user) {
return courses;
}
try {
ResponseEntity<StudipCoursesWrapper> courseWrapperEntity = restTemplate.exchange(
userMembershipUri,
HttpMethod.GET,
new HttpEntity<Void>(getAuthorizationHeader()),
StudipCoursesWrapper.class,
user.getId()
);
List<StudipCourse> sipCourses;
if (null != (sipCourses = courseWrapperEntity.getBody().getStudy())) {
for (StudipCourse sipCourse : sipCourses) {
courses.add(buildCourse(sipCourse, UserRole.MEMBER));
}
}
if (null != (sipCourses = courseWrapperEntity.getBody().getWork())) {
for (StudipCourse sipCourse : sipCourses) {
courses.add(buildCourse(sipCourse, UserRole.TEACHER));
}
}
} catch (RestClientException | HttpMessageNotReadableException e) {
/* Stud.IP sends an empty array instead of an object if no courses are found */
}
return courses;
}
private StudipUser getUserByName(String username) {
logger.trace("Retrieve user {}", username);
ResponseEntity<StudipUsersWrapper> usersWrapperEntity = restTemplate.exchange(
userSearchUri,
HttpMethod.GET,
new HttpEntity<Void>(getAuthorizationHeader()),
StudipUsersWrapper.class,
username
);
for (StudipUser user : usersWrapperEntity.getBody().getUsers()) {
if (username.equals(user.getUsername())) {
logger.trace("Username {} belongs to user {}", username, user);
return user;
}
}
logger.trace("No user was found for username {}", username);
return null;
}
private HttpHeaders getAuthorizationHeader() {
HttpHeaders httpHeaders = new HttpHeaders();
String authorization = httpUsername + ":" + httpPassword;
httpHeaders.add(
"Authorization",
"Basic " + Base64.encodeBase64String(authorization.getBytes(UTF8_CHARSET))
);
return httpHeaders;
}
private Course buildCourse(StudipCourse sipCourse, UserRole role) {
Membership membership = new Membership();
membership.setMember(true);
membership.setUserrole(role);
Course course = new Course();
course.setId(sipCourse.getId());
course.setFullname(sipCourse.getTitle());
course.setShortname(sipCourse.getTitle());
course.setType(TYPE);
course.setMembership(membership);
return course;
}
}
package de.thm.arsnova.connector.model.studip_rest;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class StudipCourse {
private String id;
private String title;
private List<String> teachers;
private List<String> tutors;
private List<String> students;
public void setName(String name) {
this.title = name;
}
@JsonProperty("course_id")
public String getId() {
return id;
}
@JsonProperty("course_id")
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getTeachers() {
return teachers;
}
public void setTeachers(List<String> teachers) {
this.teachers = teachers;
}
public List<String> getTutors() {
return tutors;
}
public void setTutors(List<String> tutors) {
this.tutors = tutors;
}
public List<String> getStudents() {
return students;
}
public void setStudents(List<String> students) {
this.students = students;
}
}
package de.thm.arsnova.connector.model.studip_rest;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class StudipCoursesWrapper {
private StudipCoursesInnerWrapper courses;
public StudipCoursesInnerWrapper getCourses() {
return courses;
}
public void setCourses(StudipCoursesInnerWrapper courses) {
this.courses = courses;
}
public List<StudipCourse> getStudy() {
return courses.study;
}
public void setStudy(List<StudipCourse> study) {
courses.study = study;
}
public List<StudipCourse> getWork() {
return courses.work;
}
public void setWork(List<StudipCourse> work) {
courses.work = work;
}
public static class StudipCoursesInnerWrapper {
private List<StudipCourse> study;
private List<StudipCourse> work;
public List<StudipCourse> getStudy() {
return study;
}
public void setStudy(List<StudipCourse> study) {
this.study = study;
}
public List<StudipCourse> getWork() {
return work;
}
public void setWork(List<StudipCourse> work) {
this.work = work;
}
}
}
package de.thm.arsnova.connector.model.studip_rest;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class StudipUser {
private String id;
private String username;
@JsonProperty("user_id")
public String getId() {
return id;
}
@JsonProperty("user_id")
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
package de.thm.arsnova.connector.model.studip_rest;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class StudipUsersWrapper {
private StudipUser[] users;
public StudipUser[] getUsers() {
return users;
}
public void setUsers(StudipUser[] users) {
this.users = users;
}
}
......@@ -3,11 +3,17 @@ jdbc.url=jdbc:mysql://127.0.0.1:3306/moodle?zeroDateTimeBehavior=convertToNull
jdbc.username=root
jdbc.password=secret
lms.http.serverUrl=https://localhost/lms-api
lms.http.username=connector-user
lms.http.password=secret
# Select the data access object implementation your target platform
# Uncomment the following line to access Moodle
dao.implementation=de.thm.arsnova.connector.dao.MoodleConnectorDaoImpl
# Uncomment the following line to access Stud.IP
# dao.implementation=de.thm.arsnova.connector.dao.StudipConnectorDaoImpl
# Uncomment the following line to access Stud.IP via REST
# dao.implementation=de.thm.arsnova.connector.dao.StudipRestConnectorDaoImpl
# Uncomment the following line to get a dummy implementation
# dao.implementation=de.thm.arsnova.connector.dao.DummyConnectorDaoImpl
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment