diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java index e03e2cab3e4537d16440598aedd25c05d0c2eaaf..1ae11a81bfde4abc0cd8dc5d9642cb7fa339c60a 100644 --- a/src/main/java/de/thm/arsnova/controller/SessionController.java +++ b/src/main/java/de/thm/arsnova/controller/SessionController.java @@ -21,8 +21,6 @@ import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; - import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONObject; @@ -43,6 +41,7 @@ import org.springframework.web.bind.annotation.RestController; import de.thm.arsnova.connector.model.Course; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.SessionInfo; +import de.thm.arsnova.entities.transport.ImportExportSession; import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.services.ISessionService; import de.thm.arsnova.services.IUserService; @@ -211,6 +210,14 @@ public class SessionController extends AbstractController { return sessions; } + @RequestMapping(value = "/import", method = RequestMethod.POST) + public final List<SessionInfo> importSession( + @RequestBody final ImportExportSession session, + final HttpServletResponse response + ) { + return sessionService.importSession(session); + } + @RequestMapping(value = "/{sessionkey}/lock", method = RequestMethod.POST) public final Session lockSession( @PathVariable final String sessionkey, diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index 5cd4730dbdd56901ba9dfa276e3c56dc9a1299f8..c2decaacf287bfcb42d8ba796c31d7b7c52e72a8 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import net.sf.ezmorph.Morpher; @@ -63,6 +64,8 @@ import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.VisitedSession; +import de.thm.arsnova.entities.transport.ImportExportSession; +import de.thm.arsnova.entities.transport.ImportExportSession.ImportExportQuestion; import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.services.ISessionService; @@ -1691,4 +1694,55 @@ public class CouchDBDao implements IDatabaseDao { return false; } + + @Override + public List<SessionInfo> importSession(User user, Session s, ImportExportSession importSession) { + final Session session = this.saveSession(user, s); + List<Document> questions = new ArrayList<Document>(); + // We need to remember which answers belong to which question. + // The answers need a questionId, so we first store the questions to get the IDs. + // Then we update the answer objects and store them as well. + Map<Document, ImportExportQuestion> mapping = new HashMap<Document, ImportExportQuestion>(); + try { + // add session id to all questions and generate documents + for (ImportExportQuestion question : importSession.getQuestions()) { + Document doc = toQuestionDocument(session, question); + question.setSessionId(session.get_id()); + questions.add(doc); + mapping.put(doc, question); + } + database.bulkSaveDocuments(questions.toArray(new Document[questions.size()])); + } catch (final IOException e) { + LOGGER.error("Could not bulk save all questions: {}", e.getMessage()); + } + // now bulk import all answers + List<Document> answers = new ArrayList<Document>(); + try { + for (Entry<Document, ImportExportQuestion> entry : mapping.entrySet()) { + final Document doc = entry.getKey(); + final ImportExportQuestion question = entry.getValue(); + question.set_id(doc.getId()); + question.set_rev(doc.getRev()); + for (de.thm.arsnova.entities.transport.Answer answer : question.getAnswers()) { + final Answer a = answer.generateAnswerEntity(user, question); + final Document answerDoc = new Document(); + answerDoc.put("type", "skill_question_answer"); + answerDoc.put("sessionId", a.getSessionId()); + answerDoc.put("questionId", a.getQuestionId()); + answerDoc.put("answerSubject", a.getAnswerSubject()); + answerDoc.put("questionVariant", a.getQuestionVariant()); + answerDoc.put("questionValue", a.getQuestionValue()); + answerDoc.put("answerText", a.getAnswerText()); + answerDoc.put("timestamp", a.getTimestamp()); + answerDoc.put("piRound", a.getPiRound()); + answerDoc.put("abstention", a.isAbstention()); + answers.add(answerDoc); + } + } + database.bulkSaveDocuments(answers.toArray(new Document[answers.size()])); + } catch (IOException e) { + LOGGER.error("Could not bulk save all answers: {}", e.getMessage()); + } + return null; + } } diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index 092e267e2ab698852b4b21f3afcb77b17057ba00..f08c1bc97d676b722fe6cb48d910caa697f67853 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -19,6 +19,7 @@ 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.entities.Answer; import de.thm.arsnova.entities.DbUser; @@ -29,6 +30,7 @@ import de.thm.arsnova.entities.Question; 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 IDatabaseDao { Session getSessionFromKeyword(String keyword); @@ -184,4 +186,6 @@ public interface IDatabaseDao { void deleteAllPreparationAnswers(Session session); void deleteAllLectureAnswers(Session session); + + List<SessionInfo> importSession(User user, Session session, ImportExportSession importSession); } diff --git a/src/main/java/de/thm/arsnova/entities/SessionInfo.java b/src/main/java/de/thm/arsnova/entities/SessionInfo.java index ee218748af70992cf17251125a5b84e9755ff985..71e925eff3116cfa15af990da49b7039828ddf3b 100644 --- a/src/main/java/de/thm/arsnova/entities/SessionInfo.java +++ b/src/main/java/de/thm/arsnova/entities/SessionInfo.java @@ -31,13 +31,13 @@ public class SessionInfo { private String sessionType; private String ppLevel; private String ppSubject; - + private int numQuestions; private int numAnswers; private int numInterposed; private int numUnredInterposed; private int numUnanswered; - + public SessionInfo(Session session) { this.name = session.getName(); this.shortName = session.getShortName(); @@ -50,6 +50,8 @@ public class SessionInfo { this.ppSubject = session.getPpSubject(); } + public SessionInfo() {} + public static List<SessionInfo> fromSessionList(List<Session> sessions) { List<SessionInfo> infos = new ArrayList<SessionInfo>(); for (Session s : sessions) { @@ -97,27 +99,27 @@ public class SessionInfo { public void setCourseType(String courseType) { this.courseType = courseType; } - + public String getSessionType() { return sessionType; } - + public void setSessionType(String sessionType) { this.sessionType = sessionType; } - + public String getPpLevel() { return ppLevel; } - + public void setPpLevel(String ppLevel) { this.ppLevel = ppLevel; } - + public String getPpSubject() { return ppSubject; } - + public void setPpSubject(String ppSubject) { this.ppSubject = ppSubject; } @@ -153,7 +155,7 @@ public class SessionInfo { public void setNumUnanswered(int numUnanswered) { this.numUnanswered = numUnanswered; } - + public long getCreationTime() { return creationTime; } diff --git a/src/main/java/de/thm/arsnova/entities/transport/Answer.java b/src/main/java/de/thm/arsnova/entities/transport/Answer.java index 77d76e768ca2f6a2d890f46f0705acaae8234d50..b12dde79236ae21993546d4d7d9fc41e7302bf79 100644 --- a/src/main/java/de/thm/arsnova/entities/transport/Answer.java +++ b/src/main/java/de/thm/arsnova/entities/transport/Answer.java @@ -17,8 +17,13 @@ */ package de.thm.arsnova.entities.transport; +import java.util.Date; + import com.fasterxml.jackson.annotation.JsonInclude; +import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.User; + @JsonInclude(JsonInclude.Include.NON_DEFAULT) public class Answer { @@ -51,4 +56,28 @@ public class Answer { public void setAbstention(boolean abstention) { this.abstention = abstention; } + + public de.thm.arsnova.entities.Answer generateAnswerEntity(final User user, final Question question) { + // rewrite all fields so that no manipulated data gets written + // only answerText, answerSubject, and abstention are allowed + de.thm.arsnova.entities.Answer theAnswer = new de.thm.arsnova.entities.Answer(); + theAnswer.setAnswerSubject(this.getAnswerSubject()); + theAnswer.setAnswerText(this.getAnswerText()); + theAnswer.setSessionId(question.getSessionId()); + theAnswer.setUser(user.getUsername()); + theAnswer.setQuestionId(question.get_id()); + theAnswer.setTimestamp(new Date().getTime()); + theAnswer.setQuestionVariant(question.getQuestionVariant()); + theAnswer.setAbstention(this.isAbstention()); + // calculate learning progress value after all properties are set + theAnswer.setQuestionValue(question.calculateValue(theAnswer)); + + if ("freetext".equals(question.getQuestionType())) { + theAnswer.setPiRound(0); + } else { + theAnswer.setPiRound(question.getPiRound()); + } + + return theAnswer; + } } diff --git a/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java b/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java new file mode 100644 index 0000000000000000000000000000000000000000..76feb0b7603e7dc7e06077a50715182642205172 --- /dev/null +++ b/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java @@ -0,0 +1,101 @@ +package de.thm.arsnova.entities.transport; + +import java.util.Date; +import java.util.List; + +import de.thm.arsnova.entities.InterposedQuestion; +import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; + +public class ImportExportSession { + + private ImportExportSesssion session; + + private List<ImportExportQuestion> questions; + + private List<InterposedQuestion> feedbackQuestions; + + public ImportExportSesssion getSession() { + return session; + } + + public void setSession(ImportExportSesssion session) { + this.session = session; + } + + public List<ImportExportQuestion> getQuestions() { + return questions; + } + + public void setQuestions(List<ImportExportQuestion> questions) { + this.questions = questions; + } + + public List<InterposedQuestion> getFeedbackQuestions() { + return feedbackQuestions; + } + + public void setFeedbackQuestions(List<InterposedQuestion> feedbackQuestions) { + this.feedbackQuestions = feedbackQuestions; + } + + public Session generateSessionEntity(User user) { + final Session s = new Session(); + // import fields + s.setActive(session.isActive()); + s.setName(session.getName()); + s.setShortName(session.getShortName()); + // other fields + s.setType("session"); + s.setCreator(user.getUsername()); + s.setCreationTime(new Date().getTime()); + return s; + } + + public static class ImportExportQuestion extends Question { + + private List<Answer> answers; + + public List<Answer> getAnswers() { + return answers; + } + + public void setAnswers(List<Answer> answers) { + this.answers = answers; + } + } + + public static class ImportExportSesssion { + + private String name; + + private String shortName; + + private boolean active; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + } +} diff --git a/src/main/java/de/thm/arsnova/services/ISessionService.java b/src/main/java/de/thm/arsnova/services/ISessionService.java index de19d60e93821c8787470eab7cbe4abfc80bfee9..da8106e10d50c9c8cea45f500ec1f1dc9f3762e3 100644 --- a/src/main/java/de/thm/arsnova/services/ISessionService.java +++ b/src/main/java/de/thm/arsnova/services/ISessionService.java @@ -18,14 +18,13 @@ package de.thm.arsnova.services; import java.util.AbstractMap.SimpleEntry; -import java.util.ArrayList; import java.util.List; -import java.util.Map; 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.transport.ImportExportSession; public interface ISessionService { Session getSession(String keyword); @@ -63,4 +62,6 @@ public interface ISessionService { List<SessionInfo> getMyPublicPoolSessionsInfo(); List<SessionInfo> getMyVisitedSessionsInfo(); + + List<SessionInfo> importSession(ImportExportSession session); } diff --git a/src/main/java/de/thm/arsnova/services/QuestionService.java b/src/main/java/de/thm/arsnova/services/QuestionService.java index 041493b8b03e17387e809253c2a315d93a223556..a4f119fd7edcb367369474e6e953ab02367a004c 100644 --- a/src/main/java/de/thm/arsnova/services/QuestionService.java +++ b/src/main/java/de/thm/arsnova/services/QuestionService.java @@ -21,7 +21,6 @@ import java.util.AbstractMap; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -431,25 +430,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis throw new NotFoundException(); } - // rewrite all fields so that no manipulated data gets written - // only answerText, answerSubject, and abstention are allowed - Answer theAnswer = new Answer(); - theAnswer.setAnswerSubject(answer.getAnswerSubject()); - theAnswer.setAnswerText(answer.getAnswerText()); - theAnswer.setSessionId(question.getSessionId()); - theAnswer.setUser(user.getUsername()); - theAnswer.setQuestionId(question.get_id()); - theAnswer.setTimestamp(new Date().getTime()); - theAnswer.setQuestionVariant(question.getQuestionVariant()); - theAnswer.setAbstention(answer.isAbstention()); - // calculate learning progress value after all properties are set - theAnswer.setQuestionValue(question.calculateValue(theAnswer)); - - if ("freetext".equals(question.getQuestionType())) { - theAnswer.setPiRound(0); - } else { - theAnswer.setPiRound(question.getPiRound()); - } + Answer theAnswer = answer.generateAnswerEntity(user, question); final Answer result = databaseDao.saveAnswer(theAnswer, user); final Session session = databaseDao.getSessionFromKeyword(question.getSessionKeyword()); diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java index 8da5105bc013ebb32ed1cfe0553186bcde008d03..1e8f5dbc9d5c252ca5f17c05b4e4692eaa919cf2 100644 --- a/src/main/java/de/thm/arsnova/services/SessionService.java +++ b/src/main/java/de/thm/arsnova/services/SessionService.java @@ -27,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +38,7 @@ import de.thm.arsnova.entities.Question; 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; import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.exceptions.BadRequestException; @@ -298,4 +298,12 @@ public class SessionService implements ISessionService { final User user = userService.getCurrentUser(); return databaseDao.getMyLearningProgress(session, user); } + + @Override + @PreAuthorize("isAuthenticated()") + public List<SessionInfo> importSession(ImportExportSession importSession) { + final User user = userService.getCurrentUser(); + final Session session = importSession.generateSessionEntity(user); + return databaseDao.importSession(user, session, importSession); + } } diff --git a/src/main/resources/log4j-dev.properties b/src/main/resources/log4j-dev.properties index c8a5268ac4d8bda8d9917488730f0e48ee71fb90..6be5e1a8f4f24c4a0e0df4aea377aef84216df63 100644 --- a/src/main/resources/log4j-dev.properties +++ b/src/main/resources/log4j-dev.properties @@ -9,4 +9,5 @@ log4j.category.org.springframework=INFO log4j.category.com.corundumstudio.socketio=INFO log4j.category.com.corundumstudio.socketio.handler.AuthorizeHandler=ERROR log4j.category.com.fourspaces.couchdb=OFF -log4j.category.net.sf.json=WARN \ No newline at end of file +log4j.category.net.sf.json=WARN +log4j.category.org.springframework.web.servlet.mvc=TRACE \ No newline at end of file diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index ab187a6342197304ba5321a403c5e2660f7d3101..6c9cb35b67647cf7dde3d9c3e96fc7e53fe0c028 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -35,6 +35,7 @@ import de.thm.arsnova.entities.Question; 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; import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NotFoundException; @@ -573,4 +574,10 @@ public class StubDatabaseDao implements IDatabaseDao { // TODO Auto-generated method stub return 0; } + + @Override + public List<SessionInfo> importSession(User user, Session session, ImportExportSession importSession) { + // TODO Auto-generated method stub + return null; + } }