diff --git a/src/main/java/de/thm/arsnova/cache/CacheBuster.java b/src/main/java/de/thm/arsnova/cache/CacheBuster.java index ed38eab6b68e8ff966a138ecaab2d93fc929b6d6..c998bd4f30ddd4c69b9f6a0eaef4149e93e8fcb0 100644 --- a/src/main/java/de/thm/arsnova/cache/CacheBuster.java +++ b/src/main/java/de/thm/arsnova/cache/CacheBuster.java @@ -51,7 +51,7 @@ public class CacheBuster implements ICacheBuster, NovaEventVisitor { @Override public void visit(LockQuestionsEvent lockQuestionsEvent) { } - @CacheEvict(value = "answers", key = "#event.Question") + @CacheEvict(value = "answers", key = "#event.content") @Override public void visit(NewAnswerEvent event) { } diff --git a/src/main/java/de/thm/arsnova/config/AppConfig.java b/src/main/java/de/thm/arsnova/config/AppConfig.java index 146d4475093ab4f90d79dd64ccd0ad90becceb46..16db42433580ec2d1ced4da85b1cfc0954017d4a 100644 --- a/src/main/java/de/thm/arsnova/config/AppConfig.java +++ b/src/main/java/de/thm/arsnova/config/AppConfig.java @@ -27,16 +27,19 @@ import de.thm.arsnova.entities.Comment; import de.thm.arsnova.entities.DbUser; import de.thm.arsnova.entities.LogEntry; import de.thm.arsnova.entities.Motd; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.serialization.CouchDbDocumentModule; import de.thm.arsnova.entities.serialization.CouchDbObjectMapperFactory; import de.thm.arsnova.entities.serialization.View; import de.thm.arsnova.persistance.CommentRepository; +import de.thm.arsnova.persistance.ContentRepository; import de.thm.arsnova.persistance.LogEntryRepository; import de.thm.arsnova.persistance.MotdRepository; import de.thm.arsnova.persistance.SessionRepository; import de.thm.arsnova.persistance.UserRepository; import de.thm.arsnova.persistance.couchdb.CouchDbCommentRepository; +import de.thm.arsnova.persistance.couchdb.CouchDbContentRepository; import de.thm.arsnova.persistance.couchdb.CouchDbLogEntryRepository; import de.thm.arsnova.persistance.couchdb.CouchDbMotdRepository; import de.thm.arsnova.persistance.couchdb.CouchDbSessionRepository; @@ -300,6 +303,11 @@ public class AppConfig extends WebMvcConfigurerAdapter { return new CouchDbCommentRepository(Comment.class, couchDbConnector(), false); } + @Bean + public ContentRepository contentRepository() throws Exception { + return new CouchDbContentRepository(Content.class, couchDbConnector(), false); + } + @Bean public UserRepository userRepository() throws Exception { return new CouchDbUserRepository(DbUser.class, couchDbConnector(), false); diff --git a/src/main/java/de/thm/arsnova/controller/CommentController.java b/src/main/java/de/thm/arsnova/controller/CommentController.java index 57beb79d660391c67422fb70b1cdff14724416e1..e38c98630f2406217bcdc5f0c532f86db677b36c 100644 --- a/src/main/java/de/thm/arsnova/controller/CommentController.java +++ b/src/main/java/de/thm/arsnova/controller/CommentController.java @@ -20,7 +20,7 @@ package de.thm.arsnova.controller; import de.thm.arsnova.entities.CommentReadingCount; import de.thm.arsnova.entities.transport.Comment; import de.thm.arsnova.exceptions.BadRequestException; -import de.thm.arsnova.services.IQuestionService; +import de.thm.arsnova.services.IContentService; import de.thm.arsnova.web.DeprecatedApi; import de.thm.arsnova.web.Pagination; import io.swagger.annotations.Api; @@ -45,11 +45,11 @@ import java.util.List; */ @RestController @RequestMapping("/audiencequestion") -@Api(value = "/audiencequestion", description = "the Audience Question API") +@Api(value = "/audiencequestion", description = "the Audience Content API") public class CommentController extends PaginationController { @Autowired - private IQuestionService questionService; + private IContentService contentService; @ApiOperation(value = "Count all the comments in current session", nickname = "getAudienceQuestionCount") @@ -57,7 +57,7 @@ public class CommentController extends PaginationController { @DeprecatedApi @Deprecated public int getInterposedCount(@ApiParam(value = "Session-Key from current session", required = true) @RequestParam final String sessionkey) { - return questionService.getInterposedCount(sessionkey); + return contentService.getInterposedCount(sessionkey); } @ApiOperation(value = "count all unread comments", @@ -66,7 +66,7 @@ public class CommentController extends PaginationController { @DeprecatedApi @Deprecated public CommentReadingCount getUnreadInterposedCount(@ApiParam(value = "Session-Key from current session", required = true) @RequestParam("sessionkey") final String sessionkey, String user) { - return questionService.getInterposedReadingCount(sessionkey, user); + return contentService.getInterposedReadingCount(sessionkey, user); } @ApiOperation(value = "Retrieves all Comments for a Session", @@ -74,14 +74,14 @@ public class CommentController extends PaginationController { @RequestMapping(value = "/", method = RequestMethod.GET) @Pagination public List<Comment> getInterposedQuestions(@ApiParam(value = "Session-Key from current session", required = true) @RequestParam final String sessionkey) { - return Comment.fromList(questionService.getInterposedQuestions(sessionkey, offset, limit)); + return Comment.fromList(contentService.getInterposedQuestions(sessionkey, offset, limit)); } @ApiOperation(value = "Retrieves an Comment", nickname = "getInterposedQuestion") @RequestMapping(value = "/{questionId}", method = RequestMethod.GET) public Comment getInterposedQuestion(@ApiParam(value = "ID of the Comment that needs to be deleted", required = true) @PathVariable final String questionId) { - return new Comment(questionService.readInterposedQuestion(questionId)); + return new Comment(contentService.readInterposedQuestion(questionId)); } @ApiOperation(value = "Creates a new Comment for a Session and returns the Comment's data", @@ -95,7 +95,7 @@ public class CommentController extends PaginationController { @ApiParam(value = "Session-Key from current session", required = true) @RequestParam final String sessionkey, @ApiParam(value = "the body from the new comment", required = true) @RequestBody final de.thm.arsnova.entities.Comment comment ) { - if (questionService.saveQuestion(comment)) { + if (contentService.saveQuestion(comment)) { return; } @@ -106,6 +106,6 @@ public class CommentController extends PaginationController { nickname = "deleteInterposedQuestion") @RequestMapping(value = "/{questionId}", method = RequestMethod.DELETE) public void deleteInterposedQuestion(@ApiParam(value = "ID of the comment that needs to be deleted", required = true) @PathVariable final String questionId) { - questionService.deleteInterposedQuestion(questionId); + contentService.deleteInterposedQuestion(questionId); } } diff --git a/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java b/src/main/java/de/thm/arsnova/controller/ContentController.java similarity index 76% rename from src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java rename to src/main/java/de/thm/arsnova/controller/ContentController.java index 85ee7c9c57380a1bd5dd757c4d97c5c440c527fd..9695d365164c78e6bff74e820cd1d12da6c4dd3d 100644 --- a/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java +++ b/src/main/java/de/thm/arsnova/controller/ContentController.java @@ -19,12 +19,12 @@ package de.thm.arsnova.controller; import de.thm.arsnova.PaginationListDecorator; import de.thm.arsnova.entities.Answer; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.exceptions.BadRequestException; import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NotFoundException; -import de.thm.arsnova.services.IQuestionService; +import de.thm.arsnova.services.IContentService; import de.thm.arsnova.web.DeprecatedApi; import de.thm.arsnova.web.Pagination; import io.swagger.annotations.Api; @@ -52,9 +52,9 @@ import java.util.List; @RestController @RequestMapping("/lecturerquestion") @Api(value = "/lecturerquestion", description = "Operations for Lecture Questions") -public class LecturerQuestionController extends PaginationController { +public class ContentController extends PaginationController { @Autowired - private IQuestionService questionService; + private IContentService contentService; @ApiOperation(value = "Get question with provided question Id", nickname = "getQuestion") @@ -62,56 +62,56 @@ public class LecturerQuestionController extends PaginationController { @ApiResponse(code = 404, message = HTML_STATUS_404) }) @RequestMapping(value = "/{questionId}", method = RequestMethod.GET) - public Question getQuestion(@PathVariable final String questionId) { - final Question question = questionService.getQuestion(questionId); - if (question != null) { - return question; + public Content getQuestion(@PathVariable final String questionId) { + final Content content = contentService.getQuestion(questionId); + if (content != null) { + return content; } throw new NotFoundException(); } - @ApiOperation(value = "Post provided question", + @ApiOperation(value = "Post provided content", nickname = "postQuestion") @ApiResponses(value = { @ApiResponse(code = 400, message = HTML_STATUS_400) }) @RequestMapping(value = "/", method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) - public Question postQuestion(@RequestBody final Question question) { - if (questionService.saveQuestion(question) != null) { - return question; + public Content postQuestion(@RequestBody final Content content) { + if (contentService.saveQuestion(content) != null) { + return content; } throw new BadRequestException(); } - @ApiOperation(value = "Post provided questions", nickname = "bulkPostQuestions") + @ApiOperation(value = "Post provided contents", nickname = "bulkPostQuestions") @ApiResponses(value = { @ApiResponse(code = 400, message = HTML_STATUS_400) }) @RequestMapping(value = "/bulk", method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) - public List<Question> bulkPostQuestions(@RequestBody final List<Question> questions) { - for (final Question question : questions) { - if (questionService.saveQuestion(question) == null) { + public List<Content> bulkPostQuestions(@RequestBody final List<Content> contents) { + for (final Content content : contents) { + if (contentService.saveQuestion(content) == null) { throw new BadRequestException(); } } - return questions; + return contents; } - @ApiOperation(value = "Update the question, identified by provided id, with the provided question in the Request Body", + @ApiOperation(value = "Update the content, identified by provided id, with the provided content in the Request Body", nickname = "updateQuestion") @ApiResponses(value = { @ApiResponse(code = 400, message = HTML_STATUS_400) }) @RequestMapping(value = "/{questionId}", method = RequestMethod.PUT) - public Question updateQuestion( + public Content updateQuestion( @PathVariable final String questionId, - @RequestBody final Question question + @RequestBody final Content content ) { try { - return questionService.update(question); + return contentService.update(content); } catch (final Exception e) { throw new BadRequestException(); } @@ -126,9 +126,9 @@ public class LecturerQuestionController extends PaginationController { ) { if (fcImage) { - return questionService.getQuestionFcImage(questionId); + return contentService.getQuestionFcImage(questionId); } else { - return questionService.getQuestionImage(questionId); + return contentService.getQuestionImage(questionId); } } @@ -139,9 +139,9 @@ public class LecturerQuestionController extends PaginationController { ) { if (time == 0) { - questionService.startNewPiRound(questionId, null); + contentService.startNewPiRound(questionId, null); } else { - questionService.startNewPiRoundDelayed(questionId, time); + contentService.startNewPiRoundDelayed(questionId, time); } } @@ -151,7 +151,7 @@ public class LecturerQuestionController extends PaginationController { public void cancelPiRound( @PathVariable final String questionId ) { - questionService.cancelPiRoundChange(questionId); + contentService.cancelPiRoundChange(questionId); } @RequestMapping(value = "/{questionId}/resetpiroundstate", method = RequestMethod.POST) @@ -160,7 +160,7 @@ public class LecturerQuestionController extends PaginationController { public void resetPiQuestion( @PathVariable final String questionId ) { - questionService.resetPiRoundState(questionId); + contentService.resetPiRoundState(questionId); } @ApiOperation(value = "Set voting admission on question, identified by provided id", @@ -176,7 +176,7 @@ public class LecturerQuestionController extends PaginationController { disable = disableVote; } - questionService.setVotingAdmission(questionId, disable); + contentService.setVotingAdmission(questionId, disable); } @ApiOperation(value = "Set voting admission for all questions", @@ -189,35 +189,35 @@ public class LecturerQuestionController extends PaginationController { @RequestParam(value = "preparationquestionsonly", defaultValue = "false", required = false) final boolean preparationQuestionsOnly ) { boolean disable = false; - List<Question> questions; + List<Content> contents; if (disableVote != null) { disable = disableVote; } if (lectureQuestionsOnly) { - questions = questionService.getLectureQuestions(sessionkey); - questionService.setVotingAdmissions(sessionkey, disable, questions); + contents = contentService.getLectureQuestions(sessionkey); + contentService.setVotingAdmissions(sessionkey, disable, contents); } else if (preparationQuestionsOnly) { - questions = questionService.getPreparationQuestions(sessionkey); - questionService.setVotingAdmissions(sessionkey, disable, questions); + contents = contentService.getPreparationQuestions(sessionkey); + contentService.setVotingAdmissions(sessionkey, disable, contents); } else { - questionService.setVotingAdmissionForAllQuestions(sessionkey, disable); + contentService.setVotingAdmissionForAllQuestions(sessionkey, disable); } } - @ApiOperation(value = "Publish a question, identified by provided id and question in Request Body.", + @ApiOperation(value = "Publish a content, identified by provided id and content in Request Body.", nickname = "publishQuestion") @RequestMapping(value = "/{questionId}/publish", method = RequestMethod.POST) public void publishQuestion( @PathVariable final String questionId, @RequestParam(required = false) final Boolean publish, - @RequestBody final Question question + @RequestBody final Content content ) { if (publish != null) { - question.setActive(publish); + content.setActive(publish); } - questionService.update(question); + contentService.update(content); } @ApiOperation(value = "Publish all questions", @@ -230,52 +230,52 @@ public class LecturerQuestionController extends PaginationController { @RequestParam(value = "preparationquestionsonly", defaultValue = "false", required = false) final boolean preparationQuestionsOnly ) { boolean p = publish == null || publish; - List<Question> questions; + List<Content> contents; if (lectureQuestionsOnly) { - questions = questionService.getLectureQuestions(sessionkey); - questionService.publishQuestions(sessionkey, p, questions); + contents = contentService.getLectureQuestions(sessionkey); + contentService.publishQuestions(sessionkey, p, contents); } else if (preparationQuestionsOnly) { - questions = questionService.getPreparationQuestions(sessionkey); - questionService.publishQuestions(sessionkey, p, questions); + contents = contentService.getPreparationQuestions(sessionkey); + contentService.publishQuestions(sessionkey, p, contents); } else { - questionService.publishAll(sessionkey, p); + contentService.publishAll(sessionkey, p); } } - @ApiOperation(value = "Publish statistics from question with provided id", + @ApiOperation(value = "Publish statistics from content with provided id", nickname = "publishStatistics") @RequestMapping(value = "/{questionId}/publishstatistics", method = RequestMethod.POST) public void publishStatistics( @PathVariable final String questionId, @RequestParam(required = false) final Boolean showStatistics, - @RequestBody final Question question + @RequestBody final Content content ) { if (showStatistics != null) { - question.setShowStatistic(showStatistics); + content.setShowStatistic(showStatistics); } - questionService.update(question); + contentService.update(content); } - @ApiOperation(value = "Publish correct answer from question with provided id", + @ApiOperation(value = "Publish correct answer from content with provided id", nickname = "publishCorrectAnswer") @RequestMapping(value = "/{questionId}/publishcorrectanswer", method = RequestMethod.POST) public void publishCorrectAnswer( @PathVariable final String questionId, @RequestParam(required = false) final Boolean showCorrectAnswer, - @RequestBody final Question question + @RequestBody final Content content ) { if (showCorrectAnswer != null) { - question.setShowAnswer(showCorrectAnswer); + content.setShowAnswer(showCorrectAnswer); } - questionService.update(question); + contentService.update(content); } @ApiOperation(value = "Get skill questions", nickname = "getSkillQuestions") @RequestMapping(value = "/", method = RequestMethod.GET) @Pagination - public List<Question> getSkillQuestions( + public List<Content> getSkillQuestions( @RequestParam final String sessionkey, @RequestParam(value = "lecturequestionsonly", defaultValue = "false") final boolean lectureQuestionsOnly, @RequestParam(value = "flashcardsonly", defaultValue = "false") final boolean flashcardsOnly, @@ -283,24 +283,24 @@ public class LecturerQuestionController extends PaginationController { @RequestParam(value = "requestImageData", defaultValue = "false") final boolean requestImageData, final HttpServletResponse response ) { - List<Question> questions; + List<Content> contents; if (lectureQuestionsOnly) { - questions = questionService.getLectureQuestions(sessionkey); + contents = contentService.getLectureQuestions(sessionkey); } else if (flashcardsOnly) { - questions = questionService.getFlashcards(sessionkey); + contents = contentService.getFlashcards(sessionkey); } else if (preparationQuestionsOnly) { - questions = questionService.getPreparationQuestions(sessionkey); + contents = contentService.getPreparationQuestions(sessionkey); } else { - questions = questionService.getSkillQuestions(sessionkey); + contents = contentService.getSkillQuestions(sessionkey); } - if (questions == null || questions.isEmpty()) { + if (contents == null || contents.isEmpty()) { response.setStatus(HttpStatus.NO_CONTENT.value()); return null; } else if (!requestImageData) { - questions = questionService.replaceImageData(questions); + contents = contentService.replaceImageData(contents); } - return new PaginationListDecorator<>(questions, offset, limit); + return new PaginationListDecorator<>(contents, offset, limit); } @ApiOperation(value = "Delete skill questions", @@ -314,13 +314,13 @@ public class LecturerQuestionController extends PaginationController { final HttpServletResponse response ) { if (lectureQuestionsOnly) { - questionService.deleteLectureQuestions(sessionkey); + contentService.deleteLectureQuestions(sessionkey); } else if (flashcardsOnly) { - questionService.deleteFlashcards(sessionkey); + contentService.deleteFlashcards(sessionkey); } else if (preparationQuestionsOnly) { - questionService.deletePreparationQuestions(sessionkey); + contentService.deletePreparationQuestions(sessionkey); } else { - questionService.deleteAllQuestions(sessionkey); + contentService.deleteAllQuestions(sessionkey); } } @@ -336,13 +336,13 @@ public class LecturerQuestionController extends PaginationController { @RequestParam(value = "preparationquestionsonly", defaultValue = "false") final boolean preparationQuestionsOnly ) { if (lectureQuestionsOnly) { - return questionService.getLectureQuestionCount(sessionkey); + return contentService.getLectureQuestionCount(sessionkey); } else if (flashcardsOnly) { - return questionService.getFlashcardCount(sessionkey); + return contentService.getFlashcardCount(sessionkey); } else if (preparationQuestionsOnly) { - return questionService.getPreparationQuestionCount(sessionkey); + return contentService.getPreparationQuestionCount(sessionkey); } else { - return questionService.getSkillQuestionCount(sessionkey); + return contentService.getSkillQuestionCount(sessionkey); } } @@ -352,7 +352,7 @@ public class LecturerQuestionController extends PaginationController { public void deleteAnswersAndQuestion( @PathVariable final String questionId ) { - questionService.deleteQuestion(questionId); + contentService.deleteQuestion(questionId); } @ApiOperation(value = "Get unanswered skill question ID by provided session ID", @@ -367,11 +367,11 @@ public class LecturerQuestionController extends PaginationController { ) { List<String> answers; if (lectureQuestionsOnly) { - answers = questionService.getUnAnsweredLectureQuestionIds(sessionkey); + answers = contentService.getUnAnsweredLectureQuestionIds(sessionkey); } else if (preparationQuestionsOnly) { - answers = questionService.getUnAnsweredPreparationQuestionIds(sessionkey); + answers = contentService.getUnAnsweredPreparationQuestionIds(sessionkey); } else { - answers = questionService.getUnAnsweredQuestionIds(sessionkey); + answers = contentService.getUnAnsweredQuestionIds(sessionkey); } if (answers == null || answers.isEmpty()) { throw new NoContentException(); @@ -384,7 +384,7 @@ public class LecturerQuestionController extends PaginationController { * returns a JSON document which represents the given answer of a question. * * @param questionId - * CouchDB Question ID for which the given answer should be + * CouchDB Content ID for which the given answer should be * retrieved * @return JSON Document of {@link Answer} or {@link NotFoundException} * @throws NotFoundException @@ -402,7 +402,7 @@ public class LecturerQuestionController extends PaginationController { @PathVariable final String questionId, final HttpServletResponse response ) { - final Answer answer = questionService.getMyAnswer(questionId); + final Answer answer = contentService.getMyAnswer(questionId); if (answer == null) { response.setStatus(HttpStatus.NO_CONTENT.value()); return null; @@ -418,7 +418,7 @@ public class LecturerQuestionController extends PaginationController { * properties are set * * @param questionId - * CouchDB Question ID for which the given answers should be + * CouchDB Content ID for which the given answers should be * retrieved * @throws NotFoundException * if wrong session, wrong question or no answers was given @@ -436,16 +436,16 @@ public class LecturerQuestionController extends PaginationController { ) { List<Answer> answers; if (allAnswers) { - answers = questionService.getAllAnswers(questionId, -1, -1); + answers = contentService.getAllAnswers(questionId, -1, -1); } else if (null == piRound) { - answers = questionService.getAnswers(questionId, offset, limit); + answers = contentService.getAnswers(questionId, offset, limit); } else { if (piRound < 1 || piRound > 2) { response.setStatus(HttpStatus.BAD_REQUEST.value()); return null; } - answers = questionService.getAnswers(questionId, piRound, offset, limit); + answers = contentService.getAnswers(questionId, piRound, offset, limit); } if (answers == null) { return new ArrayList<>(); @@ -461,7 +461,7 @@ public class LecturerQuestionController extends PaginationController { @RequestBody final de.thm.arsnova.entities.transport.Answer answer, final HttpServletResponse response ) { - return questionService.saveAnswer(questionId, answer); + return contentService.saveAnswer(questionId, answer); } @ApiOperation(value = "Update answer, provided in Request Body, identified by question ID and answer ID", @@ -473,7 +473,7 @@ public class LecturerQuestionController extends PaginationController { @RequestBody final Answer answer, final HttpServletResponse response ) { - return questionService.updateAnswer(answer); + return contentService.updateAnswer(answer); } @ApiOperation(value = "Get Image, identified by question ID and answer ID", @@ -485,7 +485,7 @@ public class LecturerQuestionController extends PaginationController { final HttpServletResponse response ) { - return questionService.getImage(questionId, answerId); + return contentService.getImage(questionId, answerId); } @ApiOperation(value = "Delete answer, identified by question ID and answer ID", @@ -496,7 +496,7 @@ public class LecturerQuestionController extends PaginationController { @PathVariable final String answerId, final HttpServletResponse response ) { - questionService.deleteAnswer(questionId, answerId); + contentService.deleteAnswer(questionId, answerId); } @ApiOperation(value = "Delete answers from a question, identified by question ID", @@ -506,7 +506,7 @@ public class LecturerQuestionController extends PaginationController { @PathVariable final String questionId, final HttpServletResponse response ) { - questionService.deleteAnswers(questionId); + contentService.deleteAnswers(questionId); } @ApiOperation(value = "Delete all answers and questions from a session, identified by sessionkey", @@ -519,18 +519,18 @@ public class LecturerQuestionController extends PaginationController { final HttpServletResponse response ) { if (lectureQuestionsOnly) { - questionService.deleteAllLectureAnswers(sessionkey); + contentService.deleteAllLectureAnswers(sessionkey); } else if (preparationQuestionsOnly) { - questionService.deleteAllPreparationAnswers(sessionkey); + contentService.deleteAllPreparationAnswers(sessionkey); } else { - questionService.deleteAllQuestionsAnswers(sessionkey); + contentService.deleteAllQuestionsAnswers(sessionkey); } } /** * * @param questionId - * CouchDB Question ID for which the given answers should be + * CouchDB Content ID for which the given answers should be * retrieved * @return count of answers for given question id * @throws NotFoundException @@ -544,7 +544,7 @@ public class LecturerQuestionController extends PaginationController { @Deprecated @RequestMapping(value = "/{questionId}/answercount", method = RequestMethod.GET) public int getAnswerCount(@PathVariable final String questionId) { - return questionService.getAnswerCount(questionId); + return contentService.getAnswerCount(questionId); } @ApiOperation(value = "Get the amount of answers for a question, identified by the question ID", @@ -552,8 +552,8 @@ public class LecturerQuestionController extends PaginationController { @RequestMapping(value = "/{questionId}/allroundanswercount", method = RequestMethod.GET) public List<Integer> getAllAnswerCount(@PathVariable final String questionId) { return Arrays.asList( - questionService.getAnswerCount(questionId, 1), - questionService.getAnswerCount(questionId, 2) + contentService.getAnswerCount(questionId, 1), + contentService.getAnswerCount(questionId, 2) ); } @@ -561,7 +561,7 @@ public class LecturerQuestionController extends PaginationController { nickname = "getTotalAnswerCountByQuestion") @RequestMapping(value = "/{questionId}/totalanswercount", method = RequestMethod.GET) public int getTotalAnswerCountByQuestion(@PathVariable final String questionId) { - return questionService.getTotalAnswerCountByQuestion(questionId); + return contentService.getTotalAnswerCountByQuestion(questionId); } @ApiOperation(value = "Get the amount of answers and abstention answers by a question, identified by the question ID", @@ -569,8 +569,8 @@ public class LecturerQuestionController extends PaginationController { @RequestMapping(value = "/{questionId}/answerandabstentioncount", method = RequestMethod.GET) public List<Integer> getAnswerAndAbstentionCount(@PathVariable final String questionId) { return Arrays.asList( - questionService.getAnswerCount(questionId), - questionService.getAbstentionAnswerCount(questionId) + contentService.getAnswerCount(questionId), + contentService.getAbstentionAnswerCount(questionId) ); } @@ -579,7 +579,7 @@ public class LecturerQuestionController extends PaginationController { @RequestMapping(value = "/{questionId}/freetextanswer/", method = RequestMethod.GET) @Pagination public List<Answer> getFreetextAnswers(@PathVariable final String questionId) { - return questionService.getFreetextAnswers(questionId, offset, limit); + return contentService.getFreetextAnswers(questionId, offset, limit); } @ApiOperation(value = "Get my answers of an session, identified by the sessionkey", @@ -588,7 +588,7 @@ public class LecturerQuestionController extends PaginationController { @Deprecated @RequestMapping(value = "/myanswers", method = RequestMethod.GET) public List<Answer> getMyAnswers(@RequestParam final String sessionkey) { - return questionService.getMyAnswers(sessionkey); + return contentService.getMyAnswers(sessionkey); } @ApiOperation(value = "Get the total amount of answers of an session, identified by the sessionkey", @@ -602,11 +602,11 @@ public class LecturerQuestionController extends PaginationController { @RequestParam(value = "preparationquestionsonly", defaultValue = "false") final boolean preparationQuestionsOnly ) { if (lectureQuestionsOnly) { - return questionService.countLectureQuestionAnswers(sessionkey); + return contentService.countLectureQuestionAnswers(sessionkey); } else if (preparationQuestionsOnly) { - return questionService.countPreparationQuestionAnswers(sessionkey); + return contentService.countPreparationQuestionAnswers(sessionkey); } else { - return questionService.getTotalAnswerCount(sessionkey); + return contentService.getTotalAnswerCount(sessionkey); } } } diff --git a/src/main/java/de/thm/arsnova/controller/LegacyController.java b/src/main/java/de/thm/arsnova/controller/LegacyController.java index c9f809c63b73415f788860754cec0716d9c2be90..a1d3a9de2a3ff25df4bba88b735f4e46853a8a94 100644 --- a/src/main/java/de/thm/arsnova/controller/LegacyController.java +++ b/src/main/java/de/thm/arsnova/controller/LegacyController.java @@ -17,7 +17,7 @@ */ package de.thm.arsnova.controller; -import de.thm.arsnova.services.IQuestionService; +import de.thm.arsnova.services.IContentService; import de.thm.arsnova.web.DeprecatedApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @@ -33,7 +33,7 @@ import org.springframework.web.bind.annotation.ResponseBody; public class LegacyController extends AbstractController { @Autowired - private IQuestionService questionService; + private IContentService contentService; /* specific routes */ @@ -95,7 +95,7 @@ public class LegacyController extends AbstractController { @RequestMapping(value = "/session/{sessionKey}/interposed", method = RequestMethod.DELETE) @ResponseBody public void deleteAllInterposedQuestions(@PathVariable final String sessionKey) { - questionService.deleteAllInterposedQuestions(sessionKey); + contentService.deleteAllInterposedQuestions(sessionKey); } @DeprecatedApi diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index d45937950f55097b128c3893eaca7aeca9ab8127..72ff1ff4fcd1d3ba34af724462c45112e8cc77fc 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -19,8 +19,6 @@ package de.thm.arsnova.dao; import com.fourspaces.couchdb.Database; import com.fourspaces.couchdb.Document; -import com.fourspaces.couchdb.Results; -import com.fourspaces.couchdb.RowResult; import com.fourspaces.couchdb.View; import com.fourspaces.couchdb.ViewResults; import com.google.common.collect.Lists; @@ -30,16 +28,13 @@ import de.thm.arsnova.entities.*; import de.thm.arsnova.entities.transport.AnswerQueueElement; import de.thm.arsnova.events.NewAnswerEvent; import de.thm.arsnova.exceptions.NotFoundException; +import de.thm.arsnova.persistance.ContentRepository; import de.thm.arsnova.persistance.LogEntryRepository; import de.thm.arsnova.persistance.MotdRepository; import de.thm.arsnova.persistance.SessionRepository; import de.thm.arsnova.services.ISessionService; -import net.sf.ezmorph.Morpher; -import net.sf.ezmorph.MorpherRegistry; -import net.sf.ezmorph.bean.BeanMorpher; import net.sf.json.JSONArray; import net.sf.json.JSONObject; -import net.sf.json.util.JSONUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +44,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.annotation.Profile; @@ -59,7 +53,6 @@ import org.springframework.stereotype.Service; import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -75,7 +68,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; * * This class makes use of Spring Framework's caching annotations. When you are about to add new functionality, * you should also think about the possibility of caching. Ideally, your methods should be dependent on domain - * objects like Session or Question, which can be used as cache keys. Relying on plain String objects as a key, e.g. + * objects like Session or Content, which can be used as cache keys. Relying on plain String objects as a key, e.g. * by passing only a Session's keyword, will make your cache annotations less readable. You will also need to think * about cases where your cache needs to be updated and evicted. * @@ -104,6 +97,9 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @Autowired private MotdRepository motdRepository; + @Autowired + private ContentRepository contentRepository; + private String databaseHost; private int databasePort; private String databaseName; @@ -151,46 +147,6 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware this.publisher = publisher; } - @Cacheable("skillquestions") - @Override - public List<Question> getSkillQuestionsForUsers(final Session session) { - final List<Question> questions = new ArrayList<>(); - final String viewName = "content/doc_by_sessionid_variant_active"; - final View view1 = new View(viewName); - final View view2 = new View(viewName); - final View view3 = new View(viewName); - view1.setStartKey(session.getId(), "lecture", true); - view1.setEndKey(session.getId(), "lecture", true, "{}"); - view2.setStartKey(session.getId(), "preparation", true); - view2.setEndKey(session.getId(), "preparation", true, "{}"); - view3.setStartKey(session.getId(), "flashcard", true); - view3.setEndKey(session.getId(), "flashcard", true, "{}"); - questions.addAll(getQuestions(view1, session)); - questions.addAll(getQuestions(view2, session)); - questions.addAll(getQuestions(view3, session)); - - return questions; - } - - @Cacheable("skillquestions") - @Override - public List<Question> getSkillQuestionsForTeachers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKey(session.getId()); - view.setEndKey(session.getId(), "{}"); - - return getQuestions(view, session); - } - - @Override - public int getSkillQuestionCount(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKey(session.getId()); - view.setEndKey(session.getId(), "{}"); - - return getQuestionCount(view); - } - private Database getDatabase() { if (database == null) { try { @@ -208,240 +164,6 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return database; } - @Caching(evict = {@CacheEvict(value = "skillquestions", key = "#session"), - @CacheEvict(value = "lecturequestions", key = "#session", condition = "#question.getQuestionVariant().equals('lecture')"), - @CacheEvict(value = "preparationquestions", key = "#session", condition = "#question.getQuestionVariant().equals('preparation')"), - @CacheEvict(value = "flashcardquestions", key = "#session", condition = "#question.getQuestionVariant().equals('flashcard')") }, - put = {@CachePut(value = "questions", key = "#question._id")}) - @Override - public Question saveQuestion(final Session session, final Question question) { - final Document q = toQuestionDocument(session, question); - try { - database.saveDocument(q); - question.set_id(q.getId()); - question.set_rev(q.getRev()); - return question; - } catch (final IOException e) { - logger.error("Could not save question {}.", question, e); - } - return null; - } - - private Document toQuestionDocument(final Session session, final Question question) { - Document q = new Document(); - - question.updateRoundManagementState(); - q.put("type", "skill_question"); - q.put("questionType", question.getQuestionType()); - q.put("ignoreCaseSensitive", question.isIgnoreCaseSensitive()); - q.put("ignoreWhitespaces", question.isIgnoreWhitespaces()); - q.put("ignorePunctuation", question.isIgnorePunctuation()); - q.put("fixedAnswer", question.isFixedAnswer()); - q.put("strictMode", question.isStrictMode()); - q.put("rating", question.getRating()); - q.put("correctAnswer", question.getCorrectAnswer()); - q.put("questionVariant", question.getQuestionVariant()); - q.put("sessionId", session.getId()); - q.put("subject", question.getSubject()); - q.put("text", question.getText()); - q.put("active", question.isActive()); - q.put("votingDisabled", question.isVotingDisabled()); - q.put("number", 0); // TODO: This number is now unused. A clean up is necessary. - q.put("releasedFor", question.getReleasedFor()); - q.put("possibleAnswers", question.getPossibleAnswers()); - q.put("noCorrect", question.isNoCorrect()); - q.put("piRound", question.getPiRound()); - q.put("piRoundStartTime", question.getPiRoundStartTime()); - q.put("piRoundEndTime", question.getPiRoundEndTime()); - q.put("piRoundFinished", question.isPiRoundFinished()); - q.put("piRoundActive", question.isPiRoundActive()); - q.put("showStatistic", question.isShowStatistic()); - q.put("showAnswer", question.isShowAnswer()); - q.put("abstention", question.isAbstention()); - q.put("image", question.getImage()); - q.put("fcImage", question.getFcImage()); - q.put("gridSize", question.getGridSize()); - q.put("offsetX", question.getOffsetX()); - q.put("offsetY", question.getOffsetY()); - q.put("zoomLvl", question.getZoomLvl()); - q.put("gridOffsetX", question.getGridOffsetX()); - q.put("gridOffsetY", question.getGridOffsetY()); - q.put("gridZoomLvl", question.getGridZoomLvl()); - q.put("gridSizeX", question.getGridSizeX()); - q.put("gridSizeY", question.getGridSizeY()); - q.put("gridIsHidden", question.getGridIsHidden()); - q.put("imgRotation", question.getImgRotation()); - q.put("toggleFieldsLeft", question.getToggleFieldsLeft()); - q.put("numClickableFields", question.getNumClickableFields()); - q.put("thresholdCorrectAnswers", question.getThresholdCorrectAnswers()); - q.put("cvIsColored", question.getCvIsColored()); - q.put("gridLineColor", question.getGridLineColor()); - q.put("numberOfDots", question.getNumberOfDots()); - q.put("gridType", question.getGridType()); - q.put("scaleFactor", question.getScaleFactor()); - q.put("gridScaleFactor", question.getGridScaleFactor()); - q.put("imageQuestion", question.isImageQuestion()); - q.put("textAnswerEnabled", question.isTextAnswerEnabled()); - q.put("timestamp", question.getTimestamp()); - q.put("hint", question.getHint()); - q.put("solution", question.getSolution()); - return q; - } - - /* TODO: Only evict cache entry for the question's session. This requires some refactoring. */ - @Caching(evict = {@CacheEvict(value = "skillquestions", allEntries = true), - @CacheEvict(value = "lecturequestions", allEntries = true, condition = "#question.getQuestionVariant().equals('lecture')"), - @CacheEvict(value = "preparationquestions", allEntries = true, condition = "#question.getQuestionVariant().equals('preparation')"), - @CacheEvict(value = "flashcardquestions", allEntries = true, condition = "#question.getQuestionVariant().equals('flashcard')") }, - put = {@CachePut(value = "questions", key = "#question._id")}) - @Override - public Question updateQuestion(final Question question) { - try { - final Document q = database.getDocument(question.get_id()); - - question.updateRoundManagementState(); - q.put("subject", question.getSubject()); - q.put("text", question.getText()); - q.put("active", question.isActive()); - q.put("votingDisabled", question.isVotingDisabled()); - q.put("releasedFor", question.getReleasedFor()); - q.put("possibleAnswers", question.getPossibleAnswers()); - q.put("noCorrect", question.isNoCorrect()); - q.put("piRound", question.getPiRound()); - q.put("piRoundStartTime", question.getPiRoundStartTime()); - q.put("piRoundEndTime", question.getPiRoundEndTime()); - q.put("piRoundFinished", question.isPiRoundFinished()); - q.put("piRoundActive", question.isPiRoundActive()); - q.put("showStatistic", question.isShowStatistic()); - q.put("ignoreCaseSensitive", question.isIgnoreCaseSensitive()); - q.put("ignoreWhitespaces", question.isIgnoreWhitespaces()); - q.put("ignorePunctuation", question.isIgnorePunctuation()); - q.put("fixedAnswer", question.isFixedAnswer()); - q.put("strictMode", question.isStrictMode()); - q.put("rating", question.getRating()); - q.put("correctAnswer", question.getCorrectAnswer()); - q.put("showAnswer", question.isShowAnswer()); - q.put("abstention", question.isAbstention()); - q.put("image", question.getImage()); - q.put("fcImage", question.getFcImage()); - q.put("gridSize", question.getGridSize()); - q.put("offsetX", question.getOffsetX()); - q.put("offsetY", question.getOffsetY()); - q.put("zoomLvl", question.getZoomLvl()); - q.put("gridOffsetX", question.getGridOffsetX()); - q.put("gridOffsetY", question.getGridOffsetY()); - q.put("gridZoomLvl", question.getGridZoomLvl()); - q.put("gridSizeX", question.getGridSizeX()); - q.put("gridSizeY", question.getGridSizeY()); - q.put("gridIsHidden", question.getGridIsHidden()); - q.put("imgRotation", question.getImgRotation()); - q.put("toggleFieldsLeft", question.getToggleFieldsLeft()); - q.put("numClickableFields", question.getNumClickableFields()); - q.put("thresholdCorrectAnswers", question.getThresholdCorrectAnswers()); - q.put("cvIsColored", question.getCvIsColored()); - q.put("gridLineColor", question.getGridLineColor()); - q.put("numberOfDots", question.getNumberOfDots()); - q.put("gridType", question.getGridType()); - q.put("scaleFactor", question.getScaleFactor()); - q.put("gridScaleFactor", question.getGridScaleFactor()); - q.put("imageQuestion", question.isImageQuestion()); - q.put("hint", question.getHint()); - q.put("solution", question.getSolution()); - - database.saveDocument(q); - question.set_rev(q.getRev()); - - return question; - } catch (final IOException e) { - logger.error("Could not update question {}.", question, e); - } - - return null; - } - - @Cacheable("questions") - @Override - public Question getQuestion(final String id) { - try { - final Document q = getDatabase().getDocument(id); - if (q == null) { - return null; - } - final Question question = (Question) JSONObject.toBean(q.getJSONObject(), Question.class); - final JSONArray possibleAnswers = q.getJSONObject().getJSONArray("possibleAnswers"); - @SuppressWarnings("unchecked") - final Collection<PossibleAnswer> answers = JSONArray.toCollection(possibleAnswers, PossibleAnswer.class); - - question.updateRoundManagementState(); - question.setPossibleAnswers(new ArrayList<>(answers)); - question.setSessionKeyword(sessionRepository.getSessionFromId(question.getSessionId()).getKeyword()); - return question; - } catch (final IOException e) { - logger.error("Could not get question {}.", id, e); - } - return null; - } - - @Override - public List<String> getQuestionIds(final Session session, final User user) { - View view = new View("content/by_sessionid_variant_active"); - view.setKey(session.getId()); - return collectQuestionIds(view); - } - - /* TODO: Only evict cache entry for the question's session. This requires some refactoring. */ - @Caching(evict = { @CacheEvict(value = "questions", key = "#question._id"), - @CacheEvict(value = "skillquestions", allEntries = true), - @CacheEvict(value = "lecturequestions", allEntries = true, condition = "#question.getQuestionVariant().equals('lecture')"), - @CacheEvict(value = "preparationquestions", allEntries = true, condition = "#question.getQuestionVariant().equals('preparation')"), - @CacheEvict(value = "flashcardquestions", allEntries = true, condition = "#question.getQuestionVariant().equals('flashcard')") }) - @Override - public int deleteQuestionWithAnswers(final Question question) { - try { - int count = deleteAnswers(question); - deleteDocument(question.get_id()); - dbLogger.log("delete", "type", "question", "answerCount", count); - - return count; - } catch (final IOException e) { - logger.error("Could not delete question {}.", question.get_id(), e); - } - - return 0; - } - - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict(value = "skillquestions", key = "#session"), - @CacheEvict(value = "lecturequestions", key = "#session"), - @CacheEvict(value = "preparationquestions", key = "#session"), - @CacheEvict(value = "flashcardquestions", key = "#session") }) - @Override - public int[] deleteAllQuestionsWithAnswers(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId()); - view.setEndKey(session.getId(), "{}"); - - return deleteAllQuestionDocumentsWithAnswers(view); - } - - private int[] deleteAllQuestionDocumentsWithAnswers(final View view) { - final ViewResults results = getDatabase().view(view); - - List<Question> questions = new ArrayList<>(); - for (final Document d : results.getResults()) { - final Question q = new Question(); - q.set_id(d.getId()); - q.set_rev(d.getString("value")); - questions.add(q); - } - - int[] count = deleteAllAnswersWithQuestions(questions); - dbLogger.log("delete", "type", "question", "questionCount", count[0]); - dbLogger.log("delete", "type", "answer", "answerCount", count[1]); - - return count; - } - private void deleteDocument(final String documentId) throws IOException { final Document d = getDatabase().getDocument(documentId); getDatabase().deleteDocument(d); @@ -449,10 +171,10 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @CacheEvict("answers") @Override - public int deleteAnswers(final Question question) { + public int deleteAnswers(final Content content) { try { final View view = new View("answer/by_questionid"); - view.setKey(question.get_id()); + view.setKey(content.getId()); view.setIncludeDocs(true); final ViewResults results = getDatabase().view(view); final List<List<Document>> partitions = Lists.partition(results.getResults(), BULK_PARTITION_SIZE); @@ -475,20 +197,12 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return count; } catch (final IOException e) { - logger.error("Could not delete answers for question {}.", question.get_id(), e); + logger.error("Could not delete answers for content {}.", content.getId(), e); } return 0; } - @Override - public List<String> getUnAnsweredQuestionIds(final Session session, final User user) { - final View view = new View("answer/questionid_by_user_sessionid_variant"); - view.setStartKeyArray(user.getUsername(), session.getId()); - view.setEndKeyArray(user.getUsername(), session.getId(), "{}"); - return collectUnansweredQuestionIds(getQuestionIds(session, user), view); - } - @Override public Answer getMyAnswer(final User me, final String questionId, final int piRound) { @@ -526,8 +240,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<Answer> getAnswers(final Question question, final int piRound) { - final String questionId = question.get_id(); + public List<Answer> getAnswers(final Content content, final int piRound) { + final String questionId = content.getId(); final View view = new View("answer/by_questionid_piround_text_subject"); if (2 == piRound) { view.setStartKey(questionId, 2); @@ -556,8 +270,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<Answer> getAllAnswers(final Question question) { - final String questionId = question.get_id(); + public List<Answer> getAllAnswers(final Content content) { + final String questionId = content.getId(); final View view = new View("answer/by_questionid_piround_text_subject"); view.setStartKeyArray(questionId); view.setEndKeyArray(questionId, "{}"); @@ -584,8 +298,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @Cacheable("answers") @Override - public List<Answer> getAnswers(final Question question) { - return this.getAnswers(question, question.getPiRound()); + public List<Answer> getAnswers(final Content content) { + return this.getAnswers(content, content.getPiRound()); } @Override @@ -602,10 +316,10 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public int getAnswerCount(final Question question, final int piRound) { + public int getAnswerCount(final Content content, final int piRound) { final View view = new View("answer/by_questionid_piround_text_subject"); - view.setStartKey(question.get_id(), piRound); - view.setEndKey(question.get_id(), piRound, "{}"); + view.setStartKey(content.getId(), piRound); + view.setEndKey(content.getId(), piRound, "{}"); view.setGroup(true); final ViewResults results = getDatabase().view(view); if (results.getResults().isEmpty()) { @@ -616,10 +330,10 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public int getTotalAnswerCountByQuestion(final Question question) { + public int getTotalAnswerCountByQuestion(final Content content) { final View view = new View("answer/by_questionid_piround_text_subject"); - view.setStartKeyArray(question.get_id()); - view.setEndKeyArray(question.get_id(), "{}"); + view.setStartKeyArray(content.getId()); + view.setEndKeyArray(content.getId(), "{}"); view.setGroup(true); final ViewResults results = getDatabase().view(view); @@ -773,9 +487,9 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return stats; } - @CacheEvict(value = "answers", key = "#question") + @CacheEvict(value = "answers", key = "#content") @Override - public Answer saveAnswer(final Answer answer, final User user, final Question question, final Session session) { + public Answer saveAnswer(final Answer answer, final User user, final Content content, final Session session) { final Document a = new Document(); a.put("type", "skill_question_answer"); a.put("sessionId", answer.getSessionId()); @@ -792,7 +506,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware a.put("abstention", answer.isAbstention()); a.put("answerImage", answer.getAnswerImage()); a.put("answerThumbnailImage", answer.getAnswerThumbnailImage()); - AnswerQueueElement answerQueueElement = new AnswerQueueElement(session, question, answer, user); + AnswerQueueElement answerQueueElement = new AnswerQueueElement(session, content, answer, user); this.answerQueue.offer(new AbstractMap.SimpleEntry<>(a, answerQueueElement)); return answer; } @@ -937,131 +651,6 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return 0; } - @Cacheable("lecturequestions") - @Override - public List<Question> getLectureQuestionsForUsers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "lecture", true); - view.setEndKeyArray(session.getId(), "lecture", true, "{}"); - - return getQuestions(view, session); - } - - @Override - public List<Question> getLectureQuestionsForTeachers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "lecture"); - view.setEndKeyArray(session.getId(), "lecture", "{}"); - - return getQuestions(view, session); - } - - @Cacheable("flashcardquestions") - @Override - public List<Question> getFlashcardsForUsers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "flashcard", true); - view.setEndKeyArray(session.getId(), "flashcard", true, "{}"); - - return getQuestions(view, session); - } - - @Override - public List<Question> getFlashcardsForTeachers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "flashcard"); - view.setEndKeyArray(session.getId(), "flashcard", "{}"); - - return getQuestions(view, session); - } - - @Cacheable("preparationquestions") - @Override - public List<Question> getPreparationQuestionsForUsers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "preparation", true); - view.setEndKeyArray(session.getId(), "preparation", true, "{}"); - - return getQuestions(view, session); - } - - @Override - public List<Question> getPreparationQuestionsForTeachers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "preparation"); - view.setEndKeyArray(session.getId(), "preparation", "{}"); - - return getQuestions(view, session); - } - - @Override - public List<Question> getAllSkillQuestions(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId()); - view.setEndKeyArray(session.getId(), "{}"); - - return getQuestions(view, session); - } - - private List<Question> getQuestions(final View view, final Session session) { - final ViewResults viewResults = getDatabase().view(view); - if (viewResults == null || viewResults.isEmpty()) { - return null; - } - - final List<Question> questions = new ArrayList<>(); - - Results<Question> results = getDatabase().queryView(view, Question.class); - for (final RowResult<Question> row : results.getRows()) { - Question question = row.getValue(); - question.updateRoundManagementState(); - question.setSessionKeyword(session.getKeyword()); - if (!"freetext".equals(question.getQuestionType()) && 0 == question.getPiRound()) { - /* needed for legacy questions whose piRound property has not been set */ - question.setPiRound(1); - } - - questions.add(question); - } - return questions; - } - - @Override - public int getLectureQuestionCount(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "lecture"); - view.setEndKeyArray(session.getId(), "lecture", "{}"); - - return getQuestionCount(view); - } - - @Override - public int getFlashcardCount(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "flashcard"); - view.setEndKeyArray(session.getId(), "flashcard", "{}"); - - return getQuestionCount(view); - } - - @Override - public int getPreparationQuestionCount(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "preparation"); - view.setEndKeyArray(session.getId(), "preparation", "{}"); - - return getQuestionCount(view); - } - - private int getQuestionCount(final View view) { - view.setReduce(true); - final ViewResults results = getDatabase().view(view); - if (results.getJSONArray("rows").optJSONObject(0) == null) { - return 0; - } - return results.getJSONArray("rows").optJSONObject(0).optInt("value"); - } - @Override public int countLectureQuestionAnswers(final Session session) { return countQuestionVariantAnswers(session, "lecture"); @@ -1083,257 +672,40 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return results.getJSONArray("rows").optJSONObject(0).optInt("value"); } - /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict("skillquestions"), - @CacheEvict("lecturequestions"), - @CacheEvict(value = "answers", allEntries = true)}) - @Override - public int[] deleteAllLectureQuestionsWithAnswers(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "lecture"); - view.setEndKey(session.getId(), "lecture", "{}"); - - return deleteAllQuestionDocumentsWithAnswers(view); - } - - /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict("skillquestions"), - @CacheEvict("flashcardquestions"), - @CacheEvict(value = "answers", allEntries = true)}) - @Override - public int[] deleteAllFlashcardsWithAnswers(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "flashcard"); - view.setEndKey(session.getId(), "flashcard", "{}"); - - return deleteAllQuestionDocumentsWithAnswers(view); - } - - /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict("skillquestions"), - @CacheEvict("preparationquestions"), - @CacheEvict(value = "answers", allEntries = true)}) - @Override - public int[] deleteAllPreparationQuestionsWithAnswers(final Session session) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "preparation"); - view.setEndKey(session.getId(), "preparation", "{}"); - - return deleteAllQuestionDocumentsWithAnswers(view); - } - - @Override - public List<String> getUnAnsweredLectureQuestionIds(final Session session, final User user) { - final View view = new View("answer/questionid_piround_by_user_sessionid_variant"); - view.setKey(user.getUsername(), session.getId(), "lecture"); - return collectUnansweredQuestionIdsByPiRound(getDatabaseDao().getLectureQuestionsForUsers(session), view); - } - - @Override - public List<String> getUnAnsweredPreparationQuestionIds(final Session session, final User user) { - final View view = new View("answer/questionid_piround_by_user_sessionid_variant"); - view.setKey(user.getUsername(), session.getId(), "preparation"); - return collectUnansweredQuestionIdsByPiRound(getDatabaseDao().getPreparationQuestionsForUsers(session), view); - } - - private List<String> collectUnansweredQuestionIds( - final List<String> questions, - final View view - ) { - final ViewResults answeredQuestions = getDatabase().view(view); - - final List<String> answered = new ArrayList<>(); - for (final Document d : answeredQuestions.getResults()) { - answered.add(d.getString("value")); - } - - final List<String> unanswered = new ArrayList<>(); - for (final String questionId : questions) { - if (!answered.contains(questionId)) { - unanswered.add(questionId); - } - } - return unanswered; - } - - private List<String> collectUnansweredQuestionIdsByPiRound( - final List<Question> questions, - final View view - ) { - final ViewResults answeredQuestions = getDatabase().view(view); - - final Map<String, Integer> answered = new HashMap<>(); - for (final Document d : answeredQuestions.getResults()) { - answered.put(d.getJSONArray("value").getString(0), d.getJSONArray("value").getInt(1)); - } - - final List<String> unanswered = new ArrayList<>(); - - for (final Question question : questions) { - if (!"slide".equals(question.getQuestionType()) && (!answered.containsKey(question.get_id()) - || (answered.containsKey(question.get_id()) && answered.get(question.get_id()) != question.getPiRound()))) { - unanswered.add(question.get_id()); - } - } - - return unanswered; - } - - private List<String> collectQuestionIds(final View view) { - final ViewResults results = getDatabase().view(view); - if (results.getResults().isEmpty()) { - return new ArrayList<>(); - } - final List<String> ids = new ArrayList<>(); - for (final Document d : results.getResults()) { - ids.add(d.getId()); - } - return ids; - } - - @Override - public List<Question> publishAllQuestions(final Session session, final boolean publish) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId()); - view.setEndKeyArray(session.getId(), "{}"); - final List<Question> questions = getQuestions(view, session); - getDatabaseDao().publishQuestions(session, publish, questions); - - return questions; - } - - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict(value = "skillquestions", key = "#session"), - @CacheEvict(value = "lecturequestions", key = "#session"), - @CacheEvict(value = "preparationquestions", key = "#session"), - @CacheEvict(value = "flashcardquestions", key = "#session") }) - @Override - public void publishQuestions(final Session session, final boolean publish, List<Question> questions) { - for (final Question q : questions) { - q.setActive(publish); - } - final List<Document> documents = new ArrayList<>(); - for (final Question q : questions) { - final Document d = toQuestionDocument(session, q); - d.setId(q.get_id()); - d.setRev(q.get_rev()); - documents.add(d); - } - try { - database.bulkSaveDocuments(documents.toArray(new Document[documents.size()])); - } catch (final IOException e) { - logger.error("Could not bulk publish all questions.", e); - } - } - - @Override - public List<Question> setVotingAdmissionForAllQuestions(final Session session, final boolean disableVoting) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId()); - view.setEndKeyArray(session.getId(), "{}"); - final List<Question> questions = getQuestions(view, session); - getDatabaseDao().setVotingAdmissions(session, disableVoting, questions); - - return questions; - } - - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict(value = "skillquestions", key = "#session"), - @CacheEvict(value = "lecturequestions", key = "#session"), - @CacheEvict(value = "preparationquestions", key = "#session"), - @CacheEvict(value = "flashcardquestions", key = "#session") }) - @Override - public void setVotingAdmissions(final Session session, final boolean disableVoting, List<Question> questions) { - for (final Question q : questions) { - if (!"flashcard".equals(q.getQuestionType())) { - q.setVotingDisabled(disableVoting); - } - } - final List<Document> documents = new ArrayList<>(); - for (final Question q : questions) { - final Document d = toQuestionDocument(session, q); - d.setId(q.get_id()); - d.setRev(q.get_rev()); - documents.add(d); - } - - try { - database.bulkSaveDocuments(documents.toArray(new Document[documents.size()])); - } catch (final IOException e) { - logger.error("Could not bulk set voting admission for all questions.", e); - } - } - /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ @CacheEvict(value = "answers", allEntries = true) @Override public int deleteAllQuestionsAnswers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId()); - view.setEndKeyArray(session.getId(), "{}"); - final List<Question> questions = getQuestions(view, session); - getDatabaseDao().resetQuestionsRoundState(session, questions); + final List<Content> contents = contentRepository.getQuestions(session.getId()); + contentRepository.resetQuestionsRoundState(session, contents); - return deleteAllAnswersForQuestions(questions); + return deleteAllAnswersForQuestions(contents); } /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ @CacheEvict(value = "answers", allEntries = true) @Override public int deleteAllPreparationAnswers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "preparation"); - view.setEndKeyArray(session.getId(), "preparation", "{}"); - final List<Question> questions = getQuestions(view, session); - getDatabaseDao().resetQuestionsRoundState(session, questions); + final List<Content> contents = contentRepository.getQuestions(session.getId(), "preparation"); + contentRepository.resetQuestionsRoundState(session, contents); - return deleteAllAnswersForQuestions(questions); + return deleteAllAnswersForQuestions(contents); } /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ @CacheEvict(value = "answers", allEntries = true) @Override public int deleteAllLectureAnswers(final Session session) { - final View view = new View("content/doc_by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), "lecture"); - view.setEndKeyArray(session.getId(), "lecture", "{}"); - final List<Question> questions = getQuestions(view, session); - getDatabaseDao().resetQuestionsRoundState(session, questions); + final List<Content> contents = contentRepository.getQuestions(session.getId(), "lecture"); + contentRepository.resetQuestionsRoundState(session, contents); - return deleteAllAnswersForQuestions(questions); + return deleteAllAnswersForQuestions(contents); } - @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), - @CacheEvict(value = "skillquestions", key = "#session"), - @CacheEvict(value = "lecturequestions", key = "#session"), - @CacheEvict(value = "preparationquestions", key = "#session"), - @CacheEvict(value = "flashcardquestions", key = "#session") }) - @Override - public void resetQuestionsRoundState(final Session session, List<Question> questions) { - for (final Question q : questions) { - q.resetQuestionState(); - } - final List<Document> documents = new ArrayList<>(); - for (final Question q : questions) { - final Document d = toQuestionDocument(session, q); - d.setId(q.get_id()); - d.setRev(q.get_rev()); - documents.add(d); - } - try { - database.bulkSaveDocuments(documents.toArray(new Document[documents.size()])); - } catch (final IOException e) { - logger.error("Could not bulk reset all questions round state.", e); - } - } - - private int deleteAllAnswersForQuestions(List<Question> questions) { + public int deleteAllAnswersForQuestions(List<Content> contents) { List<String> questionIds = new ArrayList<>(); - for (Question q : questions) { - questionIds.add(q.get_id()); + for (Content q : contents) { + questionIds.add(q.getId()); } final View bulkView = new View("answer/by_questionid"); bulkView.setKeys(questionIds); @@ -1356,15 +728,15 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return 0; } - private int[] deleteAllAnswersWithQuestions(List<Question> questions) { + public int[] deleteAllAnswersWithQuestions(List<Content> contents) { List<String> questionIds = new ArrayList<>(); final List<Document> allQuestions = new ArrayList<>(); - for (Question q : questions) { + for (Content q : contents) { final Document d = new Document(); - d.put("_id", q.get_id()); - d.put("_rev", q.get_rev()); + d.put("_id", q.getId()); + d.put("_rev", q.getRevision()); d.put("_deleted", true); - questionIds.add(q.get_id()); + questionIds.add(q.getId()); allQuestions.add(d); } final View bulkView = new View("answer/by_questionid"); @@ -1386,7 +758,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return new int[] {deleteList.size(), result.size()}; } catch (IOException e) { - logger.error("Could not bulk delete questions and answers.", e); + logger.error("Could not bulk delete contents and answers.", e); } return new int[] {0, 0}; @@ -1433,92 +805,6 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return courseScore; } - @Override - public List<String> getSubjects(Session session, String questionVariant) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), questionVariant); - view.setEndKeyArray(session.getId(), questionVariant, "{}"); - ViewResults results = this.getDatabase().view(view); - - if (results.getJSONArray("rows").optJSONObject(0) == null) { - return null; - } - - Set<String> uniqueSubjects = new HashSet<>(); - - for (final Document d : results.getResults()) { - uniqueSubjects.add(d.getJSONArray("key").getString(3)); - } - - return new ArrayList<>(uniqueSubjects); - } - - /* TODO: remove if this method is no longer used */ - @Override - public List<String> getQuestionIdsBySubject(Session session, String questionVariant, String subject) { - final View view = new View("content/by_sessionid_variant_active"); - view.setStartKeyArray(session.getId(), questionVariant, 1, subject); - view.setEndKeyArray(session.getId(), questionVariant, 1, subject, "{}"); - ViewResults results = this.getDatabase().view(view); - - if (results.getJSONArray("rows").optJSONObject(0) == null) { - return null; - } - - List<String> qids = new ArrayList<>(); - - for (final Document d : results.getResults()) { - final String s = d.getId(); - qids.add(s); - } - - return qids; - } - - @Override - public List<Question> getQuestionsByIds(List<String> ids, final Session session) { - View view = new View("_all_docs"); - view.setKeys(ids); - view.setIncludeDocs(true); - final List<Document> questiondocs = getDatabase().view(view).getResults(); - if (questiondocs == null || questiondocs.isEmpty()) { - - return null; - } - final List<Question> result = new ArrayList<>(); - final MorpherRegistry morpherRegistry = JSONUtils.getMorpherRegistry(); - final Morpher dynaMorpher = new BeanMorpher(PossibleAnswer.class, morpherRegistry); - morpherRegistry.registerMorpher(dynaMorpher); - for (final Document document : questiondocs) { - if (!"".equals(document.optString("error"))) { - // Skip documents we could not load. Maybe they were deleted. - continue; - } - final Question question = (Question) JSONObject.toBean( - document.getJSONObject().getJSONObject("doc"), - Question.class - ); - @SuppressWarnings("unchecked") - final Collection<PossibleAnswer> answers = JSONArray.toCollection( - document.getJSONObject().getJSONObject("doc").getJSONArray("possibleAnswers"), - PossibleAnswer.class - ); - question.setPossibleAnswers(new ArrayList<>(answers)); - question.setSessionKeyword(session.getKeyword()); - if (!"freetext".equals(question.getQuestionType()) && 0 == question.getPiRound()) { - /* needed for legacy questions whose piRound property has not been set */ - question.setPiRound(1); - } - - if (question.getImage() != null) { - question.setImage("true"); - } - - result.add(question); - } - return result; - } - @Override @Cacheable(cacheNames = "motdlist", key = "#p0") public MotdList getMotdListForUser(final String username) { diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index 9d4849505e06da64374221a75f6d4631abc17a9d..532729fdf3fc8d101a9c2700b350209c5876c5f2 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -26,35 +26,17 @@ import java.util.List; * All methods the database must support. */ public interface IDatabaseDao { - Question saveQuestion(Session session, Question question); - - Question getQuestion(String id); - - List<Question> getSkillQuestionsForUsers(Session session); - - List<Question> getSkillQuestionsForTeachers(Session session); - - int getSkillQuestionCount(Session session); - - List<String> getQuestionIds(Session session, User user); - - int deleteQuestionWithAnswers(Question question); - - int[] deleteAllQuestionsWithAnswers(Session session); - - List<String> getUnAnsweredQuestionIds(Session session, User user); - Answer getMyAnswer(User me, String questionId, int piRound); - List<Answer> getAnswers(Question question, int piRound); + List<Answer> getAnswers(Content content, int piRound); - List<Answer> getAnswers(Question question); + List<Answer> getAnswers(Content content); - List<Answer> getAllAnswers(Question question); + List<Answer> getAllAnswers(Content content); - int getAnswerCount(Question question, int piRound); + int getAnswerCount(Content content, int piRound); - int getTotalAnswerCountByQuestion(Question question); + int getTotalAnswerCountByQuestion(Content content); int getAbstentionAnswerCount(String questionId); @@ -64,11 +46,9 @@ public interface IDatabaseDao { int getTotalAnswerCount(String sessionKey); - Question updateQuestion(Question question); + int deleteAnswers(Content content); - int deleteAnswers(Question question); - - Answer saveAnswer(Answer answer, User user, Question question, Session session); + Answer saveAnswer(Answer answer, User user, Content content, Session session); Answer updateAnswer(Answer answer); @@ -76,44 +56,10 @@ public interface IDatabaseDao { int deleteInactiveGuestVisitedSessionLists(long lastActivityBefore); - List<Question> getLectureQuestionsForUsers(Session session); - - List<Question> getLectureQuestionsForTeachers(Session session); - - List<Question> getFlashcardsForUsers(Session session); - - List<Question> getFlashcardsForTeachers(Session session); - - List<Question> getPreparationQuestionsForUsers(Session session); - - List<Question> getPreparationQuestionsForTeachers(Session session); - - List<Question> getAllSkillQuestions(Session session); - - int getLectureQuestionCount(Session session); - - int getFlashcardCount(Session session); - - int getPreparationQuestionCount(Session session); - int countLectureQuestionAnswers(Session session); int countPreparationQuestionAnswers(Session session); - int[] deleteAllLectureQuestionsWithAnswers(Session session); - - int[] deleteAllFlashcardsWithAnswers(Session session); - - int[] deleteAllPreparationQuestionsWithAnswers(Session session); - - List<String> getUnAnsweredLectureQuestionIds(Session session, User user); - - List<String> getUnAnsweredPreparationQuestionIds(Session session, User user); - - void publishQuestions(Session session, boolean publish, List<Question> questions); - - List<Question> publishAllQuestions(Session session, boolean publish); - int deleteAllQuestionsAnswers(Session session); CourseScore getLearningProgress(Session session); @@ -124,21 +70,11 @@ public interface IDatabaseDao { Statistics getStatistics(); - List<String> getSubjects(Session session, String questionVariant); - - List<String> getQuestionIdsBySubject(Session session, String questionVariant, String subject); - - List<Question> getQuestionsByIds(List<String> ids, Session session); - - void resetQuestionsRoundState(Session session, List<Question> questions); - - void setVotingAdmissions(Session session, boolean disableVoting, List<Question> questions); - - List<Question> setVotingAdmissionForAllQuestions(Session session, boolean disableVoting); - <T> T getObjectFromId(String documentId, Class<T> klass); MotdList getMotdListForUser(final String username); MotdList createOrUpdateMotdList(MotdList motdlist); + + int[] deleteAllAnswersWithQuestions(List<Content> contents); } diff --git a/src/main/java/de/thm/arsnova/entities/Question.java b/src/main/java/de/thm/arsnova/entities/Content.java similarity index 75% rename from src/main/java/de/thm/arsnova/entities/Question.java rename to src/main/java/de/thm/arsnova/entities/Content.java index a99670287ba7b6ce8c87f1bdbc730db9c2969e0e..653a645518299427ef98036fd3e8e110114fde57 100644 --- a/src/main/java/de/thm/arsnova/entities/Question.java +++ b/src/main/java/de/thm/arsnova/entities/Content.java @@ -17,20 +17,21 @@ */ package de.thm.arsnova.entities; +import com.fasterxml.jackson.annotation.JsonView; +import de.thm.arsnova.entities.serialization.View; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import java.io.Serializable; import java.util.Date; import java.util.List; /** * A question the teacher is asking. */ -@ApiModel(value = "lecturerquestion", description = "the question entity") -public class Question implements Serializable { - - private String type; +@ApiModel(value = "content", description = "the content entity") +public class Content implements Entity { + private String id; + private String rev; private String questionType; private String questionVariant; private String subject; @@ -62,8 +63,6 @@ public class Question implements Serializable { private boolean strictMode; private int rating; private String correctAnswer; - private String _id; - private String _rev; private String image; private String fcImage; @@ -92,56 +91,78 @@ public class Question implements Serializable { private String hint; private String solution; - @ApiModelProperty(required = true, value = "the type") - public final String getType() { - return type; + @ApiModelProperty(required = true, value = "the couchDB ID") + @JsonView({View.Persistence.class, View.Public.class}) + public String getId() { + return id; + } + + @JsonView({View.Persistence.class, View.Public.class}) + public void setId(final String id) { + this.id = id; + } + + @JsonView({View.Persistence.class, View.Public.class}) + public void setRevision(final String rev) { + this.rev = rev; } - public final void setType(final String type) { - this.type = type; + @JsonView({View.Persistence.class, View.Public.class}) + public String getRevision() { + return rev; } @ApiModelProperty(required = true, value = "the question type") + @JsonView({View.Persistence.class, View.Public.class}) public final String getQuestionType() { return questionType; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setQuestionType(final String questionType) { this.questionType = questionType; } @ApiModelProperty(required = true, value = "either lecture or preparation") + @JsonView({View.Persistence.class, View.Public.class}) public final String getQuestionVariant() { return questionVariant; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setQuestionVariant(final String questionVariant) { this.questionVariant = questionVariant; } @ApiModelProperty(required = true, value = "used to display subject") + @JsonView({View.Persistence.class, View.Public.class}) public final String getSubject() { return subject; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setSubject(final String subject) { this.subject = subject; } @ApiModelProperty(required = true, value = "the text") + @JsonView({View.Persistence.class, View.Public.class}) public final String getText() { return text; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setText(final String text) { this.text = text; } @ApiModelProperty(required = true, value = "true for active question") + @JsonView({View.Persistence.class, View.Public.class}) public final boolean isActive() { return active; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setActive(final boolean active) { this.active = active; } @@ -156,10 +177,12 @@ public class Question implements Serializable { } @ApiModelProperty(required = true, value = "list of possible answers") + @JsonView({View.Persistence.class, View.Public.class}) public final List<PossibleAnswer> getPossibleAnswers() { return possibleAnswers; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setPossibleAnswers(final List<PossibleAnswer> possibleAnswers) { this.possibleAnswers = possibleAnswers; } @@ -174,10 +197,12 @@ public class Question implements Serializable { } @ApiModelProperty(required = true, value = "couchDB ID of the session, the question is assigned to") + @JsonView({View.Persistence.class, View.Public.class}) public final String getSessionId() { return sessionId; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setSessionId(final String sessionId) { this.sessionId = sessionId; } @@ -201,10 +226,12 @@ public class Question implements Serializable { } @ApiModelProperty(required = true, value = "creation date timestamp") + @JsonView(View.Persistence.class) public final long getTimestamp() { return timestamp; } + @JsonView(View.Persistence.class) public final void setTimestamp(final long timestamp) { this.timestamp = timestamp; } @@ -219,46 +246,56 @@ public class Question implements Serializable { } @ApiModelProperty(required = true, value = "used to display duration") + @JsonView({View.Persistence.class, View.Public.class}) public final int getDuration() { return duration; } + @JsonView({View.Persistence.class, View.Public.class}) + public final void setDuration(final int duration) { + this.duration = duration; + } + @ApiModelProperty(required = true, value = "true for image question") + @JsonView({View.Persistence.class, View.Public.class}) public final boolean isImageQuestion() { return imageQuestion; } + @JsonView({View.Persistence.class, View.Public.class}) public void setImageQuestion(boolean imageQuestion) { this.imageQuestion = imageQuestion; } - public final void setDuration(final int duration) { - this.duration = duration; - } - @ApiModelProperty(required = true, value = "the peer instruction round no.") + @JsonView({View.Persistence.class, View.Public.class}) public int getPiRound() { return piRound; } + @JsonView({View.Persistence.class, View.Public.class}) public void setPiRound(final int piRound) { this.piRound = piRound; } @ApiModelProperty(required = true, value = "the peer instruction round end timestamp") + @JsonView({View.Persistence.class, View.Public.class}) public long getPiRoundEndTime() { return piRoundEndTime; } + @JsonView({View.Persistence.class, View.Public.class}) public void setPiRoundEndTime(long piRoundEndTime) { this.piRoundEndTime = piRoundEndTime; } @ApiModelProperty(required = true, value = "the peer instruction round start timestamp") + @JsonView({View.Persistence.class, View.Public.class}) public long getPiRoundStartTime() { return piRoundStartTime; } + @JsonView({View.Persistence.class, View.Public.class}) public void setPiRoundStartTime(long piRoundStartTime) { this.piRoundStartTime = piRoundStartTime; } @@ -282,340 +319,395 @@ public class Question implements Serializable { } @ApiModelProperty(required = true, value = "used to display showStatistic") + @JsonView({View.Persistence.class, View.Public.class}) public boolean isShowStatistic() { return showStatistic; } + @JsonView({View.Persistence.class, View.Public.class}) public void setShowStatistic(final boolean showStatistic) { this.showStatistic = showStatistic; } @ApiModelProperty(required = true, value = "used to display cvIsColored") + @JsonView({View.Persistence.class, View.Public.class}) public boolean getCvIsColored() { return cvIsColored; } + @JsonView({View.Persistence.class, View.Public.class}) public void setCvIsColored(boolean cvIsColored) { this.cvIsColored = cvIsColored; } @ApiModelProperty(required = true, value = "used to display showAnswer") + @JsonView({View.Persistence.class, View.Public.class}) public boolean isShowAnswer() { return showAnswer; } + @JsonView({View.Persistence.class, View.Public.class}) public void setShowAnswer(final boolean showAnswer) { this.showAnswer = showAnswer; } @ApiModelProperty(required = true, value = "used to display abstention") + @JsonView({View.Persistence.class, View.Public.class}) public boolean isAbstention() { return abstention; } + @JsonView({View.Persistence.class, View.Public.class}) public void setAbstention(final boolean abstention) { this.abstention = abstention; } + @JsonView({View.Persistence.class, View.Public.class}) public boolean isIgnoreCaseSensitive() { return ignoreCaseSensitive; } + @JsonView({View.Persistence.class, View.Public.class}) public void setIgnoreCaseSensitive(final boolean ignoreCaseSensitive) { this.ignoreCaseSensitive = ignoreCaseSensitive; } + @JsonView({View.Persistence.class, View.Public.class}) public boolean isIgnoreWhitespaces() { return ignoreWhitespaces; } + @JsonView({View.Persistence.class, View.Public.class}) public void setIgnoreWhitespaces(final boolean ignoreWhitespaces) { this.ignoreWhitespaces = ignoreWhitespaces; } + @JsonView({View.Persistence.class, View.Public.class}) public boolean isIgnorePunctuation() { return ignorePunctuation; } + @JsonView({View.Persistence.class, View.Public.class}) public void setIgnorePunctuation(final boolean ignorePunctuation) { this.ignorePunctuation = ignorePunctuation; } + @JsonView({View.Persistence.class, View.Public.class}) public boolean isFixedAnswer() { return this.fixedAnswer; } + @JsonView({View.Persistence.class, View.Public.class}) public void setFixedAnswer(final boolean fixedAnswer) { this.fixedAnswer = fixedAnswer; } + @JsonView({View.Persistence.class, View.Public.class}) public boolean isStrictMode() { return this.strictMode; } + @JsonView({View.Persistence.class, View.Public.class}) public void setStrictMode(final boolean strictMode) { this.strictMode = strictMode; } + @JsonView({View.Persistence.class, View.Public.class}) public final int getRating() { return this.rating; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setRating(final int rating) { this.rating = rating; } + @JsonView({View.Persistence.class, View.Public.class}) public final String getCorrectAnswer() { return correctAnswer; } + @JsonView({View.Persistence.class, View.Public.class}) public final void setCorrectAnswer(final String correctAnswer) { this.correctAnswer = correctAnswer; } - @ApiModelProperty(required = true, value = "the couchDB ID") - public final String get_id() { - return _id; - } - - public final void set_id(final String _id) { - this._id = _id; - } - - public final String get_rev() { - return _rev; - } - - public final void set_rev(final String _rev) { - this._rev = _rev; - } - @ApiModelProperty(required = true, value = "the image") + @JsonView({View.Persistence.class, View.Public.class}) public String getImage() { return image; } + @JsonView({View.Persistence.class, View.Public.class}) public void setImage(final String image) { this.image = image; } @ApiModelProperty(required = true, value = "the fcImage") + @JsonView({View.Persistence.class, View.Public.class}) public String getFcImage() { return fcImage; } + @JsonView({View.Persistence.class, View.Public.class}) public void setFcImage(final String fcImage) { this.fcImage = fcImage; } @ApiModelProperty(required = true, value = "the grid size") + @JsonView({View.Persistence.class, View.Public.class}) public int getGridSize() { return gridSize; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridSize(final int gridSize) { this.gridSize = gridSize; } @ApiModelProperty(required = true, value = "the image X offset") + @JsonView({View.Persistence.class, View.Public.class}) public int getOffsetX() { return offsetX; } + @JsonView({View.Persistence.class, View.Public.class}) public void setOffsetX(final int offsetX) { this.offsetX = offsetX; } @ApiModelProperty(required = true, value = "the image Y offset") + @JsonView({View.Persistence.class, View.Public.class}) public int getOffsetY() { return offsetY; } + @JsonView({View.Persistence.class, View.Public.class}) public void setOffsetY(final int offsetY) { this.offsetY = offsetY; } @ApiModelProperty(required = true, value = "the image zoom level") + @JsonView({View.Persistence.class, View.Public.class}) public int getZoomLvl() { return zoomLvl; } + @JsonView({View.Persistence.class, View.Public.class}) public void setZoomLvl(final int zoomLvl) { this.zoomLvl = zoomLvl; } @ApiModelProperty(required = true, value = "the grid X offset") + @JsonView({View.Persistence.class, View.Public.class}) public int getGridOffsetX() { return gridOffsetX; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridOffsetX(int gridOffsetX) { this.gridOffsetX = gridOffsetX; } @ApiModelProperty(required = true, value = "the grid Y offset") + @JsonView({View.Persistence.class, View.Public.class}) public int getGridOffsetY() { return gridOffsetY; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridOffsetY(int gridOffsetY) { this.gridOffsetY = gridOffsetY; } @ApiModelProperty(required = true, value = "the grid zoom lvl") + @JsonView({View.Persistence.class, View.Public.class}) public int getGridZoomLvl() { return gridZoomLvl; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridZoomLvl(int gridZoomLvl) { this.gridZoomLvl = gridZoomLvl; } @ApiModelProperty(required = true, value = "the grid X size") + @JsonView({View.Persistence.class, View.Public.class}) public int getGridSizeX() { return gridSizeX; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridSizeX(int gridSizeX) { this.gridSizeX = gridSizeX; } @ApiModelProperty(required = true, value = "the grid Y size") + @JsonView({View.Persistence.class, View.Public.class}) public int getGridSizeY() { return gridSizeY; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridSizeY(int gridSizeY) { this.gridSizeY = gridSizeY; } @ApiModelProperty(required = true, value = "true for hidden grid") + @JsonView({View.Persistence.class, View.Public.class}) public boolean getGridIsHidden() { return gridIsHidden; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridIsHidden(boolean gridIsHidden) { this.gridIsHidden = gridIsHidden; } @ApiModelProperty(required = true, value = "the image rotation") + @JsonView({View.Persistence.class, View.Public.class}) public int getImgRotation() { return imgRotation; } + @JsonView({View.Persistence.class, View.Public.class}) public void setImgRotation(int imgRotation) { this.imgRotation = imgRotation; } @ApiModelProperty(required = true, value = "the toggled left fields") + @JsonView({View.Persistence.class, View.Public.class}) public boolean getToggleFieldsLeft() { return toggleFieldsLeft; } + @JsonView({View.Persistence.class, View.Public.class}) public void setToggleFieldsLeft(boolean toggleFieldsLeft) { this.toggleFieldsLeft = toggleFieldsLeft; } @ApiModelProperty(required = true, value = "the number of clickable fields") + @JsonView({View.Persistence.class, View.Public.class}) public int getNumClickableFields() { return numClickableFields; } + @JsonView({View.Persistence.class, View.Public.class}) public void setNumClickableFields(int numClickableFields) { this.numClickableFields = numClickableFields; } @ApiModelProperty(required = true, value = "the threshold of correct answers") + @JsonView({View.Persistence.class, View.Public.class}) public int getThresholdCorrectAnswers() { return thresholdCorrectAnswers; } + @JsonView({View.Persistence.class, View.Public.class}) public void setThresholdCorrectAnswers(int thresholdCorrectAnswers) { this.thresholdCorrectAnswers = thresholdCorrectAnswers; } @ApiModelProperty(required = true, value = "the grid line color") + @JsonView({View.Persistence.class, View.Public.class}) public String getGridLineColor() { return gridLineColor; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridLineColor(String gridLineColor) { this.gridLineColor = gridLineColor; } @ApiModelProperty(required = true, value = "the number of dots") + @JsonView({View.Persistence.class, View.Public.class}) public int getNumberOfDots() { return numberOfDots; } + @JsonView({View.Persistence.class, View.Public.class}) public void setNumberOfDots(int numberOfDots) { this.numberOfDots = numberOfDots; } @ApiModelProperty(required = true, value = "the grid type") + @JsonView({View.Persistence.class, View.Public.class}) public String getGridType() { return gridType; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridType(String gridType) { this.gridType = gridType; } + @JsonView({View.Persistence.class, View.Public.class}) public void setScaleFactor(String scaleFactor) { this.scaleFactor = scaleFactor; } @ApiModelProperty(required = true, value = "the image scale factor") + @JsonView({View.Persistence.class, View.Public.class}) public String getScaleFactor() { return this.scaleFactor; } + @JsonView({View.Persistence.class, View.Public.class}) public void setGridScaleFactor(String scaleFactor) { this.gridScaleFactor = scaleFactor; } @ApiModelProperty(required = true, value = "the grid scale factor") + @JsonView({View.Persistence.class, View.Public.class}) public String getGridScaleFactor() { return this.gridScaleFactor; } @ApiModelProperty(required = true, value = "true for a question that can be answered via text") + @JsonView({View.Persistence.class, View.Public.class}) public boolean isTextAnswerEnabled() { return this.textAnswerEnabled; } + @JsonView({View.Persistence.class, View.Public.class}) public void setTextAnswerEnabled(boolean textAnswerEnabled) { this.textAnswerEnabled = textAnswerEnabled; } @ApiModelProperty(required = true, value = "true for disabled voting") + @JsonView({View.Persistence.class, View.Public.class}) public boolean isVotingDisabled() { return votingDisabled; } + @JsonView({View.Persistence.class, View.Public.class}) public void setVotingDisabled(boolean votingDisabled) { this.votingDisabled = votingDisabled; } + @JsonView({View.Persistence.class, View.Public.class}) public String getHint() { return hint; } + @JsonView({View.Persistence.class, View.Public.class}) public void setHint(String hint) { this.hint = hint; } + @JsonView({View.Persistence.class, View.Public.class}) public String getSolution() { return solution; } + @JsonView({View.Persistence.class, View.Public.class}) public void setSolution(String solution) { this.solution = solution; } @Override public final String toString() { - return "Question type '" + type + "': " + subject + ";\n" + text + possibleAnswers; + return "Content type '" + questionType + "': " + subject + ";\n" + text + possibleAnswers; } @Override @@ -623,7 +715,7 @@ public class Question implements Serializable { // auto generated! final int prime = 31; int result = 1; - result = prime * result + ((_id == null) ? 0 : _id.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } @@ -639,12 +731,12 @@ public class Question implements Serializable { if (getClass() != obj.getClass()) { return false; } - Question other = (Question) obj; - if (_id == null) { - if (other._id != null) { + Content other = (Content) obj; + if (id == null) { + if (other.id != null) { return false; } - } else if (!_id.equals(other._id)) { + } else if (!id.equals(other.id)) { return false; } return true; diff --git a/src/main/java/de/thm/arsnova/entities/PossibleAnswer.java b/src/main/java/de/thm/arsnova/entities/PossibleAnswer.java index 0b7fa7983f2dfadf0a92c1ea9e32002e5b87a995..f3bfb039ade4d7ed66a4d8e8b13125004e01c1cf 100644 --- a/src/main/java/de/thm/arsnova/entities/PossibleAnswer.java +++ b/src/main/java/de/thm/arsnova/entities/PossibleAnswer.java @@ -17,6 +17,8 @@ */ package de.thm.arsnova.entities; +import com.fasterxml.jackson.annotation.JsonView; +import de.thm.arsnova.entities.serialization.View; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -43,28 +45,34 @@ public class PossibleAnswer implements Serializable { } @ApiModelProperty(required = true, value = "the text") + @JsonView({View.Persistence.class, View.Public.class}) public String getText() { return text; } + @JsonView({View.Persistence.class, View.Public.class}) public void setText(String text) { this.text = text; } @ApiModelProperty(required = true, value = "true for a correct answer") + @JsonView({View.Persistence.class, View.Public.class}) public boolean isCorrect() { return correct; } + @JsonView({View.Persistence.class, View.Public.class}) public void setCorrect(boolean correct) { this.correct = correct; } @ApiModelProperty(required = true, value = "the value") + @JsonView({View.Persistence.class, View.Public.class}) public int getValue() { return value; } + @JsonView({View.Persistence.class, View.Public.class}) public void setValue(int value) { this.value = value; } diff --git a/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java b/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java index 8622e2f1a2c5075388c6703e5423995e06800560..7141f02f45cbebeabb7ee15e38aa25b2087f0975 100644 --- a/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java +++ b/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java @@ -25,6 +25,7 @@ import de.thm.arsnova.entities.DbUser; import de.thm.arsnova.entities.Entity; import de.thm.arsnova.entities.LogEntry; import de.thm.arsnova.entities.Motd; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.HashMap; @@ -39,6 +40,7 @@ public class CouchDbTypeFieldConverter implements Converter<Class<? extends Enti typeMapping.put(Motd.class, "motd"); typeMapping.put(Session.class, "session"); typeMapping.put(Comment.class, "interposed_question"); + typeMapping.put(Content.class, "skill_question"); } @Override 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 5b6d24429c25daaead6c8b770bae04b401c16394..de074d3e1cc30029d1ee9a60c315aa69319931fc 100644 --- a/src/main/java/de/thm/arsnova/entities/transport/Answer.java +++ b/src/main/java/de/thm/arsnova/entities/transport/Answer.java @@ -19,7 +19,7 @@ package de.thm.arsnova.entities.transport; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonView; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.serialization.View; import io.swagger.annotations.ApiModel; @@ -126,28 +126,28 @@ public class Answer implements Serializable { this.abstention = abstention; } - public de.thm.arsnova.entities.Answer generateAnswerEntity(final User user, final Question question) { + public de.thm.arsnova.entities.Answer generateAnswerEntity(final User user, final Content content) { // 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.setAnswerTextRaw(this.getAnswerTextRaw()); - theAnswer.setSessionId(question.getSessionId()); + theAnswer.setSessionId(content.getSessionId()); theAnswer.setUser(user.getUsername()); - theAnswer.setQuestionId(question.get_id()); + theAnswer.setQuestionId(content.getId()); theAnswer.setTimestamp(new Date().getTime()); - theAnswer.setQuestionVariant(question.getQuestionVariant()); + theAnswer.setQuestionVariant(content.getQuestionVariant()); theAnswer.setAbstention(this.isAbstention()); // calculate learning progress value after all properties are set - theAnswer.setQuestionValue(question.calculateValue(theAnswer)); + theAnswer.setQuestionValue(content.calculateValue(theAnswer)); theAnswer.setAnswerImage(this.getAnswerImage()); theAnswer.setSuccessfulFreeTextAnswer(this.isSuccessfulFreeTextAnswer()); - if ("freetext".equals(question.getQuestionType())) { + if ("freetext".equals(content.getQuestionType())) { theAnswer.setPiRound(0); } else { - theAnswer.setPiRound(question.getPiRound()); + theAnswer.setPiRound(content.getPiRound()); } return theAnswer; diff --git a/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java b/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java index 92b8b4950ba24b3407beca5e3a8e2648f7d25300..694de60fcd8d8791394a7f47e4aeadedd93521ed 100644 --- a/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java +++ b/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java @@ -18,7 +18,7 @@ package de.thm.arsnova.entities.transport; import de.thm.arsnova.entities.Answer; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; @@ -30,15 +30,15 @@ public class AnswerQueueElement { private final Session session; - private final Question question; + private final Content content; private final Answer answer; private final User user; - public AnswerQueueElement(Session session, Question question, Answer answer, User user) { + public AnswerQueueElement(Session session, Content content, Answer answer, User user) { this.session = session; - this.question = question; + this.content = content; this.answer = answer; this.user = user; } @@ -47,8 +47,8 @@ public class AnswerQueueElement { return session; } - public Question getQuestion() { - return question; + public Content getQuestion() { + return content; } public Answer getAnswer() { diff --git a/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java b/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java index 10c46dac2621cac07d14afc9f756f38495fe2de4..1ef60232f0e80f12197be2720cdb27886dfa4191 100644 --- a/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java +++ b/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java @@ -18,8 +18,8 @@ package de.thm.arsnova.entities.transport; import com.fasterxml.jackson.annotation.JsonView; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Motd; -import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.SessionFeature; import de.thm.arsnova.entities.SessionInfo; @@ -40,7 +40,7 @@ public class ImportExportSession { private ImportExportSesssion session; - private List<ImportExportQuestion> questions; + private List<ImportExportContent> questions; private List<Comment> feedbackQuestions; @@ -69,11 +69,11 @@ public class ImportExportSession { @ApiModelProperty(required = true, value = "used to display questions") @JsonView(View.Public.class) - public List<ImportExportQuestion> getQuestions() { + public List<ImportExportContent> getQuestions() { return questions; } - public void setQuestions(List<ImportExportQuestion> questions) { + public void setQuestions(List<ImportExportContent> questions) { this.questions = questions; } @@ -126,8 +126,8 @@ public class ImportExportSession { session = iesession; } - public void addQuestionWithAnswers(Question q, List<Answer> aL) { - ImportExportQuestion ieq = new ImportExportQuestion(q); + public void addQuestionWithAnswers(Content q, List<Answer> aL) { + ImportExportContent ieq = new ImportExportContent(q); ieq.setAnswers(aL); questions.add(ieq); } @@ -158,16 +158,15 @@ public class ImportExportSession { return s; } - public static class ImportExportQuestion extends Question { + public static class ImportExportContent extends Content { private List<Answer> answers; - public ImportExportQuestion() { + public ImportExportContent() { } - public ImportExportQuestion(Question q) { - setType(q.getType()); + public ImportExportContent(Content q) { setQuestionType(q.getQuestionType()); setQuestionVariant(q.getQuestionVariant()); setSubject(q.getSubject()); diff --git a/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java b/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java index 8d400e92823539cab79c6ca09ed484e772604b02..55970e207457824eff5d3ba23772ed3e24ad4e68 100644 --- a/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java +++ b/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java @@ -17,7 +17,7 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; /** @@ -27,11 +27,11 @@ public class DeleteAnswerEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public DeleteAnswerEvent(Object source, Session session, Question question) { + public DeleteAnswerEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } @Override @@ -39,7 +39,7 @@ public class DeleteAnswerEvent extends SessionEvent { visitor.visit(this); } - public Question getQuestion() { - return question; + public Content getQuestion() { + return content; } } diff --git a/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java b/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java index 2f3cfd71b2518377694c7c3e160a3ee4dcc373cf..0204ee5b7d5ca8bdd101a0cf41ddb7c005da0800 100644 --- a/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java +++ b/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java @@ -17,25 +17,25 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; /** - * Fires whenever a question is deleted. + * Fires whenever a content is deleted. */ public class DeleteQuestionEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public DeleteQuestionEvent(Object source, Session session, Question question) { + public DeleteQuestionEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } - public Question getQuestion() { - return this.question; + public Content getQuestion() { + return this.content; } @Override diff --git a/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java b/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java index 389b3ea97b08bb76af634a26036283c2344c46d1..8371c8b01c59573a2f7b6320421623a1dba4ff26 100644 --- a/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java +++ b/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java @@ -17,25 +17,25 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; /** - * Fires whenever a question is disabled, i.e., it is hidden from students. + * Fires whenever a content is disabled, i.e., it is hidden from students. */ public class LockQuestionEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public LockQuestionEvent(Object source, Session session, Question question) { + public LockQuestionEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } - public Question getQuestion() { - return this.question; + public Content getQuestion() { + return this.content; } @Override diff --git a/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java b/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java index 9ee93fa3b232f2f4ec517dc5ffa304256553f2a2..2981f4e18f5610a5799167146c1036e0cb286be2 100644 --- a/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java +++ b/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java @@ -17,27 +17,27 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.List; /** - * Fires whenever a set of questions are disabled, i.e., they are hidden from students. + * Fires whenever a set of contents are disabled, i.e., they are hidden from students. */ public class LockQuestionsEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private List<Question> questions; + private List<Content> contents; - public LockQuestionsEvent(Object source, Session session, List<Question> questions) { + public LockQuestionsEvent(Object source, Session session, List<Content> contents) { super(source, session); - this.questions = questions; + this.contents = contents; } - public List<Question> getQuestions() { - return this.questions; + public List<Content> getQuestions() { + return this.contents; } @Override diff --git a/src/main/java/de/thm/arsnova/events/LockVoteEvent.java b/src/main/java/de/thm/arsnova/events/LockVoteEvent.java index b33922f4f25bdc75a5df1a520fffce1e14c0b548..e3e9f000fd8fafa074572445ce493510a1a06d68 100644 --- a/src/main/java/de/thm/arsnova/events/LockVoteEvent.java +++ b/src/main/java/de/thm/arsnova/events/LockVoteEvent.java @@ -17,36 +17,36 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.HashMap; import java.util.Map; /** - * Fires whenever voting on a question is disabled. + * Fires whenever voting on a content is disabled. */ public class LockVoteEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public LockVoteEvent(Object source, Session session, Question question) { + public LockVoteEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } public String getQuestionId() { - return this.question.get_id(); + return this.content.getId(); } public String getQuestionVariant() { - return this.question.getQuestionVariant(); + return this.content.getQuestionVariant(); } public Boolean getVotingDisabled() { - return this.question.isVotingDisabled(); + return this.content.isVotingDisabled(); } public Map<String, Object> getVotingAdmission() { diff --git a/src/main/java/de/thm/arsnova/events/LockVotesEvent.java b/src/main/java/de/thm/arsnova/events/LockVotesEvent.java index fb5acd7c16e404db66a3a716ba48f52f7461253e..6f8043c18ae279962546d180e4191bde2d5e193e 100644 --- a/src/main/java/de/thm/arsnova/events/LockVotesEvent.java +++ b/src/main/java/de/thm/arsnova/events/LockVotesEvent.java @@ -17,27 +17,27 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.List; /** - * Fires whenever voting of multiple questions is disabled. + * Fires whenever voting of multiple contents is disabled. */ public class LockVotesEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private List<Question> questions; + private List<Content> contents; - public LockVotesEvent(Object source, Session session, List<Question> questions) { + public LockVotesEvent(Object source, Session session, List<Content> contents) { super(source, session); - this.questions = questions; + this.contents = contents; } - public List<Question> getQuestions() { - return this.questions; + public List<Content> getQuestions() { + return this.contents; } @Override diff --git a/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java b/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java index c2fd68a5237b2e0e73fc1ec9535405989d4ca579..9172a5b5a5b307be3ed77a881ee0a868872674f7 100644 --- a/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java +++ b/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java @@ -18,7 +18,7 @@ package de.thm.arsnova.events; import de.thm.arsnova.entities.Answer; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; @@ -33,13 +33,13 @@ public class NewAnswerEvent extends SessionEvent { private final User user; - private final Question question; + private final Content content; - public NewAnswerEvent(Object source, Session session, Answer answer, User user, Question question) { + public NewAnswerEvent(Object source, Session session, Answer answer, User user, Content content) { super(source, session); this.answer = answer; this.user = user; - this.question = question; + this.content = content; } @Override @@ -55,7 +55,7 @@ public class NewAnswerEvent extends SessionEvent { return user; } - public Question getQuestion() { - return question; + public Content getContent() { + return content; } } diff --git a/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java b/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java index 6ac4be12e84ad0c21b835f08f434aa72c9dfa11d..1a9e1616ec35819e5825b14b6ad1fb5609e82f92 100644 --- a/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java +++ b/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java @@ -17,25 +17,25 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; /** - * Fires whenever a new question is added. + * Fires whenever a new content is added. */ public class NewQuestionEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public NewQuestionEvent(Object source, Session session, Question question) { + public NewQuestionEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } - public Question getQuestion() { - return question; + public Content getQuestion() { + return content; } @Override diff --git a/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java index 86ff69ae311e784a077d40aa8eda3ba44627f341..64b51aea8780c1a4d5b68efd667b21f5eecc3e4d 100644 --- a/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java +++ b/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java @@ -17,7 +17,7 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; /** @@ -27,8 +27,8 @@ public class PiRoundCancelEvent extends PiRoundEndEvent { private static final long serialVersionUID = 1L; - public PiRoundCancelEvent(Object source, Session session, Question question) { - super(source, session, question); + public PiRoundCancelEvent(Object source, Session session, Content content) { + super(source, session, content); } @Override diff --git a/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java index 6fdc587e38791ae1c56c54e2fa329841dd93b9f2..dfaed2bb4fbf87b73fc27b9dae220de29b3bf29f 100644 --- a/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java +++ b/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java @@ -17,7 +17,7 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.HashMap; @@ -36,13 +36,13 @@ public class PiRoundDelayedStartEvent extends SessionEvent { private final String questionVariant; private int piRound; - public PiRoundDelayedStartEvent(Object source, Session session, Question question) { + public PiRoundDelayedStartEvent(Object source, Session session, Content content) { super(source, session); - this.questionId = question.get_id(); - this.startTime = question.getPiRoundStartTime(); - this.endTime = question.getPiRoundEndTime(); - this.questionVariant = question.getQuestionVariant(); - this.piRound = question.getPiRound(); + this.questionId = content.getId(); + this.startTime = content.getPiRoundStartTime(); + this.endTime = content.getPiRoundEndTime(); + this.questionVariant = content.getQuestionVariant(); + this.piRound = content.getPiRound(); } @Override diff --git a/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java index b87d12590bdd7e3667d7998367b86cbb4514b07d..335345185364f88e718c0f19d4b50c55520390f4 100644 --- a/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java +++ b/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java @@ -17,7 +17,7 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.HashMap; @@ -33,10 +33,10 @@ public class PiRoundEndEvent extends SessionEvent { private final String questionId; private final String questionVariant; - public PiRoundEndEvent(Object source, Session session, Question question) { + public PiRoundEndEvent(Object source, Session session, Content content) { super(source, session); - questionId = question.get_id(); - questionVariant = question.getQuestionVariant(); + questionId = content.getId(); + questionVariant = content.getQuestionVariant(); } @Override diff --git a/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java index 429aeb274c1b26fecbc1f779734316a9d2835ca1..96bd50df0d30637ea3c4fc3b87c65cba5b0bee70 100644 --- a/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java +++ b/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java @@ -17,7 +17,7 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.HashMap; @@ -33,10 +33,10 @@ public class PiRoundResetEvent extends SessionEvent { private final String questionId; private final String questionVariant; - public PiRoundResetEvent(Object source, Session session, Question question) { + public PiRoundResetEvent(Object source, Session session, Content content) { super(source, session); - questionId = question.get_id(); - questionVariant = question.getQuestionVariant(); + questionId = content.getId(); + questionVariant = content.getQuestionVariant(); } @Override diff --git a/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java b/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java index d04c709e8af2b89761f7bcf4d2de508558096f82..1d8e24c61ae3661a45b6d42b3f92d464df9f71e2 100644 --- a/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java +++ b/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java @@ -17,25 +17,25 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; /** - * Fires whenever a question is enabled, i.e., it becomes visible to students. + * Fires whenever a content is enabled, i.e., it becomes visible to students. */ public class UnlockQuestionEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public UnlockQuestionEvent(Object source, Session session, Question question) { + public UnlockQuestionEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } - public Question getQuestion() { - return this.question; + public Content getQuestion() { + return this.content; } @Override diff --git a/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java b/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java index b760b4ce5f4fb73e528432b782f9fbe3687d6cf0..153b702a6fbdd1177eb6fbb5fa920c8d99319215 100644 --- a/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java +++ b/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java @@ -17,27 +17,27 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.List; /** - * Fires whenever a set of questions are enabled, i.e., they become visible to students. + * Fires whenever a set of contents are enabled, i.e., they become visible to students. */ public class UnlockQuestionsEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private List<Question> questions; + private List<Content> contents; - public UnlockQuestionsEvent(Object source, Session session, List<Question> questions) { + public UnlockQuestionsEvent(Object source, Session session, List<Content> contents) { super(source, session); - this.questions = questions; + this.contents = contents; } - public List<Question> getQuestions() { - return this.questions; + public List<Content> getQuestions() { + return this.contents; } @Override diff --git a/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java b/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java index 69a1f45717e077339a28267700a43a8e6123703a..00bf47a4d8781e8368cc33fcd14a0c1f122314b3 100644 --- a/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java +++ b/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java @@ -17,36 +17,36 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.HashMap; import java.util.Map; /** - * Fires whenever voting on a question is enabled. + * Fires whenever voting on a content is enabled. */ public class UnlockVoteEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private final Question question; + private final Content content; - public UnlockVoteEvent(Object source, Session session, Question question) { + public UnlockVoteEvent(Object source, Session session, Content content) { super(source, session); - this.question = question; + this.content = content; } public String getQuestionId() { - return this.question.get_id(); + return this.content.getId(); } public String getQuestionVariant() { - return this.question.getQuestionVariant(); + return this.content.getQuestionVariant(); } public Boolean getVotingDisabled() { - return this.question.isVotingDisabled(); + return this.content.isVotingDisabled(); } public Map<String, Object> getVotingAdmission() { diff --git a/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java b/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java index c489aefcf5d8b22ab91e8d649985201e1f85a4cf..2dd3d4671849ac43cccf7a457ddc2e43a63feec7 100644 --- a/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java +++ b/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java @@ -17,27 +17,27 @@ */ package de.thm.arsnova.events; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import java.util.List; /** - * Fires whenever voting of multiple questions is enabled. + * Fires whenever voting of multiple contents is enabled. */ public class UnlockVotesEvent extends SessionEvent { private static final long serialVersionUID = 1L; - private List<Question> questions; + private List<Content> contents; - public UnlockVotesEvent(Object source, Session session, List<Question> questions) { + public UnlockVotesEvent(Object source, Session session, List<Content> contents) { super(source, session); - this.questions = questions; + this.contents = contents; } - public List<Question> getQuestions() { - return this.questions; + public List<Content> getQuestions() { + return this.contents; } @Override diff --git a/src/main/java/de/thm/arsnova/persistance/ContentRepository.java b/src/main/java/de/thm/arsnova/persistance/ContentRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..9c49aa7892f774b4eed4b6bb99b99bb6b70de7a2 --- /dev/null +++ b/src/main/java/de/thm/arsnova/persistance/ContentRepository.java @@ -0,0 +1,44 @@ +package de.thm.arsnova.persistance; + +import de.thm.arsnova.entities.Content; +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; + +import java.util.List; + +public interface ContentRepository { + List<Content> getQuestions(Object... keys); + Content getQuestion(String id); + Content saveQuestion(Session session, Content content); + List<Content> getSkillQuestionsForUsers(Session session); + List<Content> getSkillQuestionsForTeachers(Session session); + int getSkillQuestionCount(Session session); + List<String> getQuestionIds(Session session, User user); + int deleteQuestionWithAnswers(Content content); + int[] deleteAllQuestionsWithAnswers(Session session); + List<String> getUnAnsweredQuestionIds(Session session, User user); + Content updateQuestion(Content content); + List<Content> getLectureQuestionsForUsers(Session session); + List<Content> getLectureQuestionsForTeachers(Session session); + List<Content> getFlashcardsForUsers(Session session); + List<Content> getFlashcardsForTeachers(Session session); + List<Content> getPreparationQuestionsForUsers(Session session); + List<Content> getPreparationQuestionsForTeachers(Session session); + List<Content> getAllSkillQuestions(Session session); + int getLectureQuestionCount(Session session); + int getFlashcardCount(Session session); + int getPreparationQuestionCount(Session session); + void publishQuestions(Session session, boolean publish, List<Content> contents); + List<Content> publishAllQuestions(Session session, boolean publish); + List<String> getQuestionIdsBySubject(Session session, String questionVariant, String subject); + List<Content> getQuestionsByIds(List<String> ids, Session session); + void resetQuestionsRoundState(Session session, List<Content> contents); + void setVotingAdmissions(Session session, boolean disableVoting, List<Content> contents); + List<Content> setVotingAdmissionForAllQuestions(Session session, boolean disableVoting); + int[] deleteAllLectureQuestionsWithAnswers(Session session); + int[] deleteAllFlashcardsWithAnswers(Session session); + int[] deleteAllPreparationQuestionsWithAnswers(Session session); + List<String> getSubjects(Session session, String questionVariant); + List<String> getUnAnsweredLectureQuestionIds(Session session, User user); + List<String> getUnAnsweredPreparationQuestionIds(Session session, User user); +} diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..ba83397e9d4426d4c60c0e828cdfb050dfda1faf --- /dev/null +++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java @@ -0,0 +1,514 @@ +package de.thm.arsnova.persistance.couchdb; + +import de.thm.arsnova.dao.IDatabaseDao; +import de.thm.arsnova.entities.Content; +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; +import de.thm.arsnova.persistance.ContentRepository; +import de.thm.arsnova.persistance.LogEntryRepository; +import org.ektorp.ComplexKey; +import org.ektorp.CouchDbConnector; +import org.ektorp.DbAccessException; +import org.ektorp.DocumentNotFoundException; +import org.ektorp.UpdateConflictException; +import org.ektorp.ViewQuery; +import org.ektorp.ViewResult; +import org.ektorp.support.CouchDbRepositorySupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class CouchDbContentRepository extends CouchDbRepositorySupport<Content> implements ContentRepository { + private static final Logger logger = LoggerFactory.getLogger(CouchDbContentRepository.class); + + @Autowired + private LogEntryRepository dbLogger; + + @Autowired + private IDatabaseDao databaseDao; + + public CouchDbContentRepository(Class<Content> type, CouchDbConnector db, boolean createIfNotExists) { + super(type, db, createIfNotExists); + } + + @Cacheable("skillquestions") + @Override + public List<Content> getSkillQuestionsForUsers(final Session session) { + final List<Content> contents = new ArrayList<>(); + final List<Content> questions1 = getQuestions(session.getId(), "lecture", true); + final List<Content> questions2 = getQuestions(session.getId(), "preparation", true); + final List<Content> questions3 = getQuestions(session.getId(), "flashcard", true); + contents.addAll(questions1); + contents.addAll(questions2); + contents.addAll(questions3); + + return contents; + } + + @Cacheable("skillquestions") + @Override + public List<Content> getSkillQuestionsForTeachers(final Session session) { + return getQuestions(new Object[] {session.getId()}, session); + } + + @Override + public int getSkillQuestionCount(final Session session) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId())) + .endKey(ComplexKey.of(session.getId(), ComplexKey.emptyObject()))); + + return result.getSize(); + } + + @Caching(evict = {@CacheEvict(value = "skillquestions", key = "#session"), + @CacheEvict(value = "lecturequestions", key = "#session", condition = "#content.getQuestionVariant().equals('lecture')"), + @CacheEvict(value = "preparationquestions", key = "#session", condition = "#content.getQuestionVariant().equals('preparation')"), + @CacheEvict(value = "flashcardquestions", key = "#session", condition = "#content.getQuestionVariant().equals('flashcard')") }, + put = {@CachePut(value = "questions", key = "#content.id")}) + @Override + public Content saveQuestion(final Session session, final Content content) { + content.setSessionId(session.getId()); + try { + db.create(content); + + return content; + } catch (final IllegalArgumentException e) { + logger.error("Could not save content {}.", content, e); + } + + return null; + } + + /* TODO: Only evict cache entry for the content's session. This requires some refactoring. */ + @Caching(evict = {@CacheEvict(value = "skillquestions", allEntries = true), + @CacheEvict(value = "lecturequestions", allEntries = true, condition = "#content.getQuestionVariant().equals('lecture')"), + @CacheEvict(value = "preparationquestions", allEntries = true, condition = "#content.getQuestionVariant().equals('preparation')"), + @CacheEvict(value = "flashcardquestions", allEntries = true, condition = "#content.getQuestionVariant().equals('flashcard')") }, + put = {@CachePut(value = "questions", key = "#content.id")}) + @Override + public Content updateQuestion(final Content content) { + try { + /* TODO: Make sure that sessionId is valid before so the content does not need to be retrieved. */ + final Content oldContent = get(content.getId()); + content.setId(oldContent.getId()); + content.setRevision(oldContent.getRevision()); + content.updateRoundManagementState(); + update(content); + + return content; + } catch (final UpdateConflictException e) { + logger.error("Could not update content {}.", content, e); + } + + return null; + } + + @Cacheable("questions") + @Override + public Content getQuestion(final String id) { + try { + final Content content = get(id); + content.updateRoundManagementState(); + //content.setSessionKeyword(sessionRepository.getSessionFromId(content.getSessionId()).getKeyword()); + + return content; + } catch (final DocumentNotFoundException e) { + logger.error("Could not get question {}.", id, e); + } + + return null; + } + + @Override + public List<String> getQuestionIds(final Session session, final User user) { + return collectQuestionIds(db.queryView(createQuery("by_sessionid_variant_active").key(session.getId()))); + } + + /* TODO: Only evict cache entry for the content's session. This requires some refactoring. */ + @Caching(evict = { @CacheEvict(value = "questions", key = "#content.id"), + @CacheEvict(value = "skillquestions", allEntries = true), + @CacheEvict(value = "lecturequestions", allEntries = true, condition = "#content.getQuestionVariant().equals('lecture')"), + @CacheEvict(value = "preparationquestions", allEntries = true, condition = "#content.getQuestionVariant().equals('preparation')"), + @CacheEvict(value = "flashcardquestions", allEntries = true, condition = "#content.getQuestionVariant().equals('flashcard')") }) + @Override + public int deleteQuestionWithAnswers(final Content content) { + try { + int count = databaseDao.deleteAnswers(content); + db.delete(content); + dbLogger.log("delete", "type", "content", "answerCount", count); + + return count; + } catch (final IllegalArgumentException e) { + logger.error("Could not delete content {}.", content.getId(), e); + } + + return 0; + } + + @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), + @CacheEvict(value = "skillquestions", key = "#session"), + @CacheEvict(value = "lecturequestions", key = "#session"), + @CacheEvict(value = "preparationquestions", key = "#session"), + @CacheEvict(value = "flashcardquestions", key = "#session") }) + @Override + public int[] deleteAllQuestionsWithAnswers(final Session session) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId())) + .endKey(ComplexKey.of(session.getId(), ComplexKey.emptyObject())) + .reduce(false)); + + return deleteAllQuestionDocumentsWithAnswers(result); + } + + private int[] deleteAllQuestionDocumentsWithAnswers(final ViewResult viewResult) { + List<Content> contents = new ArrayList<>(); + for (final ViewResult.Row row : viewResult.getRows()) { + final Content q = new Content(); + q.setId(row.getId()); + q.setRevision(row.getValueAsNode().get("_rev").asText()); + contents.add(q); + } + + int[] count = databaseDao.deleteAllAnswersWithQuestions(contents); + dbLogger.log("delete", "type", "question", "questionCount", count[0]); + dbLogger.log("delete", "type", "answer", "answerCount", count[1]); + + return count; + } + + @Override + public List<String> getUnAnsweredQuestionIds(final Session session, final User user) { + final ViewResult result = db.queryView(createQuery("questionid_by_user_sessionid_variant") + .designDocId("_design/answer") + .startKey(ComplexKey.of(user.getUsername(), session.getId())) + .endKey(ComplexKey.of(user.getUsername(), session.getId(), ComplexKey.emptyObject()))); + List<String> answeredIds = new ArrayList<>(); + for (ViewResult.Row row : result.getRows()) { + answeredIds.add(row.getId()); + } + return collectUnansweredQuestionIds(getQuestionIds(session, user), answeredIds); + } + + @Override + public List<String> getUnAnsweredLectureQuestionIds(final Session session, final User user) { + final ViewResult result = db.queryView(createQuery("questionid_piround_by_user_sessionid_variant") + .designDocId("_design/answer") + .key(ComplexKey.of(user.getUsername(), session.getId(), "lecture"))); + Map<String, Integer> answeredQuestions = new HashMap<>(); + for (ViewResult.Row row : result.getRows()) { + answeredQuestions.put(row.getId(), row.getKeyAsNode().get(2).asInt()); + } + + return collectUnansweredQuestionIdsByPiRound(getLectureQuestionsForUsers(session), answeredQuestions); + } + + @Override + public List<String> getUnAnsweredPreparationQuestionIds(final Session session, final User user) { + final ViewResult result = db.queryView(createQuery("questionid_piround_by_user_sessionid_variant") + .designDocId("_design/answer") + .key(ComplexKey.of(user.getUsername(), session.getId(), "preparation"))); + Map<String, Integer> answeredQuestions = new HashMap<>(); + for (ViewResult.Row row : result.getRows()) { + answeredQuestions.put(row.getId(), row.getKeyAsNode().get(2).asInt()); + } + + return collectUnansweredQuestionIdsByPiRound(getPreparationQuestionsForUsers(session), answeredQuestions); + } + + @Cacheable("lecturequestions") + @Override + public List<Content> getLectureQuestionsForUsers(final Session session) { + return getQuestions(session.getId(), "lecture", true); + } + + @Override + public List<Content> getLectureQuestionsForTeachers(final Session session) { + return getQuestions(session.getId(), "lecture"); + } + + @Cacheable("flashcardquestions") + @Override + public List<Content> getFlashcardsForUsers(final Session session) { + return getQuestions(session.getId(), "flashcard", true); + } + + @Override + public List<Content> getFlashcardsForTeachers(final Session session) { + return getQuestions(session.getId(), "flashcard"); + } + + @Cacheable("preparationquestions") + @Override + public List<Content> getPreparationQuestionsForUsers(final Session session) { + return getQuestions(session.getId(), "preparation", true); + } + + @Override + public List<Content> getPreparationQuestionsForTeachers(final Session session) { + return getQuestions(session.getId(), "preparation"); + } + + @Override + public List<Content> getAllSkillQuestions(final Session session) { + return getQuestions(session.getId()); + } + + @Override + public List<Content> getQuestions(final Object... keys) { + Object[] endKeys = Arrays.copyOf(keys, keys.length + 1); + endKeys[keys.length] = ComplexKey.emptyObject(); + final List<Content> contents = db.queryView(createQuery("by_sessionid_variant_active") + .includeDocs(true) + .reduce(false) + .startKey(ComplexKey.of(keys)) + .endKey(ComplexKey.of(endKeys)), + Content.class); + for (Content content : contents) { + content.updateRoundManagementState(); + //content.setSessionKeyword(session.getKeyword()); + } + + return contents; + } + + @Override + public int getLectureQuestionCount(final Session session) { + /* TODO: reduce code duplication */ + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), "lecture")) + .endKey(ComplexKey.of(session.getId(), "lecture", ComplexKey.emptyObject()))); + + return result.isEmpty() ? 0 : result.getRows().get(0).getValueAsInt(); + } + + @Override + public int getFlashcardCount(final Session session) { + /* TODO: reduce code duplication */ + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), "flashcard")) + .endKey(ComplexKey.of(session.getId(), "flashcard", ComplexKey.emptyObject()))); + + return result.isEmpty() ? 0 : result.getRows().get(0).getValueAsInt(); + } + + @Override + public int getPreparationQuestionCount(final Session session) { + /* TODO: reduce code duplication */ + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), "preparation")) + .endKey(ComplexKey.of(session.getId(), "preparation", ComplexKey.emptyObject()))); + + return result.isEmpty() ? 0 : result.getRows().get(0).getValueAsInt(); + } + + /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ + @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), + @CacheEvict("skillquestions"), + @CacheEvict("lecturequestions"), + @CacheEvict(value = "answers", allEntries = true)}) + @Override + public int[] deleteAllLectureQuestionsWithAnswers(final Session session) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), "lecture")) + .endKey(ComplexKey.of(session.getId(), "lecture", ComplexKey.emptyObject())) + .reduce(false)); + + return deleteAllQuestionDocumentsWithAnswers(result); + } + + /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ + @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), + @CacheEvict("skillquestions"), + @CacheEvict("flashcardquestions"), + @CacheEvict(value = "answers", allEntries = true)}) + @Override + public int[] deleteAllFlashcardsWithAnswers(final Session session) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), "flashcard")) + .endKey(ComplexKey.of(session.getId(), "flashcard", ComplexKey.emptyObject())) + .reduce(false)); + + return deleteAllQuestionDocumentsWithAnswers(result); + } + + /* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */ + @Caching(evict = { @CacheEvict(value = "questions", allEntries = true), + @CacheEvict("skillquestions"), + @CacheEvict("preparationquestions"), + @CacheEvict(value = "answers", allEntries = true)}) + @Override + public int[] deleteAllPreparationQuestionsWithAnswers(final Session session) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), "preparation")) + .endKey(ComplexKey.of(session.getId(), "preparation", ComplexKey.emptyObject())) + .reduce(false)); + + return deleteAllQuestionDocumentsWithAnswers(result); + } + + private List<String> collectUnansweredQuestionIds( + final List<String> questions, + final List<String> answeredQuestions + ) { + final List<String> unanswered = new ArrayList<>(); + for (final String questionId : questions) { + if (!answeredQuestions.contains(questionId)) { + unanswered.add(questionId); + } + } + return unanswered; + } + + private List<String> collectUnansweredQuestionIdsByPiRound( + final List<Content> contents, + final Map<String, Integer> answeredQuestions + ) { + final List<String> unanswered = new ArrayList<>(); + + for (final Content content : contents) { + if (!"slide".equals(content.getQuestionType()) && (!answeredQuestions.containsKey(content.getId()) + || (answeredQuestions.containsKey(content.getId()) && answeredQuestions.get(content.getId()) != content.getPiRound()))) { + unanswered.add(content.getId()); + } + } + + return unanswered; + } + + private List<String> collectQuestionIds(final ViewResult viewResult) { + final List<String> ids = new ArrayList<>(); + for (final ViewResult.Row row : viewResult.getRows()) { + ids.add(row.getId()); + } + return ids; + } + + @Override + public List<Content> publishAllQuestions(final Session session, final boolean publish) { + final List<Content> contents = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId())) + .endKey(ComplexKey.of(session.getId(), ComplexKey.emptyObject())), + Content.class); + /* FIXME: caching */ + publishQuestions(session, publish, contents); + + return contents; + } + + @Caching(evict = { @CacheEvict(value = "contents", allEntries = true), + @CacheEvict(value = "skillquestions", key = "#session"), + @CacheEvict(value = "lecturequestions", key = "#session"), + @CacheEvict(value = "preparationquestions", key = "#session"), + @CacheEvict(value = "flashcardquestions", key = "#session") }) + @Override + public void publishQuestions(final Session session, final boolean publish, List<Content> contents) { + for (final Content content : contents) { + content.setActive(publish); + } + try { + db.executeBulk(contents); + } catch (final DbAccessException e) { + logger.error("Could not bulk publish all contents.", e); + } + } + + @Override + public List<Content> setVotingAdmissionForAllQuestions(final Session session, final boolean disableVoting) { + final List<Content> contents = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId())) + .endKey(ComplexKey.of(session.getId(), ComplexKey.emptyObject())) + .includeDocs(true), + Content.class); + /* FIXME: caching */ + setVotingAdmissions(session, disableVoting, contents); + + return contents; + } + + @Caching(evict = { @CacheEvict(value = "contents", allEntries = true), + @CacheEvict(value = "skillquestions", key = "#session"), + @CacheEvict(value = "lecturequestions", key = "#session"), + @CacheEvict(value = "preparationquestions", key = "#session"), + @CacheEvict(value = "flashcardquestions", key = "#session") }) + @Override + public void setVotingAdmissions(final Session session, final boolean disableVoting, List<Content> contents) { + for (final Content q : contents) { + if (!"flashcard".equals(q.getQuestionType())) { + q.setVotingDisabled(disableVoting); + } + } + + try { + db.executeBulk(contents); + } catch (final DbAccessException e) { + logger.error("Could not bulk set voting admission for all contents.", e); + } + } + + /* TODO: remove if this method is no longer used */ + @Override + public List<String> getQuestionIdsBySubject(Session session, String questionVariant, String subject) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), questionVariant, 1, subject)) + .endKey(ComplexKey.of(session.getId(), questionVariant, 1, subject, ComplexKey.emptyObject()))); + + List<String> qids = new ArrayList<>(); + + for (final ViewResult.Row row : result.getRows()) { + final String s = row.getId(); + qids.add(s); + } + + return qids; + } + + @Override + public List<Content> getQuestionsByIds(List<String> ids, final Session session) { + return db.queryView(new ViewQuery().allDocs().keys(ids).includeDocs(true), Content.class); + } + + @Override + public List<String> getSubjects(Session session, String questionVariant) { + final ViewResult result = db.queryView(createQuery("by_sessionid_variant_active") + .startKey(ComplexKey.of(session.getId(), questionVariant)) + .endKey(ComplexKey.of(session.getId(), questionVariant, ComplexKey.emptyObject()))); + + Set<String> uniqueSubjects = new HashSet<>(); + + for (final ViewResult.Row row : result.getRows()) { + uniqueSubjects.add(row.getKeyAsNode().get(3).asText()); + } + + return new ArrayList<>(uniqueSubjects); + } + + @Caching(evict = { @CacheEvict(value = "contents", allEntries = true), + @CacheEvict(value = "skillquestions", key = "#session"), + @CacheEvict(value = "lecturequestions", key = "#session"), + @CacheEvict(value = "preparationquestions", key = "#session"), + @CacheEvict(value = "flashcardquestions", key = "#session") }) + @Override + public void resetQuestionsRoundState(final Session session, List<Content> contents) { + for (final Content q : contents) { + q.setSessionId(session.getId()); + q.resetQuestionState(); + } + try { + db.executeBulk(contents); + } catch (final DbAccessException e) { + logger.error("Could not bulk reset all contents round state.", e); + } + } +} diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionRepository.java index e23d2ca29cb9e18dae6f4eb798a4aa33ca0bbb68..0d0da5868042151d096c7c8242b7661560eca471 100644 --- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionRepository.java +++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionRepository.java @@ -292,7 +292,7 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> // // 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, ImportExportSession.ImportExportQuestion> mapping = new HashMap<>(); +// Map<Document, ImportExportSession.ImportExportContent> mapping = new HashMap<>(); // // Later, generate all answer documents // List<Document> answers = new ArrayList<>(); // // We can then push answers together with comments in one large bulk request @@ -301,7 +301,7 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> // List<Document> motds = new ArrayList<>(); // try { // // add session id to all questions and generate documents -// for (ImportExportSession.ImportExportQuestion question : importSession.getQuestions()) { +// for (ImportExportSession.ImportExportContent question : importSession.getQuestions()) { // Document doc = toQuestionDocument(session, question); // question.setSessionId(session.getId()); // questions.add(doc); @@ -310,11 +310,11 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> // database.bulkSaveDocuments(questions.toArray(new Document[questions.size()])); // // // bulk import answers together with interposed questions -// for (Map.Entry<Document, ImportExportSession.ImportExportQuestion> entry : mapping.entrySet()) { +// for (Map.Entry<Document, ImportExportSession.ImportExportContent> entry : mapping.entrySet()) { // final Document doc = entry.getKey(); -// final ImportExportSession.ImportExportQuestion question = entry.getValue(); +// final ImportExportSession.ImportExportContent question = entry.getValue(); // question.setId(doc.getId()); -// question.set_rev(doc.getRev()); +// question.setRevision(doc.getRev()); // for (de.thm.arsnova.entities.transport.Answer answer : question.getAnswers()) { // final Answer a = answer.generateAnswerEntity(user, question); // final Document answerDoc = new Document(); @@ -379,8 +379,8 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> // ImportExportSession importExportSession = new ImportExportSession(); // Session session = getDatabaseDao().getSessionFromKeyword(sessionkey); // importExportSession.setSessionFromSessionObject(session); -// List<Question> questionList = getDatabaseDao().getAllSkillQuestions(session); -// for (Question question : questionList) { +// List<Content> questionList = getDatabaseDao().getAllSkillQuestions(session); +// for (Content question : questionList) { // List<de.thm.arsnova.entities.transport.Answer> answerList = new ArrayList<>(); // if (withAnswers) { // for (Answer a : this.getDatabaseDao().getAllAnswers(question)) { @@ -424,7 +424,7 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> unreadComments++; } } - for (ImportExportSession.ImportExportQuestion question : importExportSession.getQuestions()) { + for (ImportExportSession.ImportExportContent question : importExportSession.getQuestions()) { numAnswers += question.getAnswers().size(); if (question.getAnswers().isEmpty()) { numUnanswered++; @@ -506,7 +506,7 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> private List<SessionInfo> getInfosForSessions(final List<Session> sessions) { /* TODO: migrate to new view */ List<String> sessionIds = sessions.stream().map(Session::getId).collect(Collectors.toList()); - final ViewQuery questionCountView = createQuery("by_sessionid").designDocId("_design/content") + final ViewQuery questionCountView = createQuery("by_sessionid").designDocId("_design/Content") .group(true).keys(sessionIds); final ViewQuery answerCountView = createQuery("by_sessionid").designDocId("_design/answer") .group(true).keys(sessionIds); @@ -521,7 +521,7 @@ public class CouchDbSessionRepository extends CouchDbRepositorySupport<Session> private List<SessionInfo> getInfosForVisitedSessions(final List<Session> sessions, final User user) { final ViewQuery answeredQuestionsView = createQuery("by_user_sessionid").designDocId("_design/answer") .keys(sessions.stream().map(session -> ComplexKey.of(user.getUsername(), session.getId())).collect(Collectors.toList())); - final ViewQuery questionIdsView = createQuery("by_sessionid").designDocId("_design/content") + final ViewQuery questionIdsView = createQuery("by_sessionid").designDocId("_design/Content") .keys(sessions.stream().map(Session::getId).collect(Collectors.toList())); return getVisitedSessionInfoData(sessions, answeredQuestionsView, questionIdsView); diff --git a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java index 9a18beb4638c8a8429f8fe663eb168363e919d8f..7b65c1c95fe3f05b37d3797331d1a294268db896 100644 --- a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java +++ b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java @@ -19,11 +19,12 @@ package de.thm.arsnova.security; import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.Comment; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.persistance.CommentRepository; +import de.thm.arsnova.persistance.ContentRepository; import de.thm.arsnova.persistance.SessionRepository; import org.pac4j.oauth.profile.facebook.FacebookProfile; import org.pac4j.oauth.profile.google2.Google2Profile; @@ -55,6 +56,9 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { @Autowired private CommentRepository commentRepository; + @Autowired + private ContentRepository contentRepository; + @Override public boolean hasPermission( final Authentication authentication, @@ -88,7 +92,7 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { && checkSessionPermission(username, targetId, permission)) { return true; } else if ( - "question".equals(targetType) + "content".equals(targetType) && checkQuestionPermission(username, targetId, permission) ) { return true; @@ -125,9 +129,9 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final Object permission ) { if (permission instanceof String && "owner".equals(permission)) { - final Question question = dao.getQuestion(targetId.toString()); - if (question != null) { - final Session session = sessionRepository.getSessionFromId(question.getSessionId()); + final Content content = contentRepository.getQuestion(targetId.toString()); + if (content != null) { + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); return session != null && session.getCreator().equals(username); } diff --git a/src/main/java/de/thm/arsnova/services/QuestionService.java b/src/main/java/de/thm/arsnova/services/ContentService.java similarity index 69% rename from src/main/java/de/thm/arsnova/services/QuestionService.java rename to src/main/java/de/thm/arsnova/services/ContentService.java index 2ba43ee681f1cef938065393cfb244b6b9a47df1..c08d1ccbf8e3837132e5b536abeb5ff23139cb96 100644 --- a/src/main/java/de/thm/arsnova/services/QuestionService.java +++ b/src/main/java/de/thm/arsnova/services/ContentService.java @@ -22,7 +22,7 @@ import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.Comment; import de.thm.arsnova.entities.CommentReadingCount; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; import de.thm.arsnova.events.*; @@ -31,6 +31,7 @@ import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.persistance.CommentRepository; +import de.thm.arsnova.persistance.ContentRepository; import de.thm.arsnova.persistance.SessionRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +54,7 @@ import java.util.TimerTask; * Performs all question, comment, and answer related operations. */ @Service -public class QuestionService implements IQuestionService, ApplicationEventPublisherAware { +public class ContentService implements IContentService, ApplicationEventPublisherAware { @Autowired private IDatabaseDao databaseDao; @@ -67,6 +68,9 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Autowired private CommentRepository commentRepository; + @Autowired + private ContentRepository contentRepository; + @Autowired private ImageUtils imageUtils; @@ -75,7 +79,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis private ApplicationEventPublisher publisher; - private static final Logger logger = LoggerFactory.getLogger(QuestionService.class); + private static final Logger logger = LoggerFactory.getLogger(ContentService.class); private HashMap<String, Timer> timerList = new HashMap<>(); @@ -85,13 +89,13 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public List<Question> getSkillQuestions(final String sessionkey) { + public List<Content> getSkillQuestions(final String sessionkey) { final Session session = getSession(sessionkey); final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getSkillQuestionsForTeachers(session); + return contentRepository.getSkillQuestionsForTeachers(session); } else { - return databaseDao.getSkillQuestionsForUsers(session); + return contentRepository.getSkillQuestionsForUsers(session); } } @@ -99,33 +103,34 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @PreAuthorize("isAuthenticated()") public int getSkillQuestionCount(final String sessionkey) { final Session session = sessionRepository.getSessionFromKeyword(sessionkey); - return databaseDao.getSkillQuestionCount(session); + return contentRepository.getSkillQuestionCount(session); } + /* FIXME: #content.getSessionKeyword() cannot be checked since keyword is no longer set for content. */ @Override - @PreAuthorize("isAuthenticated() and hasPermission(#question.getSessionKeyword(), 'session', 'owner')") - public Question saveQuestion(final Question question) { - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); - question.setSessionId(session.getId()); - question.setTimestamp(System.currentTimeMillis() / 1000L); + @PreAuthorize("isAuthenticated() and hasPermission(#content.getSessionKeyword(), 'session', 'owner')") + public Content saveQuestion(final Content content) { + final Session session = sessionRepository.getSessionFromKeyword(content.getSessionKeyword()); + content.setSessionId(session.getId()); + content.setTimestamp(System.currentTimeMillis() / 1000L); - if ("freetext".equals(question.getQuestionType())) { - question.setPiRound(0); - } else if (question.getPiRound() < 1 || question.getPiRound() > 2) { - question.setPiRound(1); + if ("freetext".equals(content.getQuestionType())) { + content.setPiRound(0); + } else if (content.getPiRound() < 1 || content.getPiRound() > 2) { + content.setPiRound(1); } // convert imageurl to base64 if neccessary - if ("grid".equals(question.getQuestionType()) && !question.getImage().startsWith("http")) { + if ("grid".equals(content.getQuestionType()) && !content.getImage().startsWith("http")) { // base64 adds offset to filesize, formula taken from: http://en.wikipedia.org/wiki/Base64#MIME - final int fileSize = (int) ((question.getImage().length() - 814) / 1.37); + final int fileSize = (int) ((content.getImage().length() - 814) / 1.37); if (fileSize > uploadFileSizeByte) { logger.error("Could not save file. File is too large with {} Byte.", fileSize); throw new BadRequestException(); } } - final Question result = databaseDao.saveQuestion(session, question); + final Content result = contentRepository.saveQuestion(session, content); final NewQuestionEvent event = new NewQuestionEvent(this, session, result); this.publisher.publishEvent(event); @@ -149,8 +154,8 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public Question getQuestion(final String id) { - final Question result = databaseDao.getQuestion(id); + public Content getQuestion(final String id) { + final Content result = contentRepository.getQuestion(id); if (result == null) { return null; } @@ -163,20 +168,20 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void deleteQuestion(final String questionId) { - final Question question = databaseDao.getQuestion(questionId); - if (question == null) { + final Content content = contentRepository.getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); if (session == null) { throw new UnauthorizedException(); } - databaseDao.deleteQuestionWithAnswers(question); + contentRepository.deleteQuestionWithAnswers(content); - final DeleteQuestionEvent event = new DeleteQuestionEvent(this, session, question); + final DeleteQuestionEvent event = new DeleteQuestionEvent(this, session, content); this.publisher.publishEvent(event); } @@ -184,17 +189,17 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @PreAuthorize("isAuthenticated() and hasPermission(#sessionKeyword, 'session', 'owner')") public void deleteAllQuestions(final String sessionKeyword) { final Session session = getSessionWithAuthCheck(sessionKeyword); - databaseDao.deleteAllQuestionsWithAnswers(session); + contentRepository.deleteAllQuestionsWithAnswers(session); final DeleteAllQuestionsEvent event = new DeleteAllQuestionsEvent(this, session); this.publisher.publishEvent(event); } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void startNewPiRound(final String questionId, User user) { - final Question question = databaseDao.getQuestion(questionId); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Content content = contentRepository.getQuestion(questionId); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); if (null == user) { user = userService.getCurrentUser(); @@ -202,57 +207,57 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis cancelDelayedPiRoundChange(questionId); - question.setPiRoundEndTime(0); - question.setVotingDisabled(true); - question.updateRoundManagementState(); - update(question, user); + content.setPiRoundEndTime(0); + content.setVotingDisabled(true); + content.updateRoundManagementState(); + update(content, user); - this.publisher.publishEvent(new PiRoundEndEvent(this, session, question)); + this.publisher.publishEvent(new PiRoundEndEvent(this, session, content)); } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void startNewPiRoundDelayed(final String questionId, final int time) { - final IQuestionService questionService = this; + final IContentService contentService = this; final User user = userService.getCurrentUser(); - final Question question = databaseDao.getQuestion(questionId); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Content content = contentRepository.getQuestion(questionId); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); final Date date = new Date(); final Timer timer = new Timer(); final Date endDate = new Date(date.getTime() + (time * 1000)); - question.updateRoundStartVariables(date, endDate); - update(question); + content.updateRoundStartVariables(date, endDate); + update(content); - this.publisher.publishEvent(new PiRoundDelayedStartEvent(this, session, question)); + this.publisher.publishEvent(new PiRoundDelayedStartEvent(this, session, content)); timerList.put(questionId, timer); timer.schedule(new TimerTask() { @Override public void run() { - questionService.startNewPiRound(questionId, user); + contentService.startNewPiRound(questionId, user); } }, endDate); } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void cancelPiRoundChange(final String questionId) { - final Question question = databaseDao.getQuestion(questionId); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Content content = contentRepository.getQuestion(questionId); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); cancelDelayedPiRoundChange(questionId); - question.resetRoundManagementState(); + content.resetRoundManagementState(); - if (0 == question.getPiRound() || 1 == question.getPiRound()) { - question.setPiRoundFinished(false); + if (0 == content.getPiRound() || 1 == content.getPiRound()) { + content.setPiRoundFinished(false); } else { - question.setPiRound(1); - question.setPiRoundFinished(true); + content.setPiRound(1); + content.setPiRoundFinished(true); } - update(question); - this.publisher.publishEvent(new PiRoundCancelEvent(this, session, question)); + update(content); + this.publisher.publishEvent(new PiRoundCancelEvent(this, session, content)); } @Override @@ -267,60 +272,60 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void resetPiRoundState(final String questionId) { - final Question question = databaseDao.getQuestion(questionId); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Content content = contentRepository.getQuestion(questionId); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); cancelDelayedPiRoundChange(questionId); - if ("freetext".equals(question.getQuestionType())) { - question.setPiRound(0); + if ("freetext".equals(content.getQuestionType())) { + content.setPiRound(0); } else { - question.setPiRound(1); + content.setPiRound(1); } - question.resetRoundManagementState(); - databaseDao.deleteAnswers(question); - update(question); - this.publisher.publishEvent(new PiRoundResetEvent(this, session, question)); + content.resetRoundManagementState(); + databaseDao.deleteAnswers(content); + update(content); + this.publisher.publishEvent(new PiRoundResetEvent(this, session, content)); } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void setVotingAdmission(final String questionId, final boolean disableVoting) { - final Question question = databaseDao.getQuestion(questionId); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); - question.setVotingDisabled(disableVoting); + final Content content = contentRepository.getQuestion(questionId); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); + content.setVotingDisabled(disableVoting); - if (!disableVoting && !question.isActive()) { - question.setActive(true); - update(question); + if (!disableVoting && !content.isActive()) { + content.setActive(true); + update(content); } else { - databaseDao.updateQuestion(question); + contentRepository.updateQuestion(content); } NovaEvent event; if (disableVoting) { - event = new LockVoteEvent(this, session, question); + event = new LockVoteEvent(this, session, content); } else { - event = new UnlockVoteEvent(this, session, question); + event = new UnlockVoteEvent(this, session, content); } this.publisher.publishEvent(event); } @Override @PreAuthorize("isAuthenticated()") - public void setVotingAdmissions(final String sessionkey, final boolean disableVoting, List<Question> questions) { + public void setVotingAdmissions(final String sessionkey, final boolean disableVoting, List<Content> contents) { final User user = getCurrentUser(); final Session session = getSession(sessionkey); if (!session.isCreator(user)) { throw new UnauthorizedException(); } - databaseDao.setVotingAdmissions(session, disableVoting, questions); + contentRepository.setVotingAdmissions(session, disableVoting, contents); NovaEvent event; if (disableVoting) { - event = new LockVotesEvent(this, session, questions); + event = new LockVotesEvent(this, session, contents); } else { - event = new UnlockVotesEvent(this, session, questions); + event = new UnlockVotesEvent(this, session, contents); } this.publisher.publishEvent(event); } @@ -333,12 +338,12 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis if (!session.isCreator(user)) { throw new UnauthorizedException(); } - final List<Question> questions = databaseDao.setVotingAdmissionForAllQuestions(session, disableVoting); + final List<Content> contents = contentRepository.setVotingAdmissionForAllQuestions(session, disableVoting); NovaEvent event; if (disableVoting) { - event = new LockVotesEvent(this, session, questions); + event = new LockVotesEvent(this, session, contents); } else { - event = new UnlockVotesEvent(this, session, questions); + event = new UnlockVotesEvent(this, session, contents); } this.publisher.publishEvent(event); } @@ -382,12 +387,12 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis } @Override - @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'question', 'owner')") + @PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')") public void deleteAnswers(final String questionId) { - final Question question = databaseDao.getQuestion(questionId); - question.resetQuestionState(); - databaseDao.updateQuestion(question); - databaseDao.deleteAnswers(question); + final Content content = contentRepository.getQuestion(questionId); + content.resetQuestionState(); + contentRepository.updateQuestion(content); + databaseDao.deleteAnswers(content); } @Override @@ -395,7 +400,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis public List<String> getUnAnsweredQuestionIds(final String sessionKey) { final User user = getCurrentUser(); final Session session = getSession(sessionKey); - return databaseDao.getUnAnsweredQuestionIds(session, user); + return contentRepository.getUnAnsweredQuestionIds(session, user); } private User getCurrentUser() { @@ -409,11 +414,11 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") public Answer getMyAnswer(final String questionId) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } - return databaseDao.getMyAnswer(userService.getCurrentUser(), questionId, question.getPiRound()); + return databaseDao.getMyAnswer(userService.getCurrentUser(), questionId, content.getPiRound()); } @Override @@ -435,74 +440,74 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") public List<Answer> getAnswers(final String questionId, final int piRound, final int offset, final int limit) { - final Question question = databaseDao.getQuestion(questionId); - if (question == null) { + final Content content = contentRepository.getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } - return "freetext".equals(question.getQuestionType()) + return "freetext".equals(content.getQuestionType()) ? getFreetextAnswers(questionId, offset, limit) - : databaseDao.getAnswers(question, piRound); + : databaseDao.getAnswers(content, piRound); } @Override @PreAuthorize("isAuthenticated()") public List<Answer> getAnswers(final String questionId, final int offset, final int limit) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } - if ("freetext".equals(question.getQuestionType())) { + if ("freetext".equals(content.getQuestionType())) { return getFreetextAnswers(questionId, offset, limit); } else { - return databaseDao.getAnswers(question); + return databaseDao.getAnswers(content); } } @Override @PreAuthorize("isAuthenticated()") public List<Answer> getAllAnswers(final String questionId, final int offset, final int limit) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } - if ("freetext".equals(question.getQuestionType())) { + if ("freetext".equals(content.getQuestionType())) { return getFreetextAnswers(questionId, offset, limit); } else { - return databaseDao.getAllAnswers(question); + return databaseDao.getAllAnswers(content); } } @Override @PreAuthorize("isAuthenticated()") public int getAnswerCount(final String questionId) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { return 0; } - if ("freetext".equals(question.getQuestionType())) { - return databaseDao.getTotalAnswerCountByQuestion(question); + if ("freetext".equals(content.getQuestionType())) { + return databaseDao.getTotalAnswerCountByQuestion(content); } else { - return databaseDao.getAnswerCount(question, question.getPiRound()); + return databaseDao.getAnswerCount(content, content.getPiRound()); } } @Override @PreAuthorize("isAuthenticated()") public int getAnswerCount(final String questionId, final int piRound) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { return 0; } - return databaseDao.getAnswerCount(question, piRound); + return databaseDao.getAnswerCount(content, piRound); } @Override @PreAuthorize("isAuthenticated()") public int getAbstentionAnswerCount(final String questionId) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { return 0; } @@ -512,12 +517,12 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") public int getTotalAnswerCountByQuestion(final String questionId) { - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { return 0; } - return databaseDao.getTotalAnswerCountByQuestion(question); + return databaseDao.getTotalAnswerCountByQuestion(content); } @Override @@ -539,29 +544,29 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @PreAuthorize("isAuthenticated()") public List<Answer> getMyAnswers(final String sessionKey) { final Session session = getSession(sessionKey); - // Load questions first because we are only interested in answers of the latest piRound. - final List<Question> questions = databaseDao.getSkillQuestionsForUsers(session); - final Map<String, Question> questionIdToQuestion = new HashMap<>(); - for (final Question question : questions) { - questionIdToQuestion.put(question.get_id(), question); + // Load contents first because we are only interested in answers of the latest piRound. + final List<Content> contents = contentRepository.getSkillQuestionsForUsers(session); + final Map<String, Content> questionIdToQuestion = new HashMap<>(); + for (final Content content : contents) { + questionIdToQuestion.put(content.getId(), content); } /* filter answers by active piRound per question */ final List<Answer> answers = databaseDao.getMyAnswers(userService.getCurrentUser(), session); final List<Answer> filteredAnswers = new ArrayList<>(); for (final Answer answer : answers) { - final Question question = questionIdToQuestion.get(answer.getQuestionId()); - if (question == null) { - // Question is not present. Most likely it has been locked by the + final Content content = questionIdToQuestion.get(answer.getQuestionId()); + if (content == null) { + // Content is not present. Most likely it has been locked by the // Session's creator. Locked Questions do not appear in this list. continue; } - if (0 == answer.getPiRound() && !"freetext".equals(question.getQuestionType())) { + if (0 == answer.getPiRound() && !"freetext".equals(content.getQuestionType())) { answer.setPiRound(1); } - // discard all answers that aren't in the same piRound as the question - if (answer.getPiRound() == question.getPiRound()) { + // discard all answers that aren't in the same piRound as the content + if (answer.getPiRound() == content.getPiRound()) { filteredAnswers.add(answer); } } @@ -641,36 +646,36 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public Question update(final Question question) { + public Content update(final Content content) { final User user = userService.getCurrentUser(); - return update(question, user); + return update(content, user); } @Override @PreAuthorize("isAuthenticated()") - public Question update(final Question question, User user) { - final Question oldQuestion = databaseDao.getQuestion(question.get_id()); - if (null == oldQuestion) { + public Content update(final Content content, User user) { + final Content oldContent = contentRepository.getQuestion(content.getId()); + if (null == oldContent) { throw new NotFoundException(); } - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); if (user == null || session == null || !session.isCreator(user)) { throw new UnauthorizedException(); } - if ("freetext".equals(question.getQuestionType())) { - question.setPiRound(0); - } else if (question.getPiRound() < 1 || question.getPiRound() > 2) { - question.setPiRound(oldQuestion.getPiRound() > 0 ? oldQuestion.getPiRound() : 1); + if ("freetext".equals(content.getQuestionType())) { + content.setPiRound(0); + } else if (content.getPiRound() < 1 || content.getPiRound() > 2) { + content.setPiRound(oldContent.getPiRound() > 0 ? oldContent.getPiRound() : 1); } - final Question result = databaseDao.updateQuestion(question); + final Content result = contentRepository.updateQuestion(content); - if (!oldQuestion.isActive() && question.isActive()) { + if (!oldContent.isActive() && content.isActive()) { final UnlockQuestionEvent event = new UnlockQuestionEvent(this, session, result); this.publisher.publishEvent(event); - } else if (oldQuestion.isActive() && !question.isActive()) { + } else if (oldContent.isActive() && !content.isActive()) { final LockQuestionEvent event = new LockQuestionEvent(this, session, result); this.publisher.publishEvent(event); } @@ -681,26 +686,26 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @PreAuthorize("isAuthenticated()") public Answer saveAnswer(final String questionId, final de.thm.arsnova.entities.transport.Answer answer) { final User user = getCurrentUser(); - final Question question = getQuestion(questionId); - if (question == null) { + final Content content = getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } - Answer theAnswer = answer.generateAnswerEntity(user, question); - if ("freetext".equals(question.getQuestionType())) { + Answer theAnswer = answer.generateAnswerEntity(user, content); + if ("freetext".equals(content.getQuestionType())) { imageUtils.generateThumbnailImage(theAnswer); - if (question.isFixedAnswer() && question.getText() != null) { + if (content.isFixedAnswer() && content.getText() != null) { theAnswer.setAnswerTextRaw(theAnswer.getAnswerText()); - if (question.isStrictMode()) { - question.checkTextStrictOptions(theAnswer); + if (content.isStrictMode()) { + content.checkTextStrictOptions(theAnswer); } - theAnswer.setQuestionValue(question.evaluateCorrectAnswerFixedText(theAnswer.getAnswerTextRaw())); - theAnswer.setSuccessfulFreeTextAnswer(question.isSuccessfulFreeTextAnswer(theAnswer.getAnswerTextRaw())); + theAnswer.setQuestionValue(content.evaluateCorrectAnswerFixedText(theAnswer.getAnswerTextRaw())); + theAnswer.setSuccessfulFreeTextAnswer(content.isSuccessfulFreeTextAnswer(theAnswer.getAnswerTextRaw())); } } - return databaseDao.saveAnswer(theAnswer, user, question, getSession(question.getSessionKeyword())); + return databaseDao.saveAnswer(theAnswer, user, content, sessionRepository.getSessionFromId(content.getSessionId())); } @Override @@ -712,14 +717,14 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis throw new UnauthorizedException(); } - final Question question = getQuestion(answer.getQuestionId()); - if ("freetext".equals(question.getQuestionType())) { + final Content content = getQuestion(answer.getQuestionId()); + if ("freetext".equals(content.getQuestionType())) { imageUtils.generateThumbnailImage(realAnswer); - question.checkTextStrictOptions(realAnswer); + content.checkTextStrictOptions(realAnswer); } final Answer result = databaseDao.updateAnswer(realAnswer); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); - this.publisher.publishEvent(new NewAnswerEvent(this, session, result, user, question)); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); + this.publisher.publishEvent(new NewAnswerEvent(this, session, result, user, content)); return result; } @@ -727,66 +732,66 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") public void deleteAnswer(final String questionId, final String answerId) { - final Question question = databaseDao.getQuestion(questionId); - if (question == null) { + final Content content = contentRepository.getQuestion(questionId); + if (content == null) { throw new NotFoundException(); } final User user = userService.getCurrentUser(); - final Session session = sessionRepository.getSessionFromKeyword(question.getSessionKeyword()); + final Session session = sessionRepository.getSessionFromId(content.getSessionId()); if (user == null || session == null || !session.isCreator(user)) { throw new UnauthorizedException(); } databaseDao.deleteAnswer(answerId); - this.publisher.publishEvent(new DeleteAnswerEvent(this, session, question)); + this.publisher.publishEvent(new DeleteAnswerEvent(this, session, content)); } @Override @PreAuthorize("isAuthenticated()") - public List<Question> getLectureQuestions(final String sessionkey) { + public List<Content> getLectureQuestions(final String sessionkey) { final Session session = getSession(sessionkey); final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getLectureQuestionsForTeachers(session); + return contentRepository.getLectureQuestionsForTeachers(session); } else { - return databaseDao.getLectureQuestionsForUsers(session); + return contentRepository.getLectureQuestionsForUsers(session); } } @Override @PreAuthorize("isAuthenticated()") - public List<Question> getFlashcards(final String sessionkey) { + public List<Content> getFlashcards(final String sessionkey) { final Session session = getSession(sessionkey); final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getFlashcardsForTeachers(session); + return contentRepository.getFlashcardsForTeachers(session); } else { - return databaseDao.getFlashcardsForUsers(session); + return contentRepository.getFlashcardsForUsers(session); } } @Override @PreAuthorize("isAuthenticated()") - public List<Question> getPreparationQuestions(final String sessionkey) { + public List<Content> getPreparationQuestions(final String sessionkey) { final Session session = getSession(sessionkey); final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getPreparationQuestionsForTeachers(session); + return contentRepository.getPreparationQuestionsForTeachers(session); } else { - return databaseDao.getPreparationQuestionsForUsers(session); + return contentRepository.getPreparationQuestionsForUsers(session); } } @Override @PreAuthorize("isAuthenticated()") - public List<Question> replaceImageData(final List<Question> questions) { - for (Question q : questions) { + public List<Content> replaceImageData(final List<Content> contents) { + for (Content q : contents) { if (q.getImage() != null && q.getImage().startsWith("data:image/")) { q.setImage("true"); } } - return questions; + return contents; } private Session getSession(final String sessionkey) { @@ -800,19 +805,19 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") public int getLectureQuestionCount(final String sessionkey) { - return databaseDao.getLectureQuestionCount(getSession(sessionkey)); + return contentRepository.getLectureQuestionCount(getSession(sessionkey)); } @Override @PreAuthorize("isAuthenticated()") public int getFlashcardCount(final String sessionkey) { - return databaseDao.getFlashcardCount(getSession(sessionkey)); + return contentRepository.getFlashcardCount(getSession(sessionkey)); } @Override @PreAuthorize("isAuthenticated()") public int getPreparationQuestionCount(final String sessionkey) { - return databaseDao.getPreparationQuestionCount(getSession(sessionkey)); + return contentRepository.getPreparationQuestionCount(getSession(sessionkey)); } @Override @@ -832,15 +837,15 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override public Map<String, Object> getAnswerAndAbstentionCountInternal(final String questionId) { - final Question question = getQuestion(questionId); + final Content content = getQuestion(questionId); HashMap<String, Object> map = new HashMap<>(); - if (question == null) { + if (content == null) { return null; } map.put("_id", questionId); - map.put("answers", databaseDao.getAnswerCount(question, question.getPiRound())); + map.put("answers", databaseDao.getAnswerCount(content, content.getPiRound())); map.put("abstentions", databaseDao.getAbstentionAnswerCount(questionId)); return map; @@ -867,28 +872,28 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis */ @Override public int countFlashcardsForUserInternal(final String sessionkey) { - return databaseDao.getFlashcardsForUsers(getSession(sessionkey)).size(); + return contentRepository.getFlashcardsForUsers(getSession(sessionkey)).size(); } @Override @PreAuthorize("isAuthenticated()") public void deleteLectureQuestions(final String sessionkey) { final Session session = getSessionWithAuthCheck(sessionkey); - databaseDao.deleteAllLectureQuestionsWithAnswers(session); + contentRepository.deleteAllLectureQuestionsWithAnswers(session); } @Override @PreAuthorize("isAuthenticated()") public void deleteFlashcards(final String sessionkey) { final Session session = getSessionWithAuthCheck(sessionkey); - databaseDao.deleteAllFlashcardsWithAnswers(session); + contentRepository.deleteAllFlashcardsWithAnswers(session); } @Override @PreAuthorize("isAuthenticated()") public void deletePreparationQuestions(final String sessionkey) { final Session session = getSessionWithAuthCheck(sessionkey); - databaseDao.deleteAllPreparationQuestionsWithAnswers(session); + contentRepository.deleteAllPreparationQuestionsWithAnswers(session); } @Override @@ -901,7 +906,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override public List<String> getUnAnsweredLectureQuestionIds(final String sessionkey, final User user) { final Session session = getSession(sessionkey); - return databaseDao.getUnAnsweredLectureQuestionIds(session, user); + return contentRepository.getUnAnsweredLectureQuestionIds(session, user); } @Override @@ -914,7 +919,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override public List<String> getUnAnsweredPreparationQuestionIds(final String sessionkey, final User user) { final Session session = getSession(sessionkey); - return databaseDao.getUnAnsweredPreparationQuestionIds(session, user); + return contentRepository.getUnAnsweredPreparationQuestionIds(session, user); } @Override @@ -925,30 +930,30 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis if (!session.isCreator(user)) { throw new UnauthorizedException(); } - final List<Question> questions = databaseDao.publishAllQuestions(session, publish); + final List<Content> contents = contentRepository.publishAllQuestions(session, publish); NovaEvent event; if (publish) { - event = new UnlockQuestionsEvent(this, session, questions); + event = new UnlockQuestionsEvent(this, session, contents); } else { - event = new LockQuestionsEvent(this, session, questions); + event = new LockQuestionsEvent(this, session, contents); } this.publisher.publishEvent(event); } @Override @PreAuthorize("isAuthenticated()") - public void publishQuestions(final String sessionkey, final boolean publish, List<Question> questions) { + public void publishQuestions(final String sessionkey, final boolean publish, List<Content> contents) { final User user = getCurrentUser(); final Session session = getSession(sessionkey); if (!session.isCreator(user)) { throw new UnauthorizedException(); } - databaseDao.publishQuestions(session, publish, questions); + contentRepository.publishQuestions(session, publish, contents); NovaEvent event; if (publish) { - event = new UnlockQuestionsEvent(this, session, questions); + event = new UnlockQuestionsEvent(this, session, contents); } else { - event = new LockQuestionsEvent(this, session, questions); + event = new LockQuestionsEvent(this, session, contents); } this.publisher.publishEvent(event); } @@ -1010,8 +1015,8 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override public String getQuestionImage(String questionId) { - Question question = databaseDao.getQuestion(questionId); - String imageData = question.getImage(); + Content content = contentRepository.getQuestion(questionId); + String imageData = content.getImage(); if (imageData == null) { imageData = ""; @@ -1022,8 +1027,8 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override public String getQuestionFcImage(String questionId) { - Question question = databaseDao.getQuestion(questionId); - String imageData = question.getFcImage(); + Content content = contentRepository.getQuestion(questionId); + String imageData = content.getFcImage(); if (imageData == null) { imageData = ""; diff --git a/src/main/java/de/thm/arsnova/services/IQuestionService.java b/src/main/java/de/thm/arsnova/services/IContentService.java similarity index 88% rename from src/main/java/de/thm/arsnova/services/IQuestionService.java rename to src/main/java/de/thm/arsnova/services/IContentService.java index 4e257c395e584e06058ec2549c2d84c60421c4c2..9b4e4f97bf40433a750034b28a3ee53d03ee19ef 100644 --- a/src/main/java/de/thm/arsnova/services/IQuestionService.java +++ b/src/main/java/de/thm/arsnova/services/IContentService.java @@ -20,7 +20,7 @@ package de.thm.arsnova.services; import de.thm.arsnova.entities.Answer; import de.thm.arsnova.entities.Comment; import de.thm.arsnova.entities.CommentReadingCount; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.entities.User; import java.util.List; @@ -29,14 +29,14 @@ import java.util.Map; /** * The functionality the question service should provide. */ -public interface IQuestionService { - Question saveQuestion(Question question); +public interface IContentService { + Content saveQuestion(Content content); boolean saveQuestion(Comment comment); - Question getQuestion(String id); + Content getQuestion(String id); - List<Question> getSkillQuestions(String sessionkey); + List<Content> getSkillQuestions(String sessionkey); int getSkillQuestionCount(String sessionkey); @@ -88,9 +88,9 @@ public interface IQuestionService { Comment readInterposedQuestionInternal(String commentId, User user); - Question update(Question question); + Content update(Content content); - Question update(Question question, User user); + Content update(Content content, User user); void deleteAnswers(String questionId); @@ -102,11 +102,11 @@ public interface IQuestionService { void deleteInterposedQuestion(String commentId); - List<Question> getLectureQuestions(String sessionkey); + List<Content> getLectureQuestions(String sessionkey); - List<Question> getFlashcards(String sessionkey); + List<Content> getFlashcards(String sessionkey); - List<Question> getPreparationQuestions(String sessionkey); + List<Content> getPreparationQuestions(String sessionkey); int getLectureQuestionCount(String sessionkey); @@ -144,7 +144,7 @@ public interface IQuestionService { void publishAll(String sessionkey, boolean publish); - void publishQuestions(String sessionkey, boolean publish, List<Question> questions); + void publishQuestions(String sessionkey, boolean publish, List<Content> contents); void deleteAllQuestionsAnswers(String sessionkey); @@ -158,7 +158,7 @@ public interface IQuestionService { void setVotingAdmission(String questionId, boolean disableVoting); - void setVotingAdmissions(String sessionkey, boolean disableVoting, List<Question> questions); + void setVotingAdmissions(String sessionkey, boolean disableVoting, List<Content> contents); void setVotingAdmissionForAllQuestions(String sessionkey, boolean disableVoting); @@ -166,6 +166,6 @@ public interface IQuestionService { String getQuestionFcImage(String questionId); - List<Question> replaceImageData(List<Question> questions); + List<Content> replaceImageData(List<Content> contents); } diff --git a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java index 26057c7ecf592828b5a7e13e5358fab1920ef2b1..b348dc32cc48c729bde2d61fbad4c0b28c0d26ff 100644 --- a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java +++ b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java @@ -36,11 +36,11 @@ import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.services.IFeedbackService; -import de.thm.arsnova.services.IQuestionService; +import de.thm.arsnova.services.IContentService; import de.thm.arsnova.services.ISessionService; import de.thm.arsnova.services.IUserService; import de.thm.arsnova.socket.message.Feedback; -import de.thm.arsnova.socket.message.Question; +import de.thm.arsnova.socket.message.Content; import de.thm.arsnova.socket.message.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,7 +76,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { private ISessionService sessionService; @Autowired - private IQuestionService questionService; + private IContentService contentService; private static final Logger logger = LoggerFactory.getLogger(ARSnovaSocketIOServer.class); @@ -191,7 +191,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { AckRequest ackRequest) { final User user = userService.getUser2SocketId(client.getSessionId()); try { - questionService.readInterposedQuestionInternal(comment.getId(), user); + contentService.readInterposedQuestionInternal(comment.getId(), user); } catch (NotFoundException | UnauthorizedException e) { logger.error("Loading of comment {} failed for user {} with exception {}", comment.getId(), user, e.getMessage()); } @@ -203,7 +203,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { public void onData(SocketIOClient client, String answerId, AckRequest ackRequest) { final User user = userService.getUser2SocketId(client.getSessionId()); try { - questionService.readFreetextAnswer(answerId, user); + contentService.readFreetextAnswer(answerId, user); } catch (NotFoundException | UnauthorizedException e) { logger.error("Marking answer {} as read failed for user {} with exception {}", answerId, user, e.getMessage()); } @@ -360,17 +360,17 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { final de.thm.arsnova.entities.Session session = sessionService.getSessionInternal(sessionKey, user); final de.thm.arsnova.entities.SessionFeature features = sessionService.getSessionFeatures(sessionKey); - client.sendEvent("unansweredLecturerQuestions", questionService.getUnAnsweredLectureQuestionIds(sessionKey, user)); - client.sendEvent("unansweredPreparationQuestions", questionService.getUnAnsweredPreparationQuestionIds(sessionKey, user)); - client.sendEvent("countLectureQuestionAnswers", questionService.countLectureQuestionAnswersInternal(sessionKey)); - client.sendEvent("countPreparationQuestionAnswers", questionService.countPreparationQuestionAnswersInternal(sessionKey)); + client.sendEvent("unansweredLecturerQuestions", contentService.getUnAnsweredLectureQuestionIds(sessionKey, user)); + client.sendEvent("unansweredPreparationQuestions", contentService.getUnAnsweredPreparationQuestionIds(sessionKey, user)); + client.sendEvent("countLectureQuestionAnswers", contentService.countLectureQuestionAnswersInternal(sessionKey)); + client.sendEvent("countPreparationQuestionAnswers", contentService.countPreparationQuestionAnswersInternal(sessionKey)); client.sendEvent("activeUserCountData", sessionService.activeUsers(sessionKey)); client.sendEvent("learningProgressOptions", session.getLearningProgressOptions()); final de.thm.arsnova.entities.Feedback fb = feedbackService.getFeedback(sessionKey); client.sendEvent("feedbackData", fb.getValues()); if (features.isFlashcard() || features.isFlashcardFeature()) { - client.sendEvent("countFlashcards", questionService.countFlashcardsForUserInternal(sessionKey)); + client.sendEvent("countFlashcards", contentService.countFlashcardsForUserInternal(sessionKey)); client.sendEvent("flipFlashcards", session.getFlipFlashcards()); } @@ -421,8 +421,8 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { broadcastInSession(sessionKey, "activeUserCountData", count); } - public void reportAnswersToLecturerQuestionAvailable(final de.thm.arsnova.entities.Session session, final Question lecturerQuestion) { - broadcastInSession(session.getKeyword(), "answersToLecQuestionAvail", lecturerQuestion.get_id()); + public void reportAnswersToLecturerQuestionAvailable(final de.thm.arsnova.entities.Session session, final Content content) { + broadcastInSession(session.getKeyword(), "answersToLecQuestionAvail", content.get_id()); } public void reportAudienceQuestionAvailable(final de.thm.arsnova.entities.Session session, final Comment audienceQuestion) { @@ -430,25 +430,25 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { broadcastInSession(session.getKeyword(), "audQuestionAvail", audienceQuestion.getId()); } - public void reportLecturerQuestionAvailable(final de.thm.arsnova.entities.Session session, final List<de.thm.arsnova.entities.Question> qs) { - List<Question> questions = new ArrayList<>(); - for (de.thm.arsnova.entities.Question q : qs) { - questions.add(new Question(q)); + public void reportLecturerQuestionAvailable(final de.thm.arsnova.entities.Session session, final List<de.thm.arsnova.entities.Content> qs) { + List<Content> contents = new ArrayList<>(); + for (de.thm.arsnova.entities.Content q : qs) { + contents.add(new Content(q)); } /* TODO role handling implementation, send this only to users with role audience */ if (!qs.isEmpty()) { - broadcastInSession(session.getKeyword(), "lecQuestionAvail", questions.get(0).get_id()); // deprecated! + broadcastInSession(session.getKeyword(), "lecQuestionAvail", contents.get(0).get_id()); // deprecated! } - broadcastInSession(session.getKeyword(), "lecturerQuestionAvailable", questions); + broadcastInSession(session.getKeyword(), "lecturerQuestionAvailable", contents); } - public void reportLecturerQuestionsLocked(final de.thm.arsnova.entities.Session session, final List<de.thm.arsnova.entities.Question> qs) { - List<Question> questions = new ArrayList<>(); - for (de.thm.arsnova.entities.Question q : qs) { - questions.add(new Question(q)); + public void reportLecturerQuestionsLocked(final de.thm.arsnova.entities.Session session, final List<de.thm.arsnova.entities.Content> qs) { + List<Content> contents = new ArrayList<>(); + for (de.thm.arsnova.entities.Content q : qs) { + contents.add(new Content(q)); } - broadcastInSession(session.getKeyword(), "lecturerQuestionLocked", questions); + broadcastInSession(session.getKeyword(), "lecturerQuestionLocked", contents); } public void reportSessionStatus(final String sessionKey, final boolean active) { @@ -505,17 +505,17 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Timed(name = "visit.NewAnswerEvent") public void visit(NewAnswerEvent event) { final String sessionKey = event.getSession().getKeyword(); - this.reportAnswersToLecturerQuestionAvailable(event.getSession(), new Question(event.getQuestion())); - broadcastInSession(sessionKey, "countQuestionAnswersByQuestionId", questionService.getAnswerAndAbstentionCountInternal(event.getQuestion().get_id())); - broadcastInSession(sessionKey, "countLectureQuestionAnswers", questionService.countLectureQuestionAnswersInternal(sessionKey)); - broadcastInSession(sessionKey, "countPreparationQuestionAnswers", questionService.countPreparationQuestionAnswersInternal(sessionKey)); - - // Update the unanswered count for the question variant that was answered. - final de.thm.arsnova.entities.Question question = event.getQuestion(); - if ("lecture".equals(question.getQuestionVariant())) { - sendToUser(event.getUser(), "unansweredLecturerQuestions", questionService.getUnAnsweredLectureQuestionIds(sessionKey, event.getUser())); - } else if ("preparation".equals(question.getQuestionVariant())) { - sendToUser(event.getUser(), "unansweredPreparationQuestions", questionService.getUnAnsweredPreparationQuestionIds(sessionKey, event.getUser())); + this.reportAnswersToLecturerQuestionAvailable(event.getSession(), new Content(event.getContent())); + broadcastInSession(sessionKey, "countQuestionAnswersByQuestionId", contentService.getAnswerAndAbstentionCountInternal(event.getContent().getId())); + broadcastInSession(sessionKey, "countLectureQuestionAnswers", contentService.countLectureQuestionAnswersInternal(sessionKey)); + broadcastInSession(sessionKey, "countPreparationQuestionAnswers", contentService.countPreparationQuestionAnswersInternal(sessionKey)); + + // Update the unanswered count for the content variant that was answered. + final de.thm.arsnova.entities.Content content = event.getContent(); + if ("lecture".equals(content.getQuestionVariant())) { + sendToUser(event.getUser(), "unansweredLecturerQuestions", contentService.getUnAnsweredLectureQuestionIds(sessionKey, event.getUser())); + } else if ("preparation".equals(content.getQuestionVariant())) { + sendToUser(event.getUser(), "unansweredPreparationQuestions", contentService.getUnAnsweredPreparationQuestionIds(sessionKey, event.getUser())); } } @@ -524,10 +524,10 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Timed(name = "visit.DeleteAnswerEvent") public void visit(DeleteAnswerEvent event) { final String sessionKey = event.getSession().getKeyword(); - this.reportAnswersToLecturerQuestionAvailable(event.getSession(), new Question(event.getQuestion())); + this.reportAnswersToLecturerQuestionAvailable(event.getSession(), new Content(event.getQuestion())); // We do not know which user's answer was deleted, so we can't update his 'unanswered' list of questions... - broadcastInSession(sessionKey, "countLectureQuestionAnswers", questionService.countLectureQuestionAnswersInternal(sessionKey)); - broadcastInSession(sessionKey, "countPreparationQuestionAnswers", questionService.countPreparationQuestionAnswersInternal(sessionKey)); + broadcastInSession(sessionKey, "countLectureQuestionAnswers", contentService.countLectureQuestionAnswersInternal(sessionKey)); + broadcastInSession(sessionKey, "countPreparationQuestionAnswers", contentService.countPreparationQuestionAnswersInternal(sessionKey)); } @Async @@ -574,20 +574,20 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { @Override public void visit(LockVotesEvent event) { - List<Question> questions = new ArrayList<>(); - for (de.thm.arsnova.entities.Question q : event.getQuestions()) { - questions.add(new Question(q)); + List<Content> contents = new ArrayList<>(); + for (de.thm.arsnova.entities.Content q : event.getQuestions()) { + contents.add(new Content(q)); } - broadcastInSession(event.getSession().getKeyword(), "lockVotes", questions); + broadcastInSession(event.getSession().getKeyword(), "lockVotes", contents); } @Override public void visit(UnlockVotesEvent event) { - List<Question> questions = new ArrayList<>(); - for (de.thm.arsnova.entities.Question q : event.getQuestions()) { - questions.add(new Question(q)); + List<Content> contents = new ArrayList<>(); + for (de.thm.arsnova.entities.Content q : event.getQuestions()) { + contents.add(new Content(q)); } - broadcastInSession(event.getSession().getKeyword(), "unlockVotes", questions); + broadcastInSession(event.getSession().getKeyword(), "unlockVotes", contents); } @Override @@ -597,7 +597,7 @@ public class ARSnovaSocketIOServer implements ARSnovaSocket, NovaEventVisitor { broadcastInSession(sessionKey, "featureChange", features); if (features.isFlashcard() || features.isFlashcardFeature()) { - broadcastInSession(sessionKey, "countFlashcards", questionService.countFlashcardsForUserInternal(sessionKey)); + broadcastInSession(sessionKey, "countFlashcards", contentService.countFlashcardsForUserInternal(sessionKey)); broadcastInSession(sessionKey, "flipFlashcards", event.getSession().getFlipFlashcards()); } } diff --git a/src/main/java/de/thm/arsnova/socket/message/Question.java b/src/main/java/de/thm/arsnova/socket/message/Content.java similarity index 85% rename from src/main/java/de/thm/arsnova/socket/message/Question.java rename to src/main/java/de/thm/arsnova/socket/message/Content.java index c8660e3dbc80ef7e479d86832f9c053d1e688287..f462baa7bb7e62b81f15e512774f630d9e848d80 100644 --- a/src/main/java/de/thm/arsnova/socket/message/Question.java +++ b/src/main/java/de/thm/arsnova/socket/message/Content.java @@ -20,14 +20,14 @@ package de.thm.arsnova.socket.message; /** * Represents a question. */ -public class Question { +public class Content { private final String _id; private final String variant; - public Question(de.thm.arsnova.entities.Question question) { - this._id = question.get_id(); - this.variant = question.getQuestionVariant(); + public Content(de.thm.arsnova.entities.Content content) { + this._id = content.getId(); + this.variant = content.getQuestionVariant(); } public String get_id() { diff --git a/src/test/java/de/thm/arsnova/controller/LecturerQuestionControllerTest.java b/src/test/java/de/thm/arsnova/controller/ContentControllerTest.java similarity index 96% rename from src/test/java/de/thm/arsnova/controller/LecturerQuestionControllerTest.java rename to src/test/java/de/thm/arsnova/controller/ContentControllerTest.java index 47a9b29c0e1d35b9ede8046a0562e4384f41bad9..ec09fcca0b6d5685767c8329161cc8b3dff310c3 100644 --- a/src/test/java/de/thm/arsnova/controller/LecturerQuestionControllerTest.java +++ b/src/test/java/de/thm/arsnova/controller/ContentControllerTest.java @@ -31,13 +31,13 @@ import org.springframework.web.context.WebApplicationContext; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -public class LecturerQuestionControllerTest extends AbstractControllerTest { +public class ContentControllerTest extends AbstractControllerTest { @Autowired private StubUserService userService; @Autowired - private LecturerQuestionController questionController; + private ContentController questionController; private MockMvc mockMvc; diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index cbfb86d5571738d3eb029f65d4d3b615f80a5283..6dc8bb931103247839034b0284de259a87f05e75 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -33,7 +33,7 @@ public class StubDatabaseDao implements IDatabaseDao { private static Map<String, Session> stubSessions = new ConcurrentHashMap<>(); private static Map<String, Feedback> stubFeedbacks = new ConcurrentHashMap<>(); - private static Map<String, List<Question>> stubQuestions = new ConcurrentHashMap<>(); + private static Map<String, List<Content>> stubQuestions = new ConcurrentHashMap<>(); private static Map<String, User> stubUsers = new ConcurrentHashMap<>(); public Comment comment; @@ -91,29 +91,9 @@ public class StubDatabaseDao implements IDatabaseDao { } private void fillWithDummyQuestions() { - List<Question> questions = new ArrayList<>(); - questions.add(new Question()); - stubQuestions.put("12345678", questions); - } - - @Override - public Question saveQuestion(Session session, Question question) { - List<Question> questions = stubQuestions.get(session.getKeyword()); - questions.add(question); - stubQuestions.put(session.getId(), questions); - - return question; - } - - @Override - public Question getQuestion(String id) { - // Simply ... no such question ;-) - return null; - } - - @Override - public int getSkillQuestionCount(Session session) { - return stubQuestions.get(session.getKeyword()).size(); + List<Content> contents = new ArrayList<>(); + contents.add(new Content()); + stubQuestions.put("12345678", contents); } @Override @@ -123,7 +103,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public int getAnswerCount(Question question, int piRound) { + public int getAnswerCount(Content content, int piRound) { // TODO Auto-generated method stub return 0; } @@ -146,31 +126,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<String> getQuestionIds(Session session, User user) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<String> getUnAnsweredQuestionIds(Session session, User user) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Question updateQuestion(Question question) { - // TODO Auto-generated method stub - return null; - } - - @Override - public int deleteQuestionWithAnswers(Question question) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int deleteAnswers(Question question) { + public int deleteAnswers(Content content) { // TODO Auto-generated method stub return 0; } @@ -192,29 +148,6 @@ public class StubDatabaseDao implements IDatabaseDao { return 0; } - @Override - public int[] deleteAllQuestionsWithAnswers(Session session) { - return new int[] { 0, 0 }; - } - - @Override - public int getLectureQuestionCount(Session session) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getFlashcardCount(Session session) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getPreparationQuestionCount(Session session) { - // TODO Auto-generated method stub - return 0; - } - @Override public int countLectureQuestionAnswers(Session session) { // TODO Auto-generated method stub @@ -227,45 +160,6 @@ public class StubDatabaseDao implements IDatabaseDao { return 0; } - @Override - public int[] deleteAllLectureQuestionsWithAnswers(Session session) { - return new int[] { 0, 0 }; - } - - @Override - public int[] deleteAllFlashcardsWithAnswers(Session session) { - return new int[] { 0, 0 }; - } - - @Override - public int[] deleteAllPreparationQuestionsWithAnswers(Session session) { - return new int[] { 0, 0 }; - } - - @Override - public List<String> getUnAnsweredLectureQuestionIds(Session session, User user) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<String> getUnAnsweredPreparationQuestionIds(Session session, User user) { - // TODO Auto-generated method stub - return null; - } - - @Override - public void publishQuestions(Session session, boolean publish, List<Question> questions) { - // TODO Auto-generated method stub - - } - - @Override - public List<Question> publishAllQuestions(Session session, boolean publish) { - // TODO Auto-generated method stub - return null; - } - @Override public int deleteAllQuestionsAnswers(Session session) { // TODO Auto-generated method stub @@ -297,73 +191,19 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<Question> getSkillQuestionsForUsers(Session session) { + public List<Answer> getAnswers(Content content, int piRound) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getSkillQuestionsForTeachers(Session session) { + public List<Answer> getAnswers(Content content) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getLectureQuestionsForUsers(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getLectureQuestionsForTeachers(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getFlashcardsForUsers(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getFlashcardsForTeachers(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getPreparationQuestionsForUsers(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getPreparationQuestionsForTeachers(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getAllSkillQuestions(Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Answer> getAnswers(Question question, int piRound) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Answer> getAnswers(Question question) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Answer saveAnswer(Answer answer, User user, Question question, Session session) { + public Answer saveAnswer(Answer answer, User user, Content content, Session session) { // TODO Auto-generated method stub return null; } @@ -380,69 +220,38 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<String> getSubjects(Session session, String questionVariant) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<String> getQuestionIdsBySubject(Session session, String questionVariant, String subject) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Question> getQuestionsByIds(List<String> ids, Session session) { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<Answer> getAllAnswers(Question question) { + public List<Answer> getAllAnswers(Content content) { // TODO Auto-generated method stub return null; } @Override - public int getTotalAnswerCountByQuestion(Question question) { + public int getTotalAnswerCountByQuestion(Content content) { // TODO Auto-generated method stub return 0; } @Override - public void resetQuestionsRoundState(Session session, - List<Question> questions) { - // TODO Auto-generated method stub - - } - - @Override - public void setVotingAdmissions(Session session, boolean disableVoting, List<Question> questions) { - // TODO Auto-generated method stub - - } - - @Override - public List<Question> setVotingAdmissionForAllQuestions(Session session, boolean disableVoting) { + public <T> T getObjectFromId(String documentId, Class<T> klass) { // TODO Auto-generated method stub return null; } @Override - public <T> T getObjectFromId(String documentId, Class<T> klass) { + public MotdList getMotdListForUser(final String username) { // TODO Auto-generated method stub return null; } @Override - public MotdList getMotdListForUser(final String username) { + public MotdList createOrUpdateMotdList(MotdList motdlist) { // TODO Auto-generated method stub return null; } @Override - public MotdList createOrUpdateMotdList(MotdList motdlist) { + public int[] deleteAllAnswersWithQuestions(List<Content> contents) { // TODO Auto-generated method stub - return null; + return new int[0]; } } diff --git a/src/test/java/de/thm/arsnova/entities/QuestionTest.java b/src/test/java/de/thm/arsnova/entities/ContentTest.java similarity index 96% rename from src/test/java/de/thm/arsnova/entities/QuestionTest.java rename to src/test/java/de/thm/arsnova/entities/ContentTest.java index 57569e6f220f4b8463bd62eb11e6e9f336069864..fc6297c8d5668b825f563e1cae5550dae3d38189 100644 --- a/src/test/java/de/thm/arsnova/entities/QuestionTest.java +++ b/src/test/java/de/thm/arsnova/entities/ContentTest.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import static org.junit.Assert.assertEquals; -public class QuestionTest { +public class ContentTest { @SuppressWarnings("serial") @Test @@ -36,7 +36,7 @@ public class QuestionTest { p2.setText("No"); p2.setCorrect(false); p2.setValue(-10); - Question q = new Question(); + Content q = new Content(); q.setQuestionType("yesno"); q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ add(p1); @@ -62,7 +62,7 @@ public class QuestionTest { p2.setText("No"); p2.setCorrect(false); p2.setValue(-10); - Question q = new Question(); + Content q = new Content(); q.setAbstention(true); q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ add(p1); @@ -89,7 +89,7 @@ public class QuestionTest { p3.setText("Maybe"); p3.setCorrect(true); p3.setValue(10); - Question q = new Question(); + Content q = new Content(); q.setQuestionType("mc"); q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ add(p1); @@ -134,7 +134,7 @@ public class QuestionTest { p4.setText("1;1"); p4.setCorrect(true); p4.setValue(10); - Question q = new Question(); + Content q = new Content(); q.setQuestionType("grid"); q.setPossibleAnswers(new ArrayList<PossibleAnswer>() {{ add(p1); diff --git a/src/test/java/de/thm/arsnova/services/QuestionServiceTest.java b/src/test/java/de/thm/arsnova/services/ContentServiceTest.java similarity index 86% rename from src/test/java/de/thm/arsnova/services/QuestionServiceTest.java rename to src/test/java/de/thm/arsnova/services/ContentServiceTest.java index daa1820e7341868639b8b7de0e4dd2f272104dde..80ec08da18557f6f6c59738e49a5c870d862f335 100644 --- a/src/test/java/de/thm/arsnova/services/QuestionServiceTest.java +++ b/src/test/java/de/thm/arsnova/services/ContentServiceTest.java @@ -22,7 +22,7 @@ import de.thm.arsnova.config.TestAppConfig; import de.thm.arsnova.config.TestSecurityConfig; import de.thm.arsnova.dao.StubDatabaseDao; import de.thm.arsnova.entities.Comment; -import de.thm.arsnova.entities.Question; +import de.thm.arsnova.entities.Content; import de.thm.arsnova.exceptions.NotFoundException; import org.junit.After; import org.junit.Before; @@ -48,10 +48,10 @@ import static org.junit.Assert.*; @WebAppConfiguration @ContextConfiguration(classes = {AppConfig.class, TestAppConfig.class, TestSecurityConfig.class}) @ActiveProfiles("test") -public class QuestionServiceTest { +public class ContentServiceTest { @Autowired - private IQuestionService questionService; + private IContentService contentService; @Autowired private StubUserService userService; @@ -83,19 +83,19 @@ public class QuestionServiceTest { @Test(expected = AuthenticationCredentialsNotFoundException.class) public void testShouldNotReturnQuestionsIfNotAuthenticated() { setAuthenticated(false, "nobody"); - questionService.getSkillQuestions("12345678"); + contentService.getSkillQuestions("12345678"); } @Test(expected = NotFoundException.class) public void testShouldFindQuestionsForNonExistantSession() { setAuthenticated(true, "ptsr00"); - questionService.getSkillQuestions("00000000"); + contentService.getSkillQuestions("00000000"); } @Test public void testShouldFindQuestions() { setAuthenticated(true, "ptsr00"); - assertEquals(1, questionService.getSkillQuestionCount("12345678")); + assertEquals(1, contentService.getSkillQuestionCount("12345678")); } @Test @@ -107,7 +107,7 @@ public class QuestionServiceTest { comment.setSessionId("12345678"); databaseDao.comment = comment; - questionService.readInterposedQuestion(comment.getId()); + contentService.readInterposedQuestion(comment.getId()); assertTrue(comment.isRead()); } @@ -122,7 +122,7 @@ public class QuestionServiceTest { comment.setCreator("regular user"); databaseDao.comment = comment; - questionService.readInterposedQuestion(comment.getId()); + contentService.readInterposedQuestion(comment.getId()); assertFalse(comment.isRead()); } @@ -130,21 +130,21 @@ public class QuestionServiceTest { @Test(expected = AccessDeniedException.class) public void testShouldSaveQuestion() throws Exception{ setAuthenticated(true, "regular user"); - final Question question = new Question(); - question.setSessionKeyword("12345678"); - question.setQuestionVariant("freetext"); - questionService.saveQuestion(question); + final Content content = new Content(); + content.setSessionKeyword("12345678"); + content.setQuestionVariant("freetext"); + contentService.saveQuestion(content); } @Test(expected = AccessDeniedException.class) public void testShouldNotDeleteQuestion() throws Exception{ setAuthenticated(true, "otheruser"); - questionService.deleteQuestion("a1a2a3a4a5a6a7a8a9a"); + contentService.deleteQuestion("a1a2a3a4a5a6a7a8a9a"); } @Test(expected = AccessDeniedException.class) public void testShouldNotDeleteInterposedQuestion() throws Exception{ setAuthenticated(true, "otheruser"); - questionService.deleteInterposedQuestion("a1a2a3a4a5a6a7a8a9a"); + contentService.deleteInterposedQuestion("a1a2a3a4a5a6a7a8a9a"); } }