From 72f3f617207e527f66578ee54cc0c29bbfe407b2 Mon Sep 17 00:00:00 2001 From: Christoph Thelen <christoph.thelen@mni.thm.de> Date: Fri, 6 Feb 2015 20:48:10 +0100 Subject: [PATCH] Set answer properties on the server --- .../LecturerQuestionController.java | 4 +- .../de/thm/arsnova/entities/Question.java | 47 ++++++ .../arsnova/entities/transport/Answer.java | 54 +++++++ .../entities/transport/package-info.java | 1 + .../arsnova/services/IQuestionService.java | 4 +- .../thm/arsnova/services/QuestionService.java | 27 +++- .../de/thm/arsnova/entities/QuestionTest.java | 142 ++++++++++++++++++ 7 files changed, 269 insertions(+), 10 deletions(-) create mode 100644 src/main/java/de/thm/arsnova/entities/transport/Answer.java create mode 100644 src/main/java/de/thm/arsnova/entities/transport/package-info.java create mode 100644 src/test/java/de/thm/arsnova/entities/QuestionTest.java diff --git a/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java b/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java index eb656043..3f9c9bd7 100644 --- a/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java +++ b/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java @@ -310,10 +310,10 @@ public class LecturerQuestionController extends AbstractController { @RequestMapping(value = "/{questionId}/answer/", method = RequestMethod.POST) public final Answer saveAnswer( @PathVariable final String questionId, - @RequestBody final Answer answer, + @RequestBody final de.thm.arsnova.entities.transport.Answer answer, final HttpServletResponse response ) { - return questionService.saveAnswer(answer); + return questionService.saveAnswer(questionId, answer); } @RequestMapping(value = "/{questionId}/answer/{answerId}", method = RequestMethod.PUT) diff --git a/src/main/java/de/thm/arsnova/entities/Question.java b/src/main/java/de/thm/arsnova/entities/Question.java index 8f268769..7ab74351 100644 --- a/src/main/java/de/thm/arsnova/entities/Question.java +++ b/src/main/java/de/thm/arsnova/entities/Question.java @@ -414,4 +414,51 @@ public class Question { public final String toString() { return "Question type '" + type + "': " + subject + ";\n" + text + possibleAnswers; } + + public int calculateValue(Answer answer) { + if (answer.isAbstention()) { + return 0; + } else if (this.questionType.equals("mc")) { + return calculateMultipleChoiceValue(answer); + } else if (this.questionType.equals("grid")) { + return calculateGridValue(answer); + } else { + return calculateRegularValue(answer); + } + } + + private int calculateRegularValue(Answer answer) { + String answerText = answer.getAnswerText(); + for (PossibleAnswer p : this.possibleAnswers) { + if (answerText.equals(p.getText())) { + return p.getValue(); + } + } + return 0; + } + + private int calculateGridValue(Answer answer) { + int value = 0; + String[] answers = answer.getAnswerText().split(","); + for (int i = 0; i < answers.length; i++) { + for (PossibleAnswer p : this.possibleAnswers) { + if (answers[i].equals(p.getText())) { + value += p.getValue(); + } + } + } + return value; + } + + private int calculateMultipleChoiceValue(Answer answer) { + int value = 0; + String[] answers = answer.getAnswerText().split(","); + for (int i = 0; i < this.possibleAnswers.size() && i < answers.length; i++) { + if (answers[i].equals("1")) { + PossibleAnswer p = this.possibleAnswers.get(i); + value += p.getValue(); + } + } + return value; + } } diff --git a/src/main/java/de/thm/arsnova/entities/transport/Answer.java b/src/main/java/de/thm/arsnova/entities/transport/Answer.java new file mode 100644 index 00000000..77d76e76 --- /dev/null +++ b/src/main/java/de/thm/arsnova/entities/transport/Answer.java @@ -0,0 +1,54 @@ +/* + * 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; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_DEFAULT) +public class Answer { + + private String answerSubject; + + private String answerText; + + private boolean abstention; + + public String getAnswerText() { + return answerText; + } + + public void setAnswerText(String answerText) { + this.answerText = answerText; + } + + public String getAnswerSubject() { + return answerSubject; + } + + public void setAnswerSubject(String answerSubject) { + this.answerSubject = answerSubject; + } + + public boolean isAbstention() { + return abstention; + } + + public void setAbstention(boolean abstention) { + this.abstention = abstention; + } +} diff --git a/src/main/java/de/thm/arsnova/entities/transport/package-info.java b/src/main/java/de/thm/arsnova/entities/transport/package-info.java new file mode 100644 index 00000000..accb5a5a --- /dev/null +++ b/src/main/java/de/thm/arsnova/entities/transport/package-info.java @@ -0,0 +1 @@ +package de.thm.arsnova.entities.transport; diff --git a/src/main/java/de/thm/arsnova/services/IQuestionService.java b/src/main/java/de/thm/arsnova/services/IQuestionService.java index a79438cc..31ce043e 100644 --- a/src/main/java/de/thm/arsnova/services/IQuestionService.java +++ b/src/main/java/de/thm/arsnova/services/IQuestionService.java @@ -17,8 +17,8 @@ */ package de.thm.arsnova.services; -import java.util.List; import java.util.AbstractMap.SimpleEntry; +import java.util.List; import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.InterposedQuestion; @@ -71,7 +71,7 @@ public interface IQuestionService { void deleteAnswers(String questionId); - Answer saveAnswer(Answer answer); + Answer saveAnswer(String questionId, de.thm.arsnova.entities.transport.Answer answer); Answer updateAnswer(Answer answer); diff --git a/src/main/java/de/thm/arsnova/services/QuestionService.java b/src/main/java/de/thm/arsnova/services/QuestionService.java index 66af7839..041493b8 100644 --- a/src/main/java/de/thm/arsnova/services/QuestionService.java +++ b/src/main/java/de/thm/arsnova/services/QuestionService.java @@ -18,12 +18,13 @@ package de.thm.arsnova.services; 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; -import java.util.AbstractMap.SimpleEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -423,20 +424,34 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public Answer saveAnswer(final Answer answer) { + public Answer saveAnswer(final String questionId, final de.thm.arsnova.entities.transport.Answer answer) { final User user = getCurrentUser(); - final Question question = getQuestion(answer.getQuestionId()); + final Question question = getQuestion(questionId); if (question == null) { 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())) { - answer.setPiRound(0); + theAnswer.setPiRound(0); } else { - answer.setPiRound(question.getPiRound()); + theAnswer.setPiRound(question.getPiRound()); } - final Answer result = databaseDao.saveAnswer(answer, user); + final Answer result = databaseDao.saveAnswer(theAnswer, user); final Session session = databaseDao.getSessionFromKeyword(question.getSessionKeyword()); this.publisher.publishEvent(new NewAnswerEvent(this, result, user, question, session)); diff --git a/src/test/java/de/thm/arsnova/entities/QuestionTest.java b/src/test/java/de/thm/arsnova/entities/QuestionTest.java new file mode 100644 index 00000000..d75ab042 --- /dev/null +++ b/src/test/java/de/thm/arsnova/entities/QuestionTest.java @@ -0,0 +1,142 @@ +package de.thm.arsnova.entities; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; + +import org.junit.Test; + +public class QuestionTest { + + @SuppressWarnings("serial") + @Test + public void shouldComputeBasedOnCorrectAnswerWithExactMatch() { + final PossibleAnswer p1 = new PossibleAnswer(); + p1.setText("Yes"); + p1.setCorrect(true); + p1.setValue(10); + final PossibleAnswer p2 = new PossibleAnswer(); + p2.setText("No"); + p2.setCorrect(false); + p2.setValue(-10); + Question q = new Question(); + q.setQuestionType("yesno"); + q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ + add(p1); + add(p2); + }}); + Answer answer1 = new Answer(); + answer1.setAnswerText("Yes"); + Answer answer2 = new Answer(); + answer2.setAnswerText("No"); + + assertEquals(10, q.calculateValue(answer1)); + assertEquals(-10, q.calculateValue(answer2)); + } + + @SuppressWarnings("serial") + @Test + public void shouldEqualAbstentionToZeroValue() { + final PossibleAnswer p1 = new PossibleAnswer(); + p1.setText("Yes"); + p1.setCorrect(true); + p1.setValue(10); + final PossibleAnswer p2 = new PossibleAnswer(); + p2.setText("No"); + p2.setCorrect(false); + p2.setValue(-10); + Question q = new Question(); + q.setAbstention(true); + q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ + add(p1); + add(p2); + }}); + Answer answer = new Answer(); + answer.setAbstention(true); + + assertEquals(0, q.calculateValue(answer)); + } + + @SuppressWarnings("serial") + @Test + public void shouldCalculateMultipleChoiceAnswers() { + final PossibleAnswer p1 = new PossibleAnswer(); + p1.setText("Yes"); + p1.setCorrect(true); + p1.setValue(10); + final PossibleAnswer p2 = new PossibleAnswer(); + p2.setText("No"); + p2.setCorrect(false); + p2.setValue(-10); + final PossibleAnswer p3 = new PossibleAnswer(); + p3.setText("Maybe"); + p3.setCorrect(true); + p3.setValue(10); + Question q = new Question(); + q.setQuestionType("mc"); + q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ + add(p1); + add(p2); + add(p3); + }}); + Answer answer1 = createAnswerWithText("0,0,0"); + Answer answer2 = createAnswerWithText("0,0,1"); + Answer answer3 = createAnswerWithText("0,1,0"); + Answer answer4 = createAnswerWithText("0,1,1"); + Answer answer5 = createAnswerWithText("1,0,0"); + Answer answer6 = createAnswerWithText("1,0,1"); + Answer answer7 = createAnswerWithText("1,1,0"); + Answer answer8 = createAnswerWithText("1,1,1"); + + assertEquals(0, q.calculateValue(answer1)); + assertEquals(10, q.calculateValue(answer2)); + assertEquals(-10, q.calculateValue(answer3)); + assertEquals(0, q.calculateValue(answer4)); + assertEquals(10, q.calculateValue(answer5)); + assertEquals(20, q.calculateValue(answer6)); + assertEquals(0, q.calculateValue(answer7)); + assertEquals(10, q.calculateValue(answer8)); + } + + @SuppressWarnings("serial") + @Test + public void shouldCalculatePictureQuestionAnswers() { + final PossibleAnswer p1 = new PossibleAnswer(); + p1.setText("0;0"); + p1.setCorrect(true); + p1.setValue(10); + final PossibleAnswer p2 = new PossibleAnswer(); + p2.setText("0;1"); + p2.setCorrect(false); + p2.setValue(-10); + final PossibleAnswer p3 = new PossibleAnswer(); + p3.setText("1;0"); + p3.setCorrect(true); + p3.setValue(10); + final PossibleAnswer p4 = new PossibleAnswer(); + p4.setText("1;1"); + p4.setCorrect(true); + p4.setValue(10); + Question q = new Question(); + q.setQuestionType("grid"); + q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ + add(p1); + add(p2); + add(p3); + add(p4); + }}); + Answer answer1 = createAnswerWithText("0;0"); + Answer answer2 = createAnswerWithText("0;1,1;1"); + Answer answer3 = createAnswerWithText("0;0,1;0,1;1"); + + assertEquals(10, q.calculateValue(answer1)); + assertEquals(0, q.calculateValue(answer2)); + assertEquals(30, q.calculateValue(answer3)); + } + + private static Answer createAnswerWithText(String text) { + Answer answer = new Answer(); + answer.setAnswerText(text); + return answer; + } +} -- GitLab