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
No related merge requests found
Showing
with 230 additions and 35 deletions
......@@ -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,
......
......@@ -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;
}
}
......@@ -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);
}
......@@ -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;
}
......
......@@ -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;
}
}
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 @@
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);
}
......@@ -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());
......
......@@ -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);
}
}
......@@ -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
......@@ -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;
}
}
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