Skip to content
Snippets Groups Projects
Commit 4fcb3127 authored by Christoph Thelen's avatar Christoph Thelen
Browse files

Fix for #14474: Import session using bulk requests

parent a10d8ad1
Branches
Tags
No related merge requests found
Showing
with 230 additions and 35 deletions
...@@ -21,8 +21,6 @@ import java.util.AbstractMap.SimpleEntry; ...@@ -21,8 +21,6 @@ import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject; import net.sf.json.JSONObject;
...@@ -43,6 +41,7 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -43,6 +41,7 @@ import org.springframework.web.bind.annotation.RestController;
import de.thm.arsnova.connector.model.Course; import de.thm.arsnova.connector.model.Course;
import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.Session;
import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.SessionInfo;
import de.thm.arsnova.entities.transport.ImportExportSession;
import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.exceptions.UnauthorizedException;
import de.thm.arsnova.services.ISessionService; import de.thm.arsnova.services.ISessionService;
import de.thm.arsnova.services.IUserService; import de.thm.arsnova.services.IUserService;
...@@ -211,6 +210,14 @@ public class SessionController extends AbstractController { ...@@ -211,6 +210,14 @@ public class SessionController extends AbstractController {
return sessions; 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) @RequestMapping(value = "/{sessionkey}/lock", method = RequestMethod.POST)
public final Session lockSession( public final Session lockSession(
@PathVariable final String sessionkey, @PathVariable final String sessionkey,
......
...@@ -26,6 +26,7 @@ import java.util.HashMap; ...@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import net.sf.ezmorph.Morpher; import net.sf.ezmorph.Morpher;
...@@ -63,6 +64,8 @@ import de.thm.arsnova.entities.Session; ...@@ -63,6 +64,8 @@ import de.thm.arsnova.entities.Session;
import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.SessionInfo;
import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.User;
import de.thm.arsnova.entities.VisitedSession; 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.exceptions.NotFoundException;
import de.thm.arsnova.services.ISessionService; import de.thm.arsnova.services.ISessionService;
...@@ -1691,4 +1694,55 @@ public class CouchDBDao implements IDatabaseDao { ...@@ -1691,4 +1694,55 @@ public class CouchDBDao implements IDatabaseDao {
return false; 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;
}
} }
...@@ -19,6 +19,7 @@ package de.thm.arsnova.dao; ...@@ -19,6 +19,7 @@ package de.thm.arsnova.dao;
import java.util.AbstractMap.SimpleEntry; import java.util.AbstractMap.SimpleEntry;
import java.util.List; import java.util.List;
import de.thm.arsnova.connector.model.Course; import de.thm.arsnova.connector.model.Course;
import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.Answer;
import de.thm.arsnova.entities.DbUser; import de.thm.arsnova.entities.DbUser;
...@@ -29,6 +30,7 @@ import de.thm.arsnova.entities.Question; ...@@ -29,6 +30,7 @@ import de.thm.arsnova.entities.Question;
import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.Session;
import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.SessionInfo;
import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.User;
import de.thm.arsnova.entities.transport.ImportExportSession;
public interface IDatabaseDao { public interface IDatabaseDao {
Session getSessionFromKeyword(String keyword); Session getSessionFromKeyword(String keyword);
...@@ -184,4 +186,6 @@ public interface IDatabaseDao { ...@@ -184,4 +186,6 @@ public interface IDatabaseDao {
void deleteAllPreparationAnswers(Session session); void deleteAllPreparationAnswers(Session session);
void deleteAllLectureAnswers(Session session); void deleteAllLectureAnswers(Session session);
List<SessionInfo> importSession(User user, Session session, ImportExportSession importSession);
} }
...@@ -31,13 +31,13 @@ public class SessionInfo { ...@@ -31,13 +31,13 @@ public class SessionInfo {
private String sessionType; private String sessionType;
private String ppLevel; private String ppLevel;
private String ppSubject; private String ppSubject;
private int numQuestions; private int numQuestions;
private int numAnswers; private int numAnswers;
private int numInterposed; private int numInterposed;
private int numUnredInterposed; private int numUnredInterposed;
private int numUnanswered; private int numUnanswered;
public SessionInfo(Session session) { public SessionInfo(Session session) {
this.name = session.getName(); this.name = session.getName();
this.shortName = session.getShortName(); this.shortName = session.getShortName();
...@@ -50,6 +50,8 @@ public class SessionInfo { ...@@ -50,6 +50,8 @@ public class SessionInfo {
this.ppSubject = session.getPpSubject(); this.ppSubject = session.getPpSubject();
} }
public SessionInfo() {}
public static List<SessionInfo> fromSessionList(List<Session> sessions) { public static List<SessionInfo> fromSessionList(List<Session> sessions) {
List<SessionInfo> infos = new ArrayList<SessionInfo>(); List<SessionInfo> infos = new ArrayList<SessionInfo>();
for (Session s : sessions) { for (Session s : sessions) {
...@@ -97,27 +99,27 @@ public class SessionInfo { ...@@ -97,27 +99,27 @@ public class SessionInfo {
public void setCourseType(String courseType) { public void setCourseType(String courseType) {
this.courseType = courseType; this.courseType = courseType;
} }
public String getSessionType() { public String getSessionType() {
return sessionType; return sessionType;
} }
public void setSessionType(String sessionType) { public void setSessionType(String sessionType) {
this.sessionType = sessionType; this.sessionType = sessionType;
} }
public String getPpLevel() { public String getPpLevel() {
return ppLevel; return ppLevel;
} }
public void setPpLevel(String ppLevel) { public void setPpLevel(String ppLevel) {
this.ppLevel = ppLevel; this.ppLevel = ppLevel;
} }
public String getPpSubject() { public String getPpSubject() {
return ppSubject; return ppSubject;
} }
public void setPpSubject(String ppSubject) { public void setPpSubject(String ppSubject) {
this.ppSubject = ppSubject; this.ppSubject = ppSubject;
} }
...@@ -153,7 +155,7 @@ public class SessionInfo { ...@@ -153,7 +155,7 @@ public class SessionInfo {
public void setNumUnanswered(int numUnanswered) { public void setNumUnanswered(int numUnanswered) {
this.numUnanswered = numUnanswered; this.numUnanswered = numUnanswered;
} }
public long getCreationTime() { public long getCreationTime() {
return creationTime; return creationTime;
} }
......
...@@ -17,8 +17,13 @@ ...@@ -17,8 +17,13 @@
*/ */
package de.thm.arsnova.entities.transport; package de.thm.arsnova.entities.transport;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import de.thm.arsnova.entities.Question;
import de.thm.arsnova.entities.User;
@JsonInclude(JsonInclude.Include.NON_DEFAULT) @JsonInclude(JsonInclude.Include.NON_DEFAULT)
public class Answer { public class Answer {
...@@ -51,4 +56,28 @@ public class Answer { ...@@ -51,4 +56,28 @@ public class Answer {
public void setAbstention(boolean abstention) { public void setAbstention(boolean abstention) {
this.abstention = 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;
}
} }
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;
}
}
}
...@@ -18,14 +18,13 @@ ...@@ -18,14 +18,13 @@
package de.thm.arsnova.services; package de.thm.arsnova.services;
import java.util.AbstractMap.SimpleEntry; import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import de.thm.arsnova.connector.model.Course; import de.thm.arsnova.connector.model.Course;
import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.Session;
import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.SessionInfo;
import de.thm.arsnova.entities.transport.ImportExportSession;
public interface ISessionService { public interface ISessionService {
Session getSession(String keyword); Session getSession(String keyword);
...@@ -63,4 +62,6 @@ public interface ISessionService { ...@@ -63,4 +62,6 @@ public interface ISessionService {
List<SessionInfo> getMyPublicPoolSessionsInfo(); List<SessionInfo> getMyPublicPoolSessionsInfo();
List<SessionInfo> getMyVisitedSessionsInfo(); List<SessionInfo> getMyVisitedSessionsInfo();
List<SessionInfo> importSession(ImportExportSession session);
} }
...@@ -21,7 +21,6 @@ import java.util.AbstractMap; ...@@ -21,7 +21,6 @@ import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry; import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -431,25 +430,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis ...@@ -431,25 +430,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis
throw new NotFoundException(); throw new NotFoundException();
} }
// rewrite all fields so that no manipulated data gets written Answer theAnswer = answer.generateAnswerEntity(user, question);
// 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());
}
final Answer result = databaseDao.saveAnswer(theAnswer, user); final Answer result = databaseDao.saveAnswer(theAnswer, user);
final Session session = databaseDao.getSessionFromKeyword(question.getSessionKeyword()); final Session session = databaseDao.getSessionFromKeyword(question.getSessionKeyword());
......
...@@ -27,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -27,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -39,6 +38,7 @@ import de.thm.arsnova.entities.Question; ...@@ -39,6 +38,7 @@ import de.thm.arsnova.entities.Question;
import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.Session;
import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.SessionInfo;
import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.User;
import de.thm.arsnova.entities.transport.ImportExportSession;
import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.ForbiddenException;
import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.exceptions.NotFoundException;
import de.thm.arsnova.exceptions.BadRequestException; import de.thm.arsnova.exceptions.BadRequestException;
...@@ -298,4 +298,12 @@ public class SessionService implements ISessionService { ...@@ -298,4 +298,12 @@ public class SessionService implements ISessionService {
final User user = userService.getCurrentUser(); final User user = userService.getCurrentUser();
return databaseDao.getMyLearningProgress(session, user); 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);
}
} }
...@@ -9,4 +9,5 @@ log4j.category.org.springframework=INFO ...@@ -9,4 +9,5 @@ log4j.category.org.springframework=INFO
log4j.category.com.corundumstudio.socketio=INFO log4j.category.com.corundumstudio.socketio=INFO
log4j.category.com.corundumstudio.socketio.handler.AuthorizeHandler=ERROR log4j.category.com.corundumstudio.socketio.handler.AuthorizeHandler=ERROR
log4j.category.com.fourspaces.couchdb=OFF log4j.category.com.fourspaces.couchdb=OFF
log4j.category.net.sf.json=WARN log4j.category.net.sf.json=WARN
\ No newline at end of file log4j.category.org.springframework.web.servlet.mvc=TRACE
\ No newline at end of file
...@@ -35,6 +35,7 @@ import de.thm.arsnova.entities.Question; ...@@ -35,6 +35,7 @@ import de.thm.arsnova.entities.Question;
import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.Session;
import de.thm.arsnova.entities.SessionInfo; import de.thm.arsnova.entities.SessionInfo;
import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.User;
import de.thm.arsnova.entities.transport.ImportExportSession;
import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.ForbiddenException;
import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NoContentException;
import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.exceptions.NotFoundException;
...@@ -573,4 +574,10 @@ public class StubDatabaseDao implements IDatabaseDao { ...@@ -573,4 +574,10 @@ public class StubDatabaseDao implements IDatabaseDao {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return 0; return 0;
} }
@Override
public List<SessionInfo> importSession(User user, Session session, ImportExportSession importSession) {
// TODO Auto-generated method stub
return null;
}
} }
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