Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/ScratchieAnswerVisitDAO.java =================================================================== diff -u -re8a7110708b15579af2c6b31ac52a6da427fef6d -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/ScratchieAnswerVisitDAO.java (.../ScratchieAnswerVisitDAO.java) (revision e8a7110708b15579af2c6b31ac52a6da427fef6d) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/ScratchieAnswerVisitDAO.java (.../ScratchieAnswerVisitDAO.java) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -37,7 +37,7 @@ /** * Get log for VSA question. */ - ScratchieAnswerVisitLog getLog(Long sessionId, Long itemUid, String answer); + ScratchieAnswerVisitLog getLog(Long sessionId, Long itemUid, boolean isCaseSensitive, String answer); int getLogCountTotal(Long sessionId); Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieAnswerVisitDAOHibernate.java =================================================================== diff -u -re8a7110708b15579af2c6b31ac52a6da427fef6d -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieAnswerVisitDAOHibernate.java (.../ScratchieAnswerVisitDAOHibernate.java) (revision e8a7110708b15579af2c6b31ac52a6da427fef6d) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieAnswerVisitDAOHibernate.java (.../ScratchieAnswerVisitDAOHibernate.java) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -25,30 +25,30 @@ import java.util.List; +import org.hibernate.query.Query; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.tool.scratchie.dao.ScratchieAnswerVisitDAO; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieAnswerVisitLog; import org.springframework.stereotype.Repository; @Repository public class ScratchieAnswerVisitDAOHibernate extends LAMSBaseDAO implements ScratchieAnswerVisitDAO { + private static final String FIND_BY_SESSION_AND_ITEM = "FROM " + ScratchieAnswerVisitLog.class.getName() + + " AS r WHERE r.sessionId=? AND r.qbToolQuestion.uid = ? ORDER BY r.accessDate ASC"; - private static final String FIND_BY_SESSION_AND_ITEM = "from " + ScratchieAnswerVisitLog.class.getName() - + " as r where r.sessionId=? and r.qbToolQuestion.uid = ? order by r.accessDate asc"; + private static final String FIND_BY_SESSION = "FROM " + ScratchieAnswerVisitLog.class.getName() + + " AS r WHERE r.sessionId=? ORDER BY r.accessDate ASC"; - private static final String FIND_BY_SESSION = "from " + ScratchieAnswerVisitLog.class.getName() - + " as r where r.sessionId=? order by r.accessDate asc"; - - private static final String FIND_COUNT_BY_SESSION = "select count(*) from " - + ScratchieAnswerVisitLog.class.getName() + " as r where r.sessionId=?"; + private static final String FIND_COUNT_BY_SESSION = "SELECT COUNT(*) FROM " + + ScratchieAnswerVisitLog.class.getName() + " AS r WHERE r.sessionId=?"; - private static final String FIND_COUNT_BY_SESSION_AND_ITEM = "select count(*) from " - + ScratchieAnswerVisitLog.class.getName() + " as r where r.sessionId=? and r.qbToolQuestion.uid = ?"; + private static final String FIND_COUNT_BY_SESSION_AND_ITEM = "SELECT COUNT(*) FROM " + + ScratchieAnswerVisitLog.class.getName() + " AS r WHERE r.sessionId=? AND r.qbToolQuestion.uid = ?"; @Override public ScratchieAnswerVisitLog getLog(Long optionUid, Long itemUid, Long sessionId) { - final String FIND_BY_SESSION_AND_OPTION = "from " + ScratchieAnswerVisitLog.class.getName() - + " as r where r.sessionId = ? and r.qbToolQuestion.uid = ? and r.qbOption.uid=?"; + final String FIND_BY_SESSION_AND_OPTION = "FROM " + ScratchieAnswerVisitLog.class.getName() + + " AS r WHERE r.sessionId = ? AND r.qbToolQuestion.uid = ? AND r.qbOption.uid=?"; List list = doFind(FIND_BY_SESSION_AND_OPTION, new Object[] { sessionId, itemUid, optionUid }); if (list == null || list.size() == 0) { @@ -58,15 +58,16 @@ } @Override - public ScratchieAnswerVisitLog getLog(Long sessionId, Long itemUid, String answer) { - final String FIND_BY_SESSION_AND_ANSWER = "from " + ScratchieAnswerVisitLog.class.getName() - + " as r where r.sessionId = ? and r.qbToolQuestion.uid = ? and r.answer=?"; + public ScratchieAnswerVisitLog getLog(Long sessionId, Long itemUid, boolean isCaseSensitive, String answer) { + final String FIND_BY_SESSION_AND_ANSWER = "FROM " + ScratchieAnswerVisitLog.class.getName() + + " AS r WHERE r.sessionId = :sessionId AND r.qbToolQuestion.uid = :itemUid AND " + + (isCaseSensitive ? "CAST(r.answer AS binary)=CAST(:answer AS binary)" : "r.answer=:answer"); - List list = doFind(FIND_BY_SESSION_AND_ANSWER, new Object[] { sessionId, itemUid, answer }); - if (list == null || list.size() == 0) { - return null; - } - return (ScratchieAnswerVisitLog) list.get(0); + Query q = getSession().createQuery(FIND_BY_SESSION_AND_ANSWER, ScratchieAnswerVisitLog.class); + q.setParameter("sessionId", sessionId); + q.setParameter("itemUid", itemUid); + q.setParameter("answer", answer); + return q.uniqueResult(); } @Override Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/model/Scratchie.java =================================================================== diff -u -re8a7110708b15579af2c6b31ac52a6da427fef6d -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/model/Scratchie.java (.../Scratchie.java) (revision e8a7110708b15579af2c6b31ac52a6da427fef6d) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/model/Scratchie.java (.../Scratchie.java) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -384,14 +384,8 @@ this.confidenceLevelsActivityUiid = confidenceLevelsActivityUiid; } - public boolean isAnswersFetchingEnabledAndVsaQuestionsAvailable() { - //check Scratchie contains VSA questions - boolean hasVsaQuestion = false; - for (ScratchieItem item : scratchieItems) { - hasVsaQuestion |= QbQuestion.TYPE_VERY_SHORT_ANSWERS == item.getQbQuestion().getType(); - } - - return activityUiidProvidingVsaAnswers != null && hasVsaQuestion; + public boolean isAnswersFetchingEnabled() { + return activityUiidProvidingVsaAnswers != null; } /** Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/IScratchieService.java =================================================================== diff -u -r122ff0d8419be3fac72ddb842cbbce1cea01e542 -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/IScratchieService.java (.../IScratchieService.java) (revision 122ff0d8419be3fac72ddb842cbbce1cea01e542) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/IScratchieService.java (.../IScratchieService.java) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -33,12 +33,12 @@ import org.lamsfoundation.lams.learningdesign.ToolActivity; import org.lamsfoundation.lams.notebook.model.NotebookEntry; import org.lamsfoundation.lams.qb.model.QbOption; -import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.tool.scratchie.dto.BurningQuestionItemDTO; import org.lamsfoundation.lams.tool.scratchie.dto.GroupSummary; import org.lamsfoundation.lams.tool.scratchie.dto.LeaderResultsDTO; import org.lamsfoundation.lams.tool.scratchie.dto.ReflectDTO; import org.lamsfoundation.lams.tool.scratchie.model.Scratchie; +import org.lamsfoundation.lams.tool.scratchie.model.ScratchieAnswerVisitLog; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieBurningQuestion; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieConfigItem; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieItem; @@ -151,14 +151,6 @@ */ Scratchie getDefaultContent(Long contentId) throws ScratchieApplicationException; - /** - * Get list of scratchie items by given scratchieUid. These scratchie items must be created by author. - * - * @param scratchieUid - * @return - */ - List getAuthoredItems(Long scratchieUid); - // ********** for user methods ************* /** * Create a new user in database. @@ -255,6 +247,11 @@ * @param scratchieItemList */ Collection getItemsWithIndicatedScratches(Long toolSessionId); + + /** + * Return log for VSA type item. + */ + ScratchieAnswerVisitLog getLog(Long sessionId, Long itemUid, boolean isCaseSensitive, String answer); /** * Leader has scratched the specified answer. Will store this scratch for all users in his group. It will also @@ -266,7 +263,7 @@ * Leader has left this answer. We will store this answer for all users in his group. It will also * update all the marks. */ - void recordVsaAnswer(Long sessionId, Long itemUid, String answer); + void recordVsaAnswer(Long sessionId, Long itemUid, boolean isCaseSensitive, String answer); /** * Recalculate mark for leader and sets it to all members of a group Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java =================================================================== diff -u -r269c13324c6bb998631af858dc8091ad3102ef78 -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision 269c13324c6bb998631af858dc8091ad3102ef78) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -184,12 +184,6 @@ } @Override - public List getAuthoredItems(Long scratchieUid) { - List res = scratchieItemDao.getAuthoringItems(scratchieUid); - return res; - } - - @Override public void createUser(ScratchieUser scratchieUser) { ScratchieUser user = getUserByIDAndSession(scratchieUser.getUserId(), scratchieUser.getSession().getSessionId()); @@ -279,13 +273,6 @@ //populate Scratchie items with confidence levels for (ScratchieItem item : items) { - - //init options' confidenceLevelDtos list -// for (OptionDTO optionDto : item.getOptionDtos()) { -// LinkedList confidenceLevelDtosTemp = new LinkedList<>(); -// optionDto.setConfidenceLevelDtos(confidenceLevelDtosTemp); -// } - //find corresponding QbQuestion for (ConfidenceLevelDTO confidenceLevelDto : confidenceLevelDtos) { if (item.getQbQuestion().getUid().equals(confidenceLevelDto.getQbQuestionUid())) { @@ -296,10 +283,8 @@ optionDTO.getConfidenceLevelDtos().add(confidenceLevelDto); } } - } } - } } @@ -428,6 +413,11 @@ public void saveOrUpdateScratchieSession(ScratchieSession resSession) { scratchieSessionDao.saveObject(resSession); } + + @Override + public ScratchieAnswerVisitLog getLog(Long sessionId, Long itemUid, boolean isCaseSensitive, String answer) { + return scratchieAnswerVisitDao.getLog(sessionId, itemUid, isCaseSensitive, answer); + } @Override public void recordItemScratched(Long sessionId, Long itemUid, Long optionUid) { @@ -445,14 +435,14 @@ log.setQbToolQuestion(qbToolQuestion); log.setAccessDate(new Timestamp(new Date().getTime())); scratchieAnswerVisitDao.saveObject(log); + + recalculateMarkForSession(sessionId, false); } - - recalculateMarkForSession(sessionId, false); } @Override - public void recordVsaAnswer(Long sessionId, Long itemUid, String answer) { - ScratchieAnswerVisitLog log = scratchieAnswerVisitDao.getLog(sessionId, itemUid, answer); + public void recordVsaAnswer(Long sessionId, Long itemUid, boolean isCaseSensitive, String answer) { + ScratchieAnswerVisitLog log = scratchieAnswerVisitDao.getLog(sessionId, itemUid, isCaseSensitive, answer); if (log == null) { log = new ScratchieAnswerVisitLog(); log.setAnswer(answer); @@ -461,9 +451,9 @@ log.setQbToolQuestion(qbToolQuestion); log.setAccessDate(new Timestamp(new Date().getTime())); scratchieAnswerVisitDao.saveObject(log); - } - recalculateMarkForSession(sessionId, false); + recalculateMarkForSession(sessionId, false); + } } @Override @@ -496,7 +486,6 @@ @Override public void recalculateUserAnswers(Scratchie scratchie, Set oldItems, Set newItems) { - // create list of modified questions List modifiedItems = new ArrayList<>(); for (ScratchieItem oldItem : oldItems) { @@ -579,7 +568,6 @@ @Override public void saveBurningQuestion(Long sessionId, Long itemUid, String question) { - boolean isGeneralBurningQuestion = itemUid == null; ScratchieBurningQuestion burningQuestion = (isGeneralBurningQuestion) @@ -720,7 +708,7 @@ // -1 if there is no log attemptNumber = -1; } else { - // adding 1 to start from 1. + // adding 1 to start from 1 attemptNumber = itemLogs.indexOf(log) + 1; } optionDto.setAttemptOrder(attemptNumber); @@ -730,19 +718,28 @@ // -1 if there is no log int attemptNumber = -1; for (ScratchieAnswerVisitLog itemLog : itemLogs) { - if (itemLog.getQbToolQuestion().getUid().equals(item.getUid()) && itemLog.getAnswer() != null - && itemLog.getAnswer().equals(optionDto.getAnswer())) { - // adding 1 to start from 1. + if (itemLog.getQbToolQuestion().getUid().equals(item.getUid()) + && isAnswersEqual(item, itemLog.getAnswer(), optionDto.getAnswer())) { + // adding 1 to start from 1 attemptNumber = itemLogs.indexOf(itemLog) + 1; break; } } optionDto.setAttemptOrder(attemptNumber); } } - } } + + private boolean isAnswersEqual(ScratchieItem item, String answer1, String answer2) { + if (answer1 == null || answer2 == null) { + return false; + } + + return item.getQbQuestion().isCaseSensitive() + ? answer1.equals(answer2) + : answer1.equalsIgnoreCase(answer2); + } @Override public Collection getItemsWithIndicatedScratches(Long toolSessionId) { @@ -752,12 +749,8 @@ Set items = new TreeSet<>(new ScratchieItemComparator()); items.addAll(scratchie.getScratchieItems()); - //populate Scratchie items with VSA answers, entered by learners in Assessment tool - if (scratchie.isAnswersFetchingEnabledAndVsaQuestionsAvailable()) { - for (ScratchieItem item : items) { - fillItemWithVsaOptionDtos(item, toolSessionId, scratchie, userLogs); - } - } + //populate Scratchie items with VSA answers + fillItemsWithVsaAnswers(items, toolSessionId, scratchie, userLogs); //mark scratched options for (ScratchieItem item : items) { @@ -779,7 +772,7 @@ // find according log if it exists for (ScratchieAnswerVisitLog userLog : userLogs) { if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) - && userLog.getAnswer().equals(optionDto.getAnswer())) { + && isAnswersEqual(item, userLog.getAnswer(), optionDto.getAnswer())) { isScratched = true; break; } @@ -795,36 +788,45 @@ return items; } - private void fillItemWithVsaOptionDtos(ScratchieItem item, Long toolSessionId, Scratchie scratchie, + /** + * Populate Scratchie item with VSA answers (both from Assessment tool and entered by current learner) + */ + private void fillItemsWithVsaAnswers(Collection items, Long toolSessionId, Scratchie scratchie, List userLogs) { - - //populate Scratchie items with VSA answers, entered by learners in Assessment tool - if (item.getQbQuestion().getType() == QbQuestion.TYPE_VERY_SHORT_ANSWERS - && scratchie.isAnswersFetchingEnabledAndVsaQuestionsAvailable()) { - ScratchieSession session = scratchieSessionDao.getSessionBySessionId(toolSessionId); - ScratchieUser leader = session.getGroupLeader(); - Collection assessmentAnswers = toolService.getVsaAnswersFromAssessment( - scratchie.getActivityUiidProvidingVsaAnswers(), leader.getUserId().intValue(), toolSessionId); - + ScratchieUser leader = scratchieSessionDao.getSessionBySessionId(toolSessionId).getGroupLeader(); + Collection assessmentAnswers = scratchie.isAnswersFetchingEnabled() + ? toolService.getVsaAnswersFromAssessment(scratchie.getActivityUiidProvidingVsaAnswers(), + leader.getUserId().intValue(), toolSessionId) + : null; + + for (ScratchieItem item : items) { Long itemQbQuestionUid = item.getQbQuestion().getUid(); + + //process only VSA items + if (item.getQbQuestion().getType() != QbQuestion.TYPE_VERY_SHORT_ANSWERS) { + continue; + } - //find corresponding QbQuestion - for (VsaAnswerDTO assessmentAnswer : assessmentAnswers) { - if (itemQbQuestionUid.equals(assessmentAnswer.getQbQuestionUid())) { - OptionDTO optionDto = new OptionDTO(); - optionDto.setAnswer(assessmentAnswer.getAnswer()); - optionDto.setCorrect(assessmentAnswer.isCorrect()); - optionDto.setUserId(assessmentAnswer.getUserId()); - optionDto.setQbQuestionUid(assessmentAnswer.getQbQuestionUid()); - if (!scratchie.isConfidenceLevelsEnabled()) { - //don't show confidence levels - for (ConfidenceLevelDTO confidenceLevel : assessmentAnswer.getConfidenceLevels()) { - confidenceLevel.setLevel(-1); + //populate Scratchie items with VSA answers, entered by learners in Assessment tool + if (scratchie.isAnswersFetchingEnabled()) { + //find corresponding QbQuestion + for (VsaAnswerDTO assessmentAnswer : assessmentAnswers) { + if (itemQbQuestionUid.equals(assessmentAnswer.getQbQuestionUid())) { + OptionDTO optionDto = new OptionDTO(); + optionDto.setAnswer(assessmentAnswer.getAnswer()); + optionDto.setCorrect(assessmentAnswer.isCorrect()); + optionDto.setUserId(assessmentAnswer.getUserId()); + optionDto.setQbQuestionUid(assessmentAnswer.getQbQuestionUid()); + if (!scratchie.isConfidenceLevelsEnabled()) { + //don't show confidence levels + for (ConfidenceLevelDTO confidenceLevel : assessmentAnswer.getConfidenceLevels()) { + confidenceLevel.setLevel(-1); + } } - } - optionDto.getConfidenceLevelDtos().addAll(assessmentAnswer.getConfidenceLevels()); + optionDto.getConfidenceLevelDtos().addAll(assessmentAnswer.getConfidenceLevels()); - item.getOptionDtos().add(optionDto); + item.getOptionDtos().add(optionDto); + } } } @@ -837,9 +839,10 @@ boolean skipAddingUserAnswerToConfidenceLevel = false; for (OptionDTO optionDtoIter : item.getOptionDtos()) { if (itemQbQuestionUid.equals(optionDtoIter.getQbQuestionUid()) - && optionDtoIter.getAnswer().equals(userLog.getAnswer())) { + && isAnswersEqual(item, optionDtoIter.getAnswer(), userLog.getAnswer())) { optionDto = optionDtoIter; - skipAddingUserAnswerToConfidenceLevel = optionDtoIter.getUserId().equals(leader.getUserId()); + skipAddingUserAnswerToConfidenceLevel = optionDtoIter.getUserId() + .equals(leader.getUserId()); break; } } @@ -1030,7 +1033,7 @@ } else { item.getOptionDtos().clear(); - fillItemWithVsaOptionDtos(item, sessionId, scratchie, sessionAttempts); + fillItemsWithVsaAnswers(List.of(item), sessionId, scratchie, sessionAttempts); List optionDtos = item.getOptionDtos(); for (OptionDTO optionDto : optionDtos) { int[] attempts = new int[optionDtos.size()]; @@ -1905,19 +1908,16 @@ ScratchieUser groupLeader = session.getGroupLeader(); List logs = scratchieAnswerVisitDao.getLogsBySession(sessionId); - + //populate Scratchie items with VSA answers (both from Assessment tool and entered by current learner) + fillItemsWithVsaAnswers(sortedItems, sessionId, scratchie, logs); + for (ScratchieItem item : sortedItems) { ScratchieItemDTO itemDto = new ScratchieItemDTO(); int numberOfAttempts = 0; int mark = -1; boolean isUnraveledOnFirstAttempt = false; String optionsSequence = ""; boolean isMcqItem = item.getQbQuestion().getType() == QbQuestion.TYPE_MULTIPLE_CHOICE; - - //populate Scratchie items with VSA answers, entered by learners in Assessment tool - if (!isMcqItem && scratchie.isAnswersFetchingEnabledAndVsaQuestionsAvailable()) { - fillItemWithVsaOptionDtos(item, sessionId, scratchie, logs); - } // if there is no group leader don't calculate numbers - there aren't any if (groupLeader != null) { @@ -1944,7 +1944,8 @@ for (OptionDTO optionDto : item.getOptionDtos()) { boolean isOptionMet = isMcqItem && optionDto.getQbOptionUid().equals(itemAttempt.getQbOption().getUid()) - || !isMcqItem && optionDto.getAnswer().equals(itemAttempt.getAnswer()); + || !isMcqItem + && isAnswersEqual(item, optionDto.getAnswer(), itemAttempt.getAnswer()); if (isOptionMet) { sequencialLetter = String.valueOf((char) ((optionCount + 'A') - 1)); break; Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/LearningController.java =================================================================== diff -u -r269c13324c6bb998631af858dc8091ad3102ef78 -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/LearningController.java (.../LearningController.java) (revision 269c13324c6bb998631af858dc8091ad3102ef78) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/LearningController.java (.../LearningController.java) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -52,8 +52,10 @@ import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.scratchie.ScratchieConstants; import org.lamsfoundation.lams.tool.scratchie.dto.BurningQuestionItemDTO; +import org.lamsfoundation.lams.tool.scratchie.dto.OptionDTO; import org.lamsfoundation.lams.tool.scratchie.dto.ReflectDTO; import org.lamsfoundation.lams.tool.scratchie.model.Scratchie; +import org.lamsfoundation.lams.tool.scratchie.model.ScratchieAnswerVisitLog; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieBurningQuestion; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieItem; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieSession; @@ -71,11 +73,13 @@ import org.lamsfoundation.lams.web.util.SessionMap; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; @@ -87,7 +91,6 @@ @Controller @RequestMapping("/learning") public class LearningController { - private static Logger log = Logger.getLogger(LearningController.class); @Autowired @@ -97,7 +100,7 @@ * Read scratchie data from database and put them into HttpSession. */ @RequestMapping("/start") - private String start(HttpServletRequest request, HttpServletResponse response) + public String start(HttpServletRequest request, HttpServletResponse response) throws ScratchieApplicationException { ToolAccessMode mode = WebUtil.readToolAccessModeParam(request, AttributeNames.PARAM_MODE, true); @@ -352,7 +355,8 @@ * Record in DB that leader has scratched specified option. And return whether scratchie option is correct or not. */ @RequestMapping("/recordItemScratched") - private String recordItemScratched(HttpServletRequest request, HttpServletResponse response) + @ResponseBody + public String recordItemScratched(HttpServletRequest request, HttpServletResponse response) throws IOException, ScratchieApplicationException { SessionMap sessionMap = getSessionMap(request); final Long toolSessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); @@ -381,8 +385,6 @@ ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); ObjectNode.put(QbConstants.ATTR_OPTION_CORRECT, option.isCorrect()); - response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(ObjectNode); // create a new thread to record item scratched (in order to do this task in parallel not to slow down sending // response back) @@ -394,48 +396,76 @@ }, "LAMS_recordItemScratched_thread"); recordItemScratchedThread.start(); - return null; + response.setContentType("application/json;charset=utf-8"); + return ObjectNode.toString(); } /** * Record in DB that leader has provided this answer. And return whether it's correct or not. */ @RequestMapping("/recordVsaAnswer") - private String recordVsaAnswer(HttpServletRequest request, HttpServletResponse response) + @ResponseBody + public String recordVsaAnswer(HttpServletRequest request, HttpServletResponse response) throws IOException, ScratchieApplicationException { SessionMap sessionMap = getSessionMap(request); final Long toolSessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); final Long itemUid = NumberUtils.createLong(request.getParameter(ScratchieConstants.PARAM_ITEM_UID)); final String answer = request.getParameter("answer"); - + ScratchieSession toolSession = scratchieService.getScratchieSessionBySessionId(toolSessionId); - ScratchieUser leader = getCurrentUser(toolSessionId); + ScratchieItem item = scratchieService.getScratchieItemByUid(itemUid); + final boolean isCaseSensitive = item.getQbQuestion().isCaseSensitive(); + // only leader is allowed to answer if (!toolSession.isUserGroupLeader(leader.getUid())) { return null; } - - // Return whether option is correct or not - ScratchieItem item = scratchieService.getScratchieItemByUid(itemUid); + + // return whether option is correct or not boolean isAnswerCorrect = ScratchieServiceImpl.isItemUnraveledByAnswers(item, List.of(answer)); + // return whether such answer was already logged (and also the answer hash which was logged previously) + int loggedAnswerHash = -1; + //1) search for the answer in logs stored in SessionMap + Collection items = (Collection) sessionMap.get(ScratchieConstants.ATTR_ITEM_LIST); + for (ScratchieItem itemIter : items) { + if (itemIter.getUid().equals(itemUid)) { + for (OptionDTO optionDto : itemIter.getOptionDtos()) { + boolean isAnswerMatched = isCaseSensitive ? optionDto.getAnswer().equals(answer) + : optionDto.getAnswer().equalsIgnoreCase(answer); + if (isAnswerMatched) { + loggedAnswerHash = optionDto.getAnswer().hashCode(); + break; + } + } + break; + } + } + //2) search in DB logs, as SessionMap might not be updated after user answered and didn't refresh the page + if (loggedAnswerHash == -1) { + ScratchieAnswerVisitLog log = scratchieService.getLog(toolSessionId, itemUid, isCaseSensitive, answer); + if (log != null) { + loggedAnswerHash = log.getAnswer().hashCode(); + } + } + ObjectNode objectNode = JsonNodeFactory.instance.objectNode(); objectNode.put("isAnswerCorrect", isAnswerCorrect); - response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(objectNode); + objectNode.put("loggedAnswerHash", loggedAnswerHash); // create a new thread to record item scratched (in order to do this task in parallel not to slow down sending // response back) Thread recordVsaAnswerThread = new Thread(new Runnable() { @Override public void run() { - scratchieService.recordVsaAnswer(toolSessionId, itemUid, answer); + scratchieService.recordVsaAnswer(toolSessionId, itemUid, isCaseSensitive, answer); } }, "LAMS_recordVsaAnswer_thread"); recordVsaAnswerThread.start(); - return null; + response.setContentType("application/json;charset=utf-8"); + return objectNode.toString(); } @RequestMapping("/vsaAutocomplete") @@ -475,7 +505,8 @@ * Stores date when user has started activity with time limit. */ @RequestMapping("/launchTimeLimit") - private String launchTimeLimit(HttpServletRequest request) + @ResponseStatus(HttpStatus.OK) + public void launchTimeLimit(HttpServletRequest request) throws ScratchieApplicationException, SchedulerException { SessionMap sessionMap = getSessionMap(request); final Long toolSessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); @@ -484,18 +515,17 @@ ScratchieUser leader = getCurrentUser(toolSessionId); // only leader is allowed to launch time limit if (!toolSession.isUserGroupLeader(leader.getUid())) { - return null; + return; } scratchieService.launchTimeLimit(toolSessionId); - return null; } /** * Displays results page. When leader gets to this page, scratchingFinished column is set to true for all users. */ @RequestMapping("/showResults") - private String showResults(HttpServletRequest request) throws ScratchieApplicationException, IOException { + public String showResults(HttpServletRequest request) throws ScratchieApplicationException, IOException { SessionMap sessionMap = getSessionMap(request); boolean isReflectOnActivity = (Boolean) sessionMap.get(ScratchieConstants.ATTR_REFLECTION_ON); boolean isBurningQuestionsEnabled = (Boolean) sessionMap @@ -565,7 +595,8 @@ * Saves newly entered burning question. Used by jqGrid cellediting feature. */ @RequestMapping("/editBurningQuestion") - private String editBurningQuestion(HttpServletRequest request) { + @ResponseStatus(HttpStatus.OK) + public void editBurningQuestion(HttpServletRequest request) { if (!StringUtils.isEmpty(request.getParameter(ScratchieConstants.ATTR_ITEM_UID)) && !StringUtils.isEmpty(request.getParameter(ScratchieConstants.PARAM_SESSION_ID))) { @@ -576,12 +607,11 @@ String question = request.getParameter(ScratchieConstants.ATTR_BURNING_QUESTION_PREFIX); scratchieService.saveBurningQuestion(sessionId, itemUid, question); } - - return null; } @RequestMapping("/like") - private String like(HttpServletRequest request, HttpServletResponse response) + @ResponseBody + public String like(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, ScratchieApplicationException { SessionMap sessionMap = getSessionMap(request); final Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); @@ -600,12 +630,12 @@ ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); ObjectNode.put("added", added); response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(ObjectNode); - return null; + return ObjectNode.toString(); } @RequestMapping("/removeLike") - private String removeLike(HttpServletRequest request, HttpServletResponse response) + @ResponseBody + public String removeLike(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, ScratchieApplicationException { SessionMap sessionMap = getSessionMap(request); final Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); @@ -624,15 +654,14 @@ ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); ObjectNode.put("added", true); response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(ObjectNode); - return null; + return ObjectNode.toString(); } /** * Finish learning session. */ @RequestMapping("/finish") - private String finish(HttpServletRequest request) { + public String finish(HttpServletRequest request) { SessionMap sessionMap = getSessionMap(request); final Long toolSessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); HttpSession ss = SessionManager.getSession(); @@ -652,8 +681,8 @@ * Autosaves burning questions. Only leaders can perform it. */ @RequestMapping("/autosaveBurningQuestions") - @ResponseBody - private void autosaveBurningQuestions(HttpServletRequest request) throws ScratchieApplicationException { + @ResponseStatus(HttpStatus.OK) + public void autosaveBurningQuestions(HttpServletRequest request) throws ScratchieApplicationException { SessionMap sessionMap = getSessionMap(request); final Long sessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); @@ -701,7 +730,7 @@ * Display empty reflection form. */ @RequestMapping("/newReflection") - private String newReflection(@ModelAttribute("reflectionForm") ReflectionForm reflectionForm, + public String newReflection(@ModelAttribute("reflectionForm") ReflectionForm reflectionForm, HttpServletRequest request) throws ScratchieApplicationException, IOException { String sessionMapID = WebUtil.readStrParam(request, ScratchieConstants.ATTR_SESSION_MAP_ID); SessionMap sessionMap = getSessionMap(request); @@ -743,7 +772,7 @@ * Submit reflection form input database. Only leaders can submit reflections. */ @RequestMapping("/submitReflection") - private String submitReflection(@ModelAttribute("reflectionForm") ReflectionForm reflectionForm, + public String submitReflection(@ModelAttribute("reflectionForm") ReflectionForm reflectionForm, HttpServletRequest request) throws ScratchieApplicationException { final Integer userId = reflectionForm.getUserID(); final String entryText = reflectionForm.getEntryText(); Index: lams_tool_scratchie/web/pages/learning/learning.jsp =================================================================== diff -u -r3126fb6636e4164bdc6e539eab16ed2a7618fe7e -r8d982bb83bb4040e0eba0076df8ab05ff715f2e9 --- lams_tool_scratchie/web/pages/learning/learning.jsp (.../learning.jsp) (revision 3126fb6636e4164bdc6e539eab16ed2a7618fe7e) +++ lams_tool_scratchie/web/pages/learning/learning.jsp (.../learning.jsp) (revision 8d982bb83bb4040e0eba0076df8ab05ff715f2e9) @@ -41,16 +41,6 @@