diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java index a1b25aa68c6ef4c6a5911962a04c58db8701fd7c..f76d377d31c73c90b972d34eea637833870718c2 100644 --- a/src/main/java/de/thm/arsnova/controller/SessionController.java +++ b/src/main/java/de/thm/arsnova/controller/SessionController.java @@ -234,17 +234,19 @@ public class SessionController extends AbstractController { @RequestMapping(value = "/{sessionkey}/learningprogress", method = RequestMethod.GET) public final int learningProgress( @PathVariable final String sessionkey, + @RequestParam(value = "type", defaultValue = "questions") final String progressType, final HttpServletResponse response ) { - return sessionService.getLearningProgress(sessionkey); + return sessionService.getLearningProgress(sessionkey, progressType); } @RequestMapping(value = "/{sessionkey}/mylearningprogress", method = RequestMethod.GET) public final JSONObject myLearningProgress( @PathVariable final String sessionkey, + @RequestParam(value = "type", defaultValue = "questions") final String progressType, final HttpServletResponse response ) { - final SimpleEntry<Integer, Integer> result = sessionService.getMyLearningProgress(sessionkey); + final SimpleEntry<Integer, Integer> result = sessionService.getMyLearningProgress(sessionkey, progressType); final JSONObject json = new JSONObject(); json.put("myprogress", result.getKey()); json.put("courseprogress", result.getValue()); diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index 44ae691a84bb115fdef2455cc54394fa3233095b..cdb87b61d141b95d6dfae563e6278f876d587d41 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -18,8 +18,6 @@ package de.thm.arsnova.dao; import java.io.IOException; -import java.util.AbstractMap; -import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -53,6 +51,7 @@ import com.fourspaces.couchdb.View; import com.fourspaces.couchdb.ViewResults; import de.thm.arsnova.connector.model.Course; +import de.thm.arsnova.domain.CourseScore; import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.DbUser; import de.thm.arsnova.entities.InterposedQuestion; @@ -403,6 +402,7 @@ public class CouchDBDao implements IDatabaseDao { sessionDocument.put("courseType", session.getCourseType()); sessionDocument.put("courseId", session.getCourseId()); sessionDocument.put("creationTime", session.getCreationTime()); + sessionDocument.put("learningProgressType", session.getLearningProgressType()); sessionDocument.put("ppAuthorName", session.getPpAuthorName()); sessionDocument.put("ppAuthorMail", session.getPpAuthorMail()); sessionDocument.put("ppUniversity", session.getPpUniversity()); @@ -1291,6 +1291,7 @@ public class CouchDBDao implements IDatabaseDao { s.put("name", session.getName()); s.put("shortName", session.getShortName()); s.put("active", session.isActive()); + s.put("learningProgressType", session.getLearningProgressType()); database.saveDocument(s); session.set_rev(s.getRev()); @@ -1634,64 +1635,39 @@ public class CouchDBDao implements IDatabaseDao { } @Override - public int getLearningProgress(final Session session) { - // Note: we have to use this many views because our CouchDB version does not support - // advanced features like summing over lists. Thus, we have to do it all by ourselves... - final NovaView maximumValueView = new NovaView("learning_progress_maximum_value/max"); - final NovaView answerSumView = new NovaView("learning_progress_user_values/sum"); - final NovaView answerDocumentCountView = new NovaView("learning_progress_course_answers/count"); - maximumValueView.setKey(session.get_id()); + public CourseScore getLearningProgress(final Session session) { + final NovaView maximumValueView = new NovaView("learning_progress/maximum_value_of_question"); + final NovaView answerSumView = new NovaView("learning_progress/question_value_achieved_for_user"); + maximumValueView.setStartKeyArray(session.get_id()); + maximumValueView.setEndKeyArray(session.get_id(), "{}"); answerSumView.setStartKeyArray(session.get_id()); answerSumView.setEndKeyArray(session.get_id(), "{}"); - answerDocumentCountView.setStartKeyArray(session.get_id()); - answerDocumentCountView.setEndKeyArray(session.get_id(), "{}"); - answerDocumentCountView.setGroup(true); final List<Document> maximumValueResult = getDatabase().view(maximumValueView).getResults(); final List<Document> answerSumResult = getDatabase().view(answerSumView).getResults(); - final List<Document> answerDocumentCountResult = getDatabase().view(answerDocumentCountView).getResults(); - if (maximumValueResult.isEmpty() || answerSumResult.isEmpty() || answerDocumentCountResult.isEmpty()) { - return 0; - } - - final double courseMaximumValue = maximumValueResult.get(0).getInt("value"); - final double userTotalValue = answerSumResult.get(0).getInt("value"); - final double numUsers = answerDocumentCountResult.size(); - if (courseMaximumValue == 0 || numUsers == 0) { - return 0; - } - final double courseAverageValue = userTotalValue / numUsers; - final double courseProgress = courseAverageValue / courseMaximumValue; - return (int) Math.min(100, Math.round(courseProgress * 100)); - } - - @Override - public SimpleEntry<Integer, Integer> getMyLearningProgress(final Session session, final User user) { - final int courseProgress = getLearningProgress(session); - - final NovaView maximumValueView = new NovaView("learning_progress_maximum_value/max"); - final NovaView answerSumView = new NovaView("learning_progress_user_values/sum"); - maximumValueView.setKey(session.get_id()); - answerSumView.setKey(session.get_id(), user.getUsername()); - - final List<Document> maximumValueResult = getDatabase().view(maximumValueView).getResults(); - final List<Document> answerSumResult = getDatabase().view(answerSumView).getResults(); + CourseScore courseScore = new CourseScore(); + // no results found if (maximumValueResult.isEmpty() || answerSumResult.isEmpty()) { - return new AbstractMap.SimpleEntry<Integer, Integer>(0, courseProgress); + return courseScore; } - final double courseMaximumValue = maximumValueResult.get(0).getInt("value"); - final double userTotalValue = answerSumResult.get(0).getInt("value"); - - if (courseMaximumValue == 0) { - return new AbstractMap.SimpleEntry<Integer, Integer>(0, courseProgress); + // collect mapping (questionId -> max value) + for (Document d : maximumValueResult) { + String questionId = d.getJSONArray("key").getString(1); + int questionScore = d.getInt("value"); + courseScore.add(questionId, questionScore); } - final double myProgress = userTotalValue / courseMaximumValue; - final int myLearningProgress = (int) Math.min(100, Math.round(myProgress * 100)); - - return new AbstractMap.SimpleEntry<Integer, Integer>(myLearningProgress, courseProgress); + // collect mapping (questionId -> (user -> value)) + for (Document d : answerSumResult) { + String username = d.getJSONArray("key").getString(1); + JSONObject value = d.getJSONObject("value"); + String questionId = value.getString("questionId"); + int userscore = value.getInt("score"); + courseScore.add(questionId, username, userscore); + } + return courseScore; } @Override diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index 6f534be9401c6180e7c508e3f2db3c0f809e7975..d688abbebe96b06212afe87a79157ccd996444ce 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -17,10 +17,10 @@ */ package de.thm.arsnova.dao; -import java.util.AbstractMap.SimpleEntry; import java.util.List; import de.thm.arsnova.connector.model.Course; +import de.thm.arsnova.domain.CourseScore; import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.DbUser; import de.thm.arsnova.entities.InterposedQuestion; @@ -171,9 +171,7 @@ public interface IDatabaseDao { boolean deleteUser(DbUser dbUser); - int getLearningProgress(Session session); - - SimpleEntry<Integer, Integer> getMyLearningProgress(Session session, User user); + CourseScore getLearningProgress(Session session); List<SessionInfo> getMySessionsInfo(User user); diff --git a/src/main/java/de/thm/arsnova/domain/CourseScore.java b/src/main/java/de/thm/arsnova/domain/CourseScore.java new file mode 100644 index 0000000000000000000000000000000000000000..fa3c9d92ec565bb578032076a7412e3d84759e3d --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/CourseScore.java @@ -0,0 +1,92 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.domain; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import de.thm.arsnova.entities.User; + +public class CourseScore implements Iterable<QuestionScore> { + + private final Map<String, QuestionScore> scores = new HashMap<String, QuestionScore>(); + + public void add(String questionId, int questionScore) { + scores.put(questionId, new QuestionScore(questionId, questionScore)); + } + + /** + * @pre questionId has been added before. + * @param questionId + * @param username + * @param userscore + */ + public void add(String questionId, String username, int userscore) { + if (!scores.containsKey(questionId)) { + // Precondition failed, ignore this element. + // Most likely this is a question that has no learning progress value. + return; + } + QuestionScore questionScore = scores.get(questionId); + questionScore.add(username, userscore); + } + + public int getMaximumScore() { + int score = 0; + for (QuestionScore questionScore : this) { + score += questionScore.getMaximum(); + } + return score; + } + + public int getTotalUserScore() { + int score = 0; + for (QuestionScore questionScore : this) { + score += questionScore.getTotalUserScore(); + } + return score; + } + + public double getTotalUserScore(User user) { + int score = 0; + for (QuestionScore questionScore : this) { + score += questionScore.getTotalUserScore(user); + } + return score; + } + + public int getTotalUserCount() { + Set<String> users = new HashSet<String>(); + for (QuestionScore questionScore : this) { + questionScore.collectUsers(users); + } + return users.size(); + } + + public int getQuestionCount() { + return scores.size(); + } + + @Override + public Iterator<QuestionScore> iterator() { + return this.scores.values().iterator(); + } +} diff --git a/src/main/java/de/thm/arsnova/domain/LearningProgress.java b/src/main/java/de/thm/arsnova/domain/LearningProgress.java new file mode 100644 index 0000000000000000000000000000000000000000..e8ccfbfedc80275bfaedfff91cf00cfbab1aa76b --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/LearningProgress.java @@ -0,0 +1,30 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.domain; + +import java.util.AbstractMap.SimpleEntry; + +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; + +public interface LearningProgress { + + public int getCourseProgress(Session session); + + public SimpleEntry<Integer,Integer> getMyProgress(Session session, User user); +} diff --git a/src/main/java/de/thm/arsnova/domain/LearningProgressFactory.java b/src/main/java/de/thm/arsnova/domain/LearningProgressFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..0f819d410e0b95b018ce3cb38f1f16713d8b3907 --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/LearningProgressFactory.java @@ -0,0 +1,22 @@ +package de.thm.arsnova.domain; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import de.thm.arsnova.dao.IDatabaseDao; + +@Component +public class LearningProgressFactory { + + @Autowired + private IDatabaseDao databaseDao; + + public LearningProgress createFromType(String progressType) { + if (progressType.equals("questions")) { + return new QuestionBasedLearningProgress(databaseDao); + } else { + return new PointBasedLearningProgress(databaseDao); + } + } + +} diff --git a/src/main/java/de/thm/arsnova/domain/PointBasedLearningProgress.java b/src/main/java/de/thm/arsnova/domain/PointBasedLearningProgress.java new file mode 100644 index 0000000000000000000000000000000000000000..c7168bc0c05dee16423a4e4d7a847aae24db3eb2 --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/PointBasedLearningProgress.java @@ -0,0 +1,70 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.domain; + +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; + +import de.thm.arsnova.dao.IDatabaseDao; +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; + +public class PointBasedLearningProgress implements LearningProgress { + + private IDatabaseDao databaseDao; + + public PointBasedLearningProgress(IDatabaseDao dao) { + this.databaseDao = dao; + } + + @Override + public int getCourseProgress(Session session) { + CourseScore courseScore = databaseDao.getLearningProgress(session); + return calculateCourseScore(courseScore); + } + + private int calculateCourseScore(CourseScore courseScore) { + final double courseMaximumValue = courseScore.getMaximumScore(); + final double userTotalValue = courseScore.getTotalUserScore(); + final double numUsers = courseScore.getTotalUserCount(); + if (courseMaximumValue == 0 || numUsers == 0) { + return 0; + } + final double courseAverageValue = userTotalValue / numUsers; + final double courseProgress = courseAverageValue / courseMaximumValue; + return (int)Math.min(100, Math.round(courseProgress * 100)); + } + + @Override + public SimpleEntry<Integer, Integer> getMyProgress(Session session, User user) { + CourseScore courseScore = databaseDao.getLearningProgress(session); + int courseProgress = calculateCourseScore(courseScore); + + final double courseMaximumValue = courseScore.getMaximumScore(); + final double userTotalValue = courseScore.getTotalUserScore(user); + + if (courseMaximumValue == 0) { + return new AbstractMap.SimpleEntry<Integer, Integer>(0, courseProgress); + } + final double myProgress = userTotalValue / courseMaximumValue; + final int myLearningProgress = (int)Math.min(100, Math.round(myProgress*100)); + + return new AbstractMap.SimpleEntry<Integer, Integer>(myLearningProgress, courseProgress); + } + +} diff --git a/src/main/java/de/thm/arsnova/domain/QuestionBasedLearningProgress.java b/src/main/java/de/thm/arsnova/domain/QuestionBasedLearningProgress.java new file mode 100644 index 0000000000000000000000000000000000000000..d1ea2d45103cf5e3eee2e8ea8e82368a37ab8f3c --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/QuestionBasedLearningProgress.java @@ -0,0 +1,101 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.domain; + +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; + +import de.thm.arsnova.dao.IDatabaseDao; +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; + +public class QuestionBasedLearningProgress implements LearningProgress { + + private IDatabaseDao databaseDao; + + public QuestionBasedLearningProgress(IDatabaseDao dao) { + this.databaseDao = dao; + } + + @Override + public int getCourseProgress(Session session) { + CourseScore courseScore = databaseDao.getLearningProgress(session); + return calculateCourseProgress(courseScore); + } + + private int calculateCourseProgress(CourseScore courseScore) { + int numQuestionsCorrect = numQuestionsCorrectForCourse(courseScore); + final double correctQuestionsOnAverage = (double)numQuestionsCorrect / (double)(courseScore.getQuestionCount()); + // calculate percent, cap results to 100 + return (int) Math.min(100, Math.round(correctQuestionsOnAverage*100)); + } + + private int numQuestionsCorrectForCourse(CourseScore courseScore) { + // a question is seen as "correct" if and only if all participants have answered it correctly + int numQuestionsCorrect = 0; + for (QuestionScore questionScore : courseScore) { + int requiredScore = questionScore.getMaximum(); + if (!questionScore.hasScores()) { + continue; + } + boolean allCorrect = true; + for (UserScore userScore : questionScore) { + if (!userScore.hasScore(requiredScore)) { + allCorrect = false; + break; + } + } + if (allCorrect) { + numQuestionsCorrect++; + } + } + return numQuestionsCorrect; + } + + @Override + public SimpleEntry<Integer, Integer> getMyProgress(Session session, User user) { + CourseScore courseScore = databaseDao.getLearningProgress(session); + + int courseProgress = calculateCourseProgress(courseScore); + + int numQuestionsCorrect = numQuestionsCorrectForUser(user, courseScore); + final double myLearningProgress = numQuestionsCorrect / (double)(courseScore.getQuestionCount()); + // calculate percent, cap results to 100 + final int percentage = (int) Math.min(100, Math.round(myLearningProgress*100)); + return new AbstractMap.SimpleEntry<Integer, Integer>(percentage, courseProgress); + } + + private int numQuestionsCorrectForUser(User user, CourseScore courseScore) { + // compare user's values to the maximum number for each question to determine the answers' correctness + // mapping (questionId -> 1 if correct, 0 if incorrect) + int numQuestionsCorrect = 0; + for (QuestionScore questionScore : courseScore) { + int requiredScore = questionScore.getMaximum(); + for (UserScore userScore : questionScore) { + if (!userScore.isUser(user)) { + continue; + } + if (userScore.hasScore(requiredScore)) { + numQuestionsCorrect++; + } + } + } + return numQuestionsCorrect; + } + +} diff --git a/src/main/java/de/thm/arsnova/domain/QuestionScore.java b/src/main/java/de/thm/arsnova/domain/QuestionScore.java new file mode 100644 index 0000000000000000000000000000000000000000..457c84edd876201fd9834efe90f1bc2d411fbbb5 --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/QuestionScore.java @@ -0,0 +1,84 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.domain; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import de.thm.arsnova.entities.User; + +public class QuestionScore implements Iterable<UserScore> { + + private String questionId; + + private int maximumScore; + + private List<UserScore> userScores = new ArrayList<UserScore>(); + + public QuestionScore(String questionId, int maximumScore) { + this.questionId = questionId; + this.maximumScore = maximumScore; + } + + public int getMaximum() { + return this.maximumScore; + } + + @Override + public Iterator<UserScore> iterator() { + return this.userScores.iterator(); + } + + public boolean hasScores() { + return this.userScores.size() > 0; + } + + public void add(String username, int userscore) { + userScores.add(new UserScore(username, userscore)); + } + + public int getTotalUserScore() { + int totalScore = 0; + for (UserScore score : userScores) { + totalScore += score.getScore(); + } + return totalScore; + } + + public int getTotalUserScore(User user) { + int totalScore = 0; + for (UserScore score : userScores) { + if (score.isUser(user)) { + totalScore += score.getScore(); + } + } + return totalScore; + } + + public int getUserCount() { + return userScores.size(); + } + + public void collectUsers(Set<String> users) { + for (UserScore score : userScores) { + users.add(score.getUsername()); + } + } +} diff --git a/src/main/java/de/thm/arsnova/domain/UserScore.java b/src/main/java/de/thm/arsnova/domain/UserScore.java new file mode 100644 index 0000000000000000000000000000000000000000..282fd06e7e73692997fee753e597b91e0c84cfde --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/UserScore.java @@ -0,0 +1,48 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.domain; + +import de.thm.arsnova.entities.User; + +public class UserScore { + + private String username; + + private int score; + + public UserScore(String username, int score) { + this.username = username; + this.score = score; + } + + public boolean hasScore(int score) { + return this.score == score; + } + + public int getScore() { + return score; + } + + public boolean isUser(User user) { + return user.getUsername().equals(username); + } + + public String getUsername() { + return username; + } +} diff --git a/src/main/java/de/thm/arsnova/domain/package-info.java b/src/main/java/de/thm/arsnova/domain/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..ee2d2f1de66118173509e1ba7b8f66e6acf2343f --- /dev/null +++ b/src/main/java/de/thm/arsnova/domain/package-info.java @@ -0,0 +1 @@ +package de.thm.arsnova.domain; \ No newline at end of file diff --git a/src/main/java/de/thm/arsnova/entities/Session.java b/src/main/java/de/thm/arsnova/entities/Session.java index 78e7dbd386229bac08d0d68fb7d38f95109b1e19..467bf26ba80da0e6012b58b8032d9d884776da98 100644 --- a/src/main/java/de/thm/arsnova/entities/Session.java +++ b/src/main/java/de/thm/arsnova/entities/Session.java @@ -37,6 +37,7 @@ public class Session implements Serializable { private String courseId; private List<String> _conflicts; private long creationTime; + private String learningProgressType = "questions"; private String ppAuthorName; private String ppAuthorMail; @@ -68,6 +69,8 @@ public class Session implements Serializable { copy.lastOwnerActivity = original.lastOwnerActivity; copy.courseType = original.courseType; copy.courseId = original.courseId; + copy.creationTime = original.creationTime; + copy.learningProgressType = original.learningProgressType; copy._id = original._id; copy._rev = original._rev; return copy; @@ -186,6 +189,14 @@ public class Session implements Serializable { this.creationTime = creationTime; } + public String getLearningProgressType() { + return learningProgressType; + } + + public void setLearningProgressType(String learningProgressType) { + this.learningProgressType = learningProgressType; + } + public String getPpAuthorName() { return ppAuthorName; } diff --git a/src/main/java/de/thm/arsnova/entities/transport/LearningProgressType.java b/src/main/java/de/thm/arsnova/entities/transport/LearningProgressType.java new file mode 100644 index 0000000000000000000000000000000000000000..4293c34b1258757b37b70878c8429845e98aa913 --- /dev/null +++ b/src/main/java/de/thm/arsnova/entities/transport/LearningProgressType.java @@ -0,0 +1,41 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.entities.transport; + +public class LearningProgressType { + + private String sessionKeyword; + + private String learningProgressType; + + public String getSessionKeyword() { + return sessionKeyword; + } + + public void setSessionKeyword(String sessionKeyword) { + this.sessionKeyword = sessionKeyword; + } + + public String getLearningProgressType() { + return learningProgressType; + } + + public void setLearningProgressType(String learningProgressType) { + this.learningProgressType = learningProgressType; + } +} diff --git a/src/main/java/de/thm/arsnova/services/ISessionService.java b/src/main/java/de/thm/arsnova/services/ISessionService.java index a65413aad83d0860a34d0eac85ec45e6901ee199..9104ddfbe6b94ec4defb9e82809cf57d3991a5f9 100644 --- a/src/main/java/de/thm/arsnova/services/ISessionService.java +++ b/src/main/java/de/thm/arsnova/services/ISessionService.java @@ -24,11 +24,14 @@ import java.util.UUID; import de.thm.arsnova.connector.model.Course; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.SessionInfo; +import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.transport.ImportExportSession; public interface ISessionService { Session getSession(String keyword); + Session getSessionInternal(String keyword, User user); + Session saveSession(Session session); boolean sessionKeyAvailable(String keyword); @@ -49,11 +52,13 @@ public interface ISessionService { Session updateSession(String sessionkey, Session session); + Session updateSessionInternal(Session session, User user); + void deleteSession(String sessionkey); - int getLearningProgress(String sessionkey); + int getLearningProgress(String sessionkey, String progressType); - SimpleEntry<Integer, Integer> getMyLearningProgress(String sessionkey); + SimpleEntry<Integer, Integer> getMyLearningProgress(String sessionkey, String progressType); List<SessionInfo> getMySessionsInfo(); diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java index d3d0267a663fb5c921e5755f06ff2dd29b165c10..9d490dad1513d956a1cbb40a9099eaf47c117887 100644 --- a/src/main/java/de/thm/arsnova/services/SessionService.java +++ b/src/main/java/de/thm/arsnova/services/SessionService.java @@ -34,6 +34,8 @@ import de.thm.arsnova.ImageUtils; import de.thm.arsnova.connector.client.ConnectorClient; import de.thm.arsnova.connector.model.Course; import de.thm.arsnova.dao.IDatabaseDao; +import de.thm.arsnova.domain.LearningProgress; +import de.thm.arsnova.domain.LearningProgressFactory; import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.SessionInfo; @@ -93,6 +95,9 @@ public class SessionService implements ISessionService { @Autowired private ARSnovaSocketIOServer socketIoServer; + @Autowired + private LearningProgressFactory learningProgressFactory; + @Autowired(required = false) private ConnectorClient connectorClient; @@ -138,6 +143,15 @@ public class SessionService implements ISessionService { @PreAuthorize("isAuthenticated()") public final Session getSession(final String keyword) { final User user = userService.getCurrentUser(); + return this.getSessionInternal(keyword, user); + } + + /* + * The "internal" suffix means it is called by internal services that have no authentication! + * TODO: Find a better way of doing this... + */ + @Override + public final Session getSessionInternal(final String keyword, final User user) { final Session session = databaseDao.getSessionFromKeyword(keyword); if (session == null) { throw new NotFoundException(); @@ -274,6 +288,18 @@ public class SessionService implements ISessionService { return databaseDao.updateSession(session); } + /* + * The "internal" suffix means it is called by internal services that have no authentication! + * TODO: Find a better way of doing this... + */ + @Override + public Session updateSessionInternal(final Session session, final User user) { + if (session.isCreator(user)) { + return databaseDao.updateSession(session); + } + return null; + } + @Override @PreAuthorize("isAuthenticated() and hasPermission(#sessionkey, 'session', 'owner')") public void deleteSession(final String sessionkey) { @@ -286,17 +312,19 @@ public class SessionService implements ISessionService { @Override @PreAuthorize("isAuthenticated()") - public int getLearningProgress(final String sessionkey) { + public int getLearningProgress(final String sessionkey, final String progressType) { final Session session = databaseDao.getSession(sessionkey); - return databaseDao.getLearningProgress(session); + LearningProgress learningProgress = learningProgressFactory.createFromType(progressType); + return learningProgress.getCourseProgress(session); } @Override @PreAuthorize("isAuthenticated()") - public SimpleEntry<Integer, Integer> getMyLearningProgress(final String sessionkey) { + public SimpleEntry<Integer, Integer> getMyLearningProgress(final String sessionkey, final String progressType) { final Session session = databaseDao.getSession(sessionkey); final User user = userService.getCurrentUser(); - return databaseDao.getMyLearningProgress(session, user); + LearningProgress learningProgress = learningProgressFactory.createFromType(progressType); + return learningProgress.getMyProgress(session, user); } @Override diff --git a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java index 2cb748b7c183b3ae23f68633ca7991005dd09d64..8cf4e7451b6dc1730f0e41abd02db033b440b509 100644 --- a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java +++ b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java @@ -48,6 +48,7 @@ import com.corundumstudio.socketio.protocol.PacketType; import de.thm.arsnova.entities.InterposedQuestion; import de.thm.arsnova.entities.User; +import de.thm.arsnova.entities.transport.LearningProgressType; import de.thm.arsnova.events.DeleteAnswerEvent; import de.thm.arsnova.events.NewAnswerEvent; import de.thm.arsnova.events.NewInterposedQuestionEvent; @@ -188,6 +189,22 @@ public class ARSnovaSocketIOServer implements ApplicationListener<NovaEvent>, No } }); + server.addEventListener( + "setLearningProgressType", + LearningProgressType.class, + new DataListener<LearningProgressType>() { + @Override + public void onData(SocketIOClient client, LearningProgressType progressType, AckRequest ack) { + final User user = userService.getUser2SocketId(client.getSessionId()); + final de.thm.arsnova.entities.Session session = sessionService.getSessionInternal(progressType.getSessionKeyword(), user); + if (session.isCreator(user)) { + session.setLearningProgressType(progressType.getLearningProgressType()); + sessionService.updateSessionInternal(session, user); + broadcastInSession(session.getKeyword(), "learningProgressType", progressType.getLearningProgressType()); + } + } + }); + server.addConnectListener(new ConnectListener() { @Override public void onConnect(final SocketIOClient client) { } @@ -316,11 +333,13 @@ public class ARSnovaSocketIOServer implements ApplicationListener<NovaEvent>, No * @param client */ public void reportSessionDataToClient(final String sessionKey, final User user, final SocketIOClient client) { + final de.thm.arsnova.entities.Session session = sessionService.getSessionInternal(sessionKey, user); client.sendEvent("unansweredLecturerQuestions", questionService.getUnAnsweredLectureQuestionIds(sessionKey, user)); client.sendEvent("unansweredPreparationQuestions", questionService.getUnAnsweredPreparationQuestionIds(sessionKey, user)); client.sendEvent("countLectureQuestionAnswers", questionService.countLectureQuestionAnswersInternal(sessionKey)); client.sendEvent("countPreparationQuestionAnswers", questionService.countPreparationQuestionAnswersInternal(sessionKey)); client.sendEvent("activeUserCountData", sessionService.activeUsers(sessionKey)); + client.sendEvent("learningProgressType", session.getLearningProgressType()); final de.thm.arsnova.entities.Feedback fb = feedbackService.getFeedback(sessionKey); client.sendEvent("feedbackData", fb.getValues()); try { diff --git a/src/main/webapp/WEB-INF/spring/spring-main.xml b/src/main/webapp/WEB-INF/spring/spring-main.xml index b9bedd607523757fe09fd2554f21851a8eaa0b7f..e5141f7570cf970dfb379f5dc75f9ab957286c4e 100644 --- a/src/main/webapp/WEB-INF/spring/spring-main.xml +++ b/src/main/webapp/WEB-INF/spring/spring-main.xml @@ -23,7 +23,7 @@ <property name="fileEncoding" value="UTF-8" /> </bean> - <context:component-scan base-package="de.thm.arsnova.dao,de.thm.arsnova.events,de.thm.arsnova.security,de.thm.arsnova.services,de.thm.arsnova.config" /> + <context:component-scan base-package="de.thm.arsnova.dao,de.thm.arsnova.events,de.thm.arsnova.security,de.thm.arsnova.services,de.thm.arsnova.config,de.thm.arsnova.domain" /> <context:annotation-config /> diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index d9ce9195a221128da561b562e8f36b999438b656..a0e26baa9cfab05611458c9b4d82eb68deb2fed9 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -18,13 +18,13 @@ */ package de.thm.arsnova.dao; -import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import de.thm.arsnova.connector.model.Course; +import de.thm.arsnova.domain.CourseScore; import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.DbUser; import de.thm.arsnova.entities.Feedback; @@ -510,13 +510,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public int getLearningProgress(Session session) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public SimpleEntry<Integer, Integer> getMyLearningProgress(Session session, User user) { + public CourseScore getLearningProgress(Session session) { // TODO Auto-generated method stub return null; }