Commit 533a43cb authored by Daniel Gerhardt's avatar Daniel Gerhardt

Remove implementation for Ilias

The Ilias connector implementation had an incompatible API and was never
usable with the ARSnova Backend.
parent d6e7e3ac
......@@ -13,7 +13,6 @@ We currently provide implementations to access Moodle, Ilias and Stud.IP:
| LMS | Retrieval method | Compatible versions |
|---------|--------------------|---------------------|
| Moodle | DBMS | * |
| Ilias | DBMS | * |
| Stud.IP | DBMS or REST API | * |
\* The database structures and/or APIs for the limited data accessed by LMS Connector usually do not change with new LMS versions and we do not have the resources to test against every new release. If you notice any incompatibilities, please create an issue.
......
......@@ -3,8 +3,6 @@ package de.thm.arsnova.connector.client;
import java.util.List;
import de.thm.arsnova.connector.model.Courses;
import de.thm.arsnova.connector.model.IliasCategoryNode;
import de.thm.arsnova.connector.model.IliasQuestion;
import de.thm.arsnova.connector.model.Membership;
/**
......@@ -36,12 +34,6 @@ import de.thm.arsnova.connector.model.Membership;
*
*/
public interface ConnectorClient {
public enum IliasQuestionSource {
RANDOM_TEST,
QUESTION_POOL
}
/** This service method returns the state of membership
*
* @param username The users name as used in target platform
......@@ -66,28 +58,4 @@ public interface ConnectorClient {
* @return The list of courses
*/
Courses getCourses(String username);
/** Returns a dump of the Ilias repository tree.
*
* @param refId The root nodes ID as reference ID
* @return A list of category nodes
*/
IliasCategoryNode getTreeObjects(int refId);
/** Returns a list of questions identified by the parent question pool reference ID
*
* The question source defaults to RANDOM_SOURCE
*
* @param refId The reference id of the question pool containing this question
* @return A list of questions containing the question, possible answers and feedback.
*/
List<IliasQuestion> getQuestions(int refId);
/** Returns a list of questions identified by the parent question pool reference ID
*
* @param refId The reference id of the question pool containing this question
* @param source The source of the questions
* @return A list of questions containing the question, possible answers and feedback.
*/
List<IliasQuestion> getQuestions(int refId, IliasQuestionSource source);
}
package de.thm.arsnova.connector.client;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.springframework.http.HttpEntity;
......@@ -12,8 +10,6 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import de.thm.arsnova.connector.model.Courses;
import de.thm.arsnova.connector.model.IliasCategoryNode;
import de.thm.arsnova.connector.model.IliasQuestion;
import de.thm.arsnova.connector.model.Membership;
public class ConnectorClientImpl implements ConnectorClient {
......@@ -21,8 +17,6 @@ public class ConnectorClientImpl implements ConnectorClient {
private static final String ISMEMBER_URI = "/{username}/membership/{courseid}";
private static final String GETCOURSES_URI = "/{username}/courses";
private static final String ILIAS_TREEOBJECTS_URI = "/ilias/{refid}";
private static final String ILIAS_QUESTIONS_URI = "/ilias/question/{refid}";
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
......@@ -72,46 +66,6 @@ public class ConnectorClientImpl implements ConnectorClient {
return response.getBody();
}
@Override
public IliasCategoryNode getTreeObjects(final int refId) {
final ResponseEntity<IliasCategoryNode> response = restTemplate.exchange(
buildRequestUri(ILIAS_TREEOBJECTS_URI),
HttpMethod.GET,
createNodeListEntity(),
IliasCategoryNode.class,
refId
);
return response.getBody();
}
@Override
public List<IliasQuestion> getQuestions(final int refId) {
final ResponseEntity<IliasQuestion[]> response = restTemplate.exchange(
buildRequestUri(ILIAS_QUESTIONS_URI),
HttpMethod.GET,
createQuestionListEntity(),
IliasQuestion[].class,
refId
);
return Arrays.asList(response.getBody());
}
@Override
public List<IliasQuestion> getQuestions(final int refId, final IliasQuestionSource source) {
final ResponseEntity<IliasQuestion[]> response = restTemplate.exchange(
buildRequestUri(ILIAS_QUESTIONS_URI + "?source={source}"),
HttpMethod.GET,
createQuestionListEntity(),
IliasQuestion[].class,
refId,
source
);
return Arrays.asList(response.getBody());
}
private HttpEntity<Membership> createMembershipEntity() {
return new HttpEntity<Membership>(getAuthorizationHeader());
}
......@@ -120,14 +74,6 @@ public class ConnectorClientImpl implements ConnectorClient {
return new HttpEntity<Courses>(getAuthorizationHeader());
}
private HttpEntity<List<IliasCategoryNode>> createNodeListEntity() {
return new HttpEntity<List<IliasCategoryNode>>(getAuthorizationHeader());
}
private HttpEntity<List<IliasQuestion>> createQuestionListEntity() {
return new HttpEntity<List<IliasQuestion>>(getAuthorizationHeader());
}
private HttpHeaders getAuthorizationHeader() {
final HttpHeaders httpHeaders = new HttpHeaders();
final String authorisation = httpUsername + ":" + httpPassword;
......
package de.thm.arsnova.connector.model;
public class IliasAnswer {
private String text;
private double points;
private double pointsUnchecked;
public IliasAnswer(String text, double points, double pointsUnchecked) {
this.text = text;
this.points = points;
this.pointsUnchecked = pointsUnchecked;
}
public String getText() {
return text;
}
public double getPoints() {
return points;
}
public double getPointsUnchecked() {
return pointsUnchecked;
}
}
package de.thm.arsnova.connector.model;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@JsonInclude(Include.NON_NULL)
public class IliasCategoryNode {
private int id;
private int parent;
private String title;
private String type;
private Boolean leaf;
private int questionCount;
private Boolean isRandomTest;
private Integer randomQuestionAmount;
private List<IliasCategoryNode> children;
public IliasCategoryNode() {}
public IliasCategoryNode(final int id, final int parent, final String title, final String type, final int questionCount) {
this.id = id;
this.parent = parent;
this.title = title;
this.type = type;
this.questionCount = questionCount;
}
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public int getParent() {
return parent;
}
public void setParent(final int parent) {
this.parent = parent;
}
public String getTitle() {
return title;
}
public void setTitle(final String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
public int getQuestionCount() {
return questionCount;
}
public void setQuestionCount(final int questionCount) {
this.questionCount = questionCount;
}
public Boolean getIsRandomTest() {
return isRandomTest;
}
public void setIsRandomTest(final Boolean isRandomTest) {
this.isRandomTest = isRandomTest;
}
public Integer getRandomQuestionCount() {
return randomQuestionAmount;
}
public void setRandomQuestionCount(final Integer randomQuestionAmount) {
this.randomQuestionAmount = randomQuestionAmount;
}
public Boolean isLeaf() {
return leaf;
}
public void setLeaf(final Boolean leaf) {
this.leaf = leaf;
}
public List<IliasCategoryNode> getChildren() {
return children;
}
public void addChild(final IliasCategoryNode node) {
if (node == null) {
throw new IllegalArgumentException();
}
if (children == null) {
children = new ArrayList<IliasCategoryNode>();
}
children.add(node);
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof IliasCategoryNode) {
final IliasCategoryNode other = (IliasCategoryNode) obj;
return id == other.getId() && parent == other.getParent();
}
return false;
}
}
package de.thm.arsnova.connector.model;
public class IliasFeedback {
private boolean correctness;
private String feedback;
public IliasFeedback(String feedback, boolean correctness) {
this.correctness = correctness;
this.feedback = feedback;
}
public IliasFeedback() {
this.correctness = false;
this.feedback = null;
}
public String getFeedback() {
return feedback;
}
public void setFeedback(String feedback) {
this.feedback = feedback;
}
public boolean isCorrect() {
return correctness;
}
public void setCorrect(boolean isCorrect) {
this.correctness = isCorrect;
}
}
package de.thm.arsnova.connector.model;
import java.util.List;
public class IliasQuestion {
private int id;
private int type;
private double points;
private String title;
private String description;
private String text;
private int timestamp;
private List<IliasAnswer> answers;
private List<IliasFeedback> feedback;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public double getPoints() {
return points;
}
public void setPoints(double points) {
this.points = points;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getTimestamp() {
return timestamp;
}
public void setTimestamp(int timestamp) {
this.timestamp = timestamp;
}
public List<IliasAnswer> getAnswers() {
return answers;
}
public void setAnswers(List<IliasAnswer> answers) {
this.answers = answers;
}
public List<IliasFeedback> getFeedback() {
return feedback;
}
public void setFeedback(List<IliasFeedback> feedback) {
this.feedback = feedback;
}
}
......@@ -21,8 +21,6 @@ import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import de.thm.arsnova.connector.dao.ConnectorDao;
import de.thm.arsnova.connector.dao.IliasConnectorDaoImpl;
import de.thm.arsnova.connector.dao.UniRepDao;
@ComponentScan(basePackages = {
"de.thm.arsnova.connector.dao",
......@@ -94,14 +92,6 @@ public class AppConfig {
return (ConnectorDao) Class.forName(env.getProperty("dao.implementation")).newInstance();
}
@Bean
public UniRepDao uniRepDao() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
if ("enable".equals(env.getProperty("service.startIliasConnector"))) {
return new IliasConnectorDaoImpl();
}
return null;
}
private class HsqlDataSource extends DriverManagerDataSource {
@PreDestroy
public void shutdown() {
......
......@@ -14,9 +14,7 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import de.thm.arsnova.connector.auth.AuthenticationFilter;
import de.thm.arsnova.connector.auth.AuthenticationHandler;
......@@ -105,25 +103,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
if("enable".equals(env.getProperty("service.startIliasConnector"))) {
http.authorizeRequests().antMatchers("/ilias/check").permitAll().and()
.authorizeRequests().antMatchers("/ilias/login").permitAll().and()
.authorizeRequests().anyRequest().authenticated().and()
.formLogin().loginPage("/ilias/login").usernameParameter("uname")
.passwordParameter("upass").successHandler(authHandler().authSuccessHandler())
.failureHandler(authHandler().authFailureHandler()).and()
.addFilterBefore(authFilter(),
UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(
authHandler().tokenAuthenticationEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
} else {
http.httpBasic();
}
http.httpBasic();
}
}
......@@ -52,13 +52,6 @@ public class RepoPermissionEvaluator implements PermissionEvaluator {
return true;
}
break;
case "uniRepQuestion":
case "uniRepTree":
if ("read".equals(permission)) {
return true;
}
break;
}
return false;
......
package de.thm.arsnova.connector.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import de.thm.arsnova.connector.dao.UniRepDao.Filter;
import de.thm.arsnova.connector.dao.UniRepDao.Filter.Type;
import de.thm.arsnova.connector.model.IliasAnswer;
import de.thm.arsnova.connector.model.IliasCategoryNode;
import de.thm.arsnova.connector.model.IliasFeedback;
import de.thm.arsnova.connector.model.IliasQuestion;
@Filter(Type.TEST)
public class IliasConnectorDaoImpl implements UniRepDao {
@Autowired
private DataSource dataSource;
@Override
public List<IliasCategoryNode> getTreeObjects(final int refId) {
final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String typefilter = null;
if (this.getClass().getAnnotation(UniRepDao.Filter.class) != null) {
switch (this.getClass().getAnnotation(UniRepDao.Filter.class).value()) {
case QUESTION_POOL:
typefilter = " AND type <> 'tst'";
break;
case TEST:
typefilter = " AND type <> 'qpl'";
break;
default:
typefilter = "";
break;
}
}
final Map<Integer, Integer> questionCount = getQuestionCount(refId);
final Map<Integer, Integer> randomQuestionAmount = getRandomQuestionAmount(refId);
final List<IliasCategoryNode> nodeList = jdbcTemplate.query(
"SELECT t2.*, d.type, d.title FROM tree AS t1"
+ " JOIN tree AS t2 ON t2.lft BETWEEN t1.lft AND t1.rgt AND t1.tree = t2.tree"
+ " JOIN object_reference AS r ON r.ref_id=t2.child "
+ " JOIN object_data as d ON d.obj_id=r.obj_id"
+ typefilter
+ " WHERE t1.child=? ORDER BY parent;",
new String[] {String.valueOf(refId)},
new RowMapper<IliasCategoryNode>() {
@Override
public IliasCategoryNode mapRow(
final ResultSet resultSet,
final int row
) throws SQLException {
final IliasCategoryNode node = new IliasCategoryNode(
resultSet.getInt("child"),
resultSet.getInt("parent"),
resultSet.getString("title"),
resultSet.getString("type"),
questionCount.get(resultSet.getInt("child")) == null ? 0 :
questionCount.get(resultSet.getInt("child"))
);
if ("tst".equals(node.getType())) {
if (randomQuestionAmount.get(node.getId()) == null) {
node.setIsRandomTest(false);
} else {
node.setIsRandomTest(true);
node.setRandomQuestionCount(randomQuestionAmount.get(node.getId()));
}
}
return node;
}
}
);
for (final IliasCategoryNode node : nodeList) {
for (final IliasCategoryNode parentNode : nodeList) {
if (node.getParent() == parentNode.getId()) {
parentNode.addChild(node);
}
}
}
final List<IliasCategoryNode> result = new ArrayList<>();
if (nodeList.size() > 0) {
result.add(nodeList.get(0));
}
return result;
}
@Override
public List<IliasQuestion> getQuestion(final int refId) {
final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate.query(
"SELECT * FROM qpl_questions JOIN object_reference ON (obj_fi = obj_id) WHERE ref_id=?;",
new String[] {String.valueOf(refId)},
new RowMapper<IliasQuestion>() {
@Override
public IliasQuestion mapRow(final ResultSet resultSet, final int row) throws SQLException {
final IliasQuestion q = new IliasQuestion();
q.setDescription(resultSet.getString("description"));
q.setId(resultSet.getInt("question_id"));
q.setPoints(resultSet.getDouble("points"));
q.setText(resultSet.getString("question_text"));
q.setTimestamp(resultSet.getInt("tstamp"));
q.setTitle(resultSet.getString("title"));
q.setType(resultSet.getInt("question_type_fi"));
q.setAnswers(getAnswers(resultSet.getInt("question_id")));