From 5778a5342264dfec1e7bed4517033342418606f8 Mon Sep 17 00:00:00 2001
From: Daniel Gerhardt <code@dgerhardt.net>
Date: Thu, 15 Feb 2018 13:14:50 +0100
Subject: [PATCH] Fix and improve Answer entity, migration and view

---
 .../java/de/thm/arsnova/entities/Answer.java  |  4 +-
 .../de/thm/arsnova/entities/TextAnswer.java   |  2 +-
 .../entities/migration/FromV2Migrator.java    | 46 +++++++++++++++----
 .../entities/migration/ToV2Migrator.java      | 26 +++++++++--
 src/main/resources/couchdb/Answer.design.js   | 18 ++++----
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/src/main/java/de/thm/arsnova/entities/Answer.java b/src/main/java/de/thm/arsnova/entities/Answer.java
index d0b77b263..58893fc34 100644
--- a/src/main/java/de/thm/arsnova/entities/Answer.java
+++ b/src/main/java/de/thm/arsnova/entities/Answer.java
@@ -8,8 +8,8 @@ import java.util.Map;
 import java.util.Objects;
 
 @JsonTypeInfo(
-		use = JsonTypeInfo.Id.MINIMAL_CLASS,
-		include = JsonTypeInfo.As.PROPERTY,
+		use = JsonTypeInfo.Id.NAME,
+		include = JsonTypeInfo.As.EXISTING_PROPERTY,
 		property = "type"
 )
 public abstract class Answer extends Entity {
diff --git a/src/main/java/de/thm/arsnova/entities/TextAnswer.java b/src/main/java/de/thm/arsnova/entities/TextAnswer.java
index 8e36c127e..14a32c287 100644
--- a/src/main/java/de/thm/arsnova/entities/TextAnswer.java
+++ b/src/main/java/de/thm/arsnova/entities/TextAnswer.java
@@ -43,6 +43,6 @@ public class TextAnswer extends Answer {
 	@Override
 	@JsonView({View.Persistence.class, View.Public.class})
 	public Date getCreationTimestamp() {
-		return getCreationTimestamp();
+		return creationTimestamp;
 	}
 }
diff --git a/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java b/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java
index 91067f880..898c6241d 100644
--- a/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java
+++ b/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java
@@ -225,27 +225,53 @@ public class FromV2Migrator {
 
 	public de.thm.arsnova.entities.Answer migrate(final Answer from, final Content content) {
 		switch (content.getQuestionType()) {
-			case "abcd":
-			case "mc":
-				return migrate(from, content.getPossibleAnswers());
-			case "freetext":
+			case V2_TYPE_ABCD:
+			case V2_TYPE_VOTE:
+			case V2_TYPE_SCHOOL:
+			case V2_TYPE_YESNO:
+				return migrate(from, content.getPossibleAnswers(), false);
+			case V2_TYPE_MC:
+				return migrate(from, content.getPossibleAnswers(), true);
+			case V2_TYPE_FREETEXT:
 				return migrate(from);
 			default:
 				throw new IllegalArgumentException("Unsupported content format.");
 		}
 	}
 
-	public ChoiceAnswer migrate(final Answer from, final List<AnswerOption> options) {
+	public ChoiceAnswer migrate(final Answer from, final List<AnswerOption> options, final boolean multiple) {
 		final ChoiceAnswer to = new ChoiceAnswer();
 		copyCommonProperties(from, to);
 		to.setContentId(from.getQuestionId());
+		to.setRoomId(from.getSessionId());
+		to.setRound(from.getPiRound());
 		List<Integer> selectedChoiceIndexes = new ArrayList<>();
 		to.setSelectedChoiceIndexes(selectedChoiceIndexes);
 
-		for (int i = 0; i < options.size(); i++) {
-			AnswerOption choice = options.get(i);
-			if (choice.getText().equals(from.getAnswerText())) {
-				selectedChoiceIndexes.add(i);
+		if (!from.isAbstention()) {
+			if (multiple) {
+				List<Boolean> flags = Arrays.stream(from.getAnswerText().split(","))
+						.map("1"::equals).collect(Collectors.toList());
+				if (flags.size() != options.size()) {
+					throw new IndexOutOfBoundsException(
+							"Number of answer's choice flags does not match number of content's answer options");
+				}
+				int i = 0;
+				for (boolean flag : flags) {
+					if (flag) {
+						selectedChoiceIndexes.add(i);
+					}
+					i++;
+				}
+			} else {
+				int i = 0;
+				for (AnswerOption option : options) {
+					if (option.getText().equals(from.getAnswerText())) {
+						selectedChoiceIndexes.add(i);
+						break;
+					}
+					i++;
+				}
 			}
 		}
 
@@ -256,6 +282,8 @@ public class FromV2Migrator {
 		final TextAnswer to = new TextAnswer();
 		copyCommonProperties(from, to);
 		to.setContentId(from.getQuestionId());
+		to.setRoomId(from.getSessionId());
+		to.setRound(from.getPiRound());
 		to.setSubject(from.getAnswerSubject());
 		to.setBody(from.getAnswerText());
 
diff --git a/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java b/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java
index 60abdf6f9..92655f42b 100644
--- a/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java
+++ b/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java
@@ -209,17 +209,33 @@ public class ToV2Migrator {
 		final Answer to = new Answer();
 		copyCommonProperties(from, to);
 		to.setQuestionId(from.getContentId());
+		to.setSessionId(from.getRoomId());
+		to.setPiRound(from.getRound());
 		if (creator.isPresent()) {
 			to.setUser(creator.get().getLoginId());
 		}
+		if (from.getSelectedChoiceIndexes().isEmpty()) {
+			to.setAbstention(true);
+		} else {
+			if (content.isMultiple()) {
+				to.setAnswerText(migrateChoice(from.getSelectedChoiceIndexes(), content.getOptions()));
+			} else {
+				int index = from.getSelectedChoiceIndexes().get(0);
+				to.setAnswerText(content.getOptions().get(index).getLabel());
+			}
+		}
 
+		return to;
+	}
+
+	public String migrateChoice(final List<Integer> selectedChoiceIndexes,
+			final List<ChoiceQuestionContent.AnswerOption> options) {
 		List<String> answers = new ArrayList<>();
-		for (int i = 0; i < content.getOptions().size(); i++) {
-			answers.add(from.getSelectedChoiceIndexes().contains(i) ? "1" : "0");
+		for (int i = 0; i < options.size(); i++) {
+			answers.add(selectedChoiceIndexes.contains(i) ? "1" : "0");
 		}
-		to.setAnswerText(answers.stream().collect(Collectors.joining()));
 
-		return to;
+		return answers.stream().collect(Collectors.joining(","));
 	}
 
 	public Answer migrate(final de.thm.arsnova.entities.ChoiceAnswer from,
@@ -232,6 +248,8 @@ public class ToV2Migrator {
 		final Answer to = new Answer();
 		copyCommonProperties(from, to);
 		to.setQuestionId(from.getContentId());
+		to.setSessionId(from.getRoomId());
+		to.setPiRound(from.getRound());
 		if (creator.isPresent()) {
 			to.setUser(creator.get().getLoginId());
 		}
diff --git a/src/main/resources/couchdb/Answer.design.js b/src/main/resources/couchdb/Answer.design.js
index e3702e94d..57e159962 100644
--- a/src/main/resources/couchdb/Answer.design.js
+++ b/src/main/resources/couchdb/Answer.design.js
@@ -4,14 +4,14 @@ var designDoc = {
 	"views": {
 		"by_contentid": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit(doc.contentId, {_rev: doc._rev});
 				}
 			}
 		},
 		"by_contentid_round_body_subject": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.contentId, doc.round, doc.abstention, doc.body, doc.subject, doc.successfulFreeTextAnswer], {_rev: doc._rev});
 				}
 			},
@@ -19,21 +19,21 @@ var designDoc = {
 		},
 		"by_contentid_creationtimestamp": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.contentId, doc.creationTimestamp], {_rev: doc._rev});
 				}
 			}
 		},
 		"by_contentid_user_round": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.contentId, doc.user, doc.round], {_rev: doc._rev});
 				}
 			}
 		},
 		"by_roomid": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit(doc.roomId, {_rev: doc._rev});
 				}
 			},
@@ -41,7 +41,7 @@ var designDoc = {
 		},
 		"by_roomid_variant": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.roomId, doc.questionVariant], {_rev: doc._rev});
 				}
 			},
@@ -49,21 +49,21 @@ var designDoc = {
 		},
 		"by_creatorid_roomid": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.creatorId, doc.roomId], {_rev: doc._rev});
 				}
 			}
 		},
 		"contentid_by_creatorid_roomid_variant": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.user, doc.roomId, doc.questionVariant], doc.contentId);
 				}
 			}
 		},
 		"contentid_round_by_creatorid_roomid_variant": {
 			"map": function (doc) {
-				if (doc.type === "Answer") {
+				if (["Answer", "ChoiceAnswer", "TextAnswer"].indexOf(doc.type) !== -1) {
 					emit([doc.creatorId, doc.roomId, doc.questionVariant], [doc.contentId, doc.round]);
 				}
 			}
-- 
GitLab