Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== diff -u -r1e85a36d6397d66fa9cc46b334e2ef2bef8af4f6 -r193e1ddf0d23bb2d90636908378b8dbe4a089dbc --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 1e85a36d6397d66fa9cc46b334e2ef2bef8af4f6) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java (.../AssessmentConstants.java) (revision 193e1ddf0d23bb2d90636908378b8dbe4a089dbc) @@ -227,7 +227,10 @@ public static final String ATTR_ALL_GROUP_USERS = "allGroupUsers"; //flux management + public static final String COMPLETION_CHARTS_UPDATE_SINK_NAME = "assessment completion chart updated"; + public static final String ANSWERS_UPDATED_SINK_NAME = "assessment learner answers updated"; + public static final String LEARNER_TRAVERSED_SINK_NAME = "assessment learner traversed"; public static final String COMPLETION_CHARTS_UPDATE_FLUX_NAME = "assessment completion chart updated"; -} +} \ No newline at end of file Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentResultDAOHibernate.java =================================================================== diff -u -r02b91789ae056e5c483db117bfa3763022d5c8a7 -r193e1ddf0d23bb2d90636908378b8dbe4a089dbc --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentResultDAOHibernate.java (.../AssessmentResultDAOHibernate.java) (revision 02b91789ae056e5c483db117bfa3763022d5c8a7) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentResultDAOHibernate.java (.../AssessmentResultDAOHibernate.java) (revision 193e1ddf0d23bb2d90636908378b8dbe4a089dbc) @@ -153,7 +153,6 @@ + " JOIN lams_user AS u USING (user_id)" + " JOIN tl_laasse10_session AS s USING (session_id)" + " WHERE ar.latest = 1 AND ar.finish_date IS NOT NULL" - + " AND (a.use_select_leader_tool_ouput = 0 OR s.group_leader_uid = ar.user_uid)" + " AND a.content_id = :toolContentId" + " ORDER BY user_name"; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -rf8f156c0f021d60857760ea60579a41e1380288c -r193e1ddf0d23bb2d90636908378b8dbe4a089dbc --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision f8f156c0f021d60857760ea60579a41e1380288c) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 193e1ddf0d23bb2d90636908378b8dbe4a089dbc) @@ -152,6 +152,8 @@ import reactor.core.publisher.Flux; +import javax.swing.text.AbstractDocument; + /** * @author Andrey Balan */ @@ -207,9 +209,13 @@ public AssessmentServiceImpl() { FluxRegistry.initFluxMap(AssessmentConstants.COMPLETION_CHARTS_UPDATE_FLUX_NAME, - AssessmentConstants.ANSWERS_UPDATED_SINK_NAME, null, + AssessmentConstants.COMPLETION_CHARTS_UPDATE_SINK_NAME, null, (Long toolContentId) -> UriUtils.encode(getCompletionChartsData(toolContentId), StandardCharsets.UTF_8.toString()), FluxMap.SHORT_THROTTLE, FluxMap.STANDARD_TIMEOUT); + FluxRegistry.bindSink(AssessmentConstants.LEARNER_TRAVERSED_SINK_NAME, + AssessmentConstants.COMPLETION_CHARTS_UPDATE_SINK_NAME, contentId -> contentId); + FluxRegistry.bindSink(AssessmentConstants.ANSWERS_UPDATED_SINK_NAME, + AssessmentConstants.COMPLETION_CHARTS_UPDATE_SINK_NAME, contentId -> contentId); } // ******************************************************************************* @@ -1343,6 +1349,9 @@ } catch (ToolException e) { throw new AssessmentApplicationException(e); } + + FluxRegistry.emit(AssessmentConstants.LEARNER_TRAVERSED_SINK_NAME, assessment.getContentId()); + return nextUrl; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java =================================================================== diff -u -r0586f1081f3b7e5b550da93b64463175ea698c28 -r193e1ddf0d23bb2d90636908378b8dbe4a089dbc --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 0586f1081f3b7e5b550da93b64463175ea698c28) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 193e1ddf0d23bb2d90636908378b8dbe4a089dbc) @@ -52,6 +52,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.flux.FluxRegistry; import org.lamsfoundation.lams.lesson.Lesson; import org.lamsfoundation.lams.lesson.service.ILessonService; import org.lamsfoundation.lams.logevent.LearnerInteractionEvent; @@ -156,8 +157,9 @@ * This method will avoid read database again and lost un-saved resouce question lost when user "refresh page". */ @RequestMapping("/start") - public String start(HttpServletRequest request) throws ServletException, IllegalAccessException, - InstantiationException, InvocationTargetException, NoSuchMethodException { + public String start(HttpServletRequest request) + throws ServletException, IllegalAccessException, InstantiationException, InvocationTargetException, + NoSuchMethodException { // initialize Session Map SessionMap sessionMap = new SessionMap<>(); @@ -203,8 +205,8 @@ AssessmentResult lastLeaderResult = service.getLastAssessmentResult(assessment.getUid(), groupLeader.getUserId()); - boolean isLastAttemptFinishedByLeader = lastLeaderResult != null - && lastLeaderResult.getFinishDate() != null; + boolean isLastAttemptFinishedByLeader = + lastLeaderResult != null && lastLeaderResult.getFinishDate() != null; // forwards to the waitForLeader pages if (assessment.getRelativeTimeLimit() != 0 && !isUserLeader && !isLastAttemptFinishedByLeader) { @@ -260,7 +262,8 @@ } //add random questions (actually replacing them with real ones) AssessmentResult lastResult = service.getLastAssessmentResult(assessment.getUid(), user.getUserId()); - Map questionToResultMap = lastResult == null ? null + Map questionToResultMap = lastResult == null + ? null : lastResult.getQuestionResults().stream() .collect(Collectors.toMap(q -> q.getQbToolQuestion().getUid(), q -> q)); for (QuestionReference questionReference : questionReferences) { @@ -271,13 +274,13 @@ if (lastResult == null) { //pick element randomly Random rand = new Random(System.currentTimeMillis()); - randomQuestion = (AssessmentQuestion) availableRandomQuestions.toArray()[rand - .nextInt(availableRandomQuestions.size())]; + randomQuestion = (AssessmentQuestion) availableRandomQuestions.toArray()[rand.nextInt( + availableRandomQuestions.size())]; availableRandomQuestions.remove(randomQuestion); } else { // pick element from the last result - for (Iterator iter = availableRandomQuestions.iterator(); iter.hasNext();) { + for (Iterator iter = availableRandomQuestions.iterator(); iter.hasNext(); ) { AssessmentQuestion availableRandomQuestion = iter.next(); if (questionToResultMap.containsKey(availableRandomQuestion.getUid())) { randomQuestion = availableRandomQuestion; @@ -295,8 +298,8 @@ } //user is allowed to answer questions if assessment activity doesn't have leaders or he is the leader - boolean hasEditRight = !assessment.isUseSelectLeaderToolOuput() - || assessment.isUseSelectLeaderToolOuput() && isUserLeader; + boolean hasEditRight = + !assessment.isUseSelectLeaderToolOuput() || assessment.isUseSelectLeaderToolOuput() && isUserLeader; //showResults if user has finished the last result boolean showResults = (lastResult != null) && (lastResult.getFinishDate() != null); @@ -458,9 +461,9 @@ } // display Etherpads after each question - boolean questionEtherpadEnabled = assessment.isUseSelectLeaderToolOuput() - && assessment.isQuestionEtherpadEnabled() - && StringUtils.isNotBlank(Configuration.get(ConfigurationKeys.ETHERPAD_API_KEY)); + boolean questionEtherpadEnabled = + assessment.isUseSelectLeaderToolOuput() && assessment.isQuestionEtherpadEnabled() + && StringUtils.isNotBlank(Configuration.get(ConfigurationKeys.ETHERPAD_API_KEY)); request.setAttribute(AssessmentConstants.ATTR_IS_QUESTION_ETHERPAD_ENABLED, questionEtherpadEnabled); if (questionEtherpadEnabled) { // get all users from the group, even if they did not reach the Scratchie yet @@ -485,15 +488,15 @@ } /** - * Auxiliary method to be called by nextPage(HttpServletRequest request, - * HttpServletResponse response) or submitAll. + * Auxiliary method to be called by nextPage(HttpServletRequest request, HttpServletResponse response) or + * submitAll. * * @param mapping * @param request * @param isAnswersValidationFailed - * submitAll() method may set it as true in case some of the pages miss required answers + * submitAll() method may set it as true in case some of the pages miss required answers * @param pageNumberWithUnasweredQuestions - * page number with questions required to be answered + * page number with questions required to be answered * @return */ @SuppressWarnings("unchecked") @@ -514,8 +517,8 @@ } int questionNumberingOffset = 0; - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); for (int i = 0; i < pageNumberToOpen - 1; i++) { Set questionsForOnePage = pagedQuestionDtos.get(i); questionNumberingOffset += questionsForOnePage.size(); @@ -555,8 +558,8 @@ throws ServletException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { SessionMap sessionMap = getSessionMap(request); int pageNumber = (Integer) sessionMap.get(AssessmentConstants.ATTR_PAGE_NUMBER); - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); Long userId = ((AssessmentUser) sessionMap.get(AssessmentConstants.ATTR_USER)).getUserId(); Long toolSessionId = (Long) sessionMap.get(AssessmentConstants.ATTR_TOOL_SESSION_ID); Assessment assessment = service.getAssessmentBySessionId(toolSessionId); @@ -626,8 +629,8 @@ // result was not stored in case user was prohibited from submitting (or autosubmitting) answers (e.g. when // using 2 browsers). Then show last stored results if (!isResultsStored) { - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); Long assessmentUid = ((Assessment) sessionMap.get(AssessmentConstants.ATTR_ASSESSMENT)).getUid(); Long userId = ((AssessmentUser) sessionMap.get(AssessmentConstants.ATTR_USER)).getUserId(); service.loadupLastAttempt(assessmentUid, userId, pagedQuestionDtos); @@ -653,8 +656,8 @@ ToolAccessMode mode = (ToolAccessMode) sessionMap.get(AttributeNames.ATTR_MODE); Assessment assessment = service.getAssessmentBySessionId(toolSessionId); AssessmentUser assessmentUser = (AssessmentUser) sessionMap.get(AssessmentConstants.ATTR_USER); - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); Long userId = assessmentUser.getUserId(); service.unsetSessionFinished(toolSessionId, userId); @@ -828,14 +831,14 @@ * * @param request * @param pageNumber - * number of the page to process + * number of the page to process */ @SuppressWarnings("unchecked") private void storeUserAnswersIntoSessionMap(HttpServletRequest request, int pageNumber) { SessionMap sessionMap = getSessionMap(request); Assessment assessment = (Assessment) sessionMap.get(AssessmentConstants.ATTR_ASSESSMENT); - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); Set questionsForOnePage = pagedQuestionDtos.get(pageNumber - 1); for (int i = 0; i < questionsForOnePage.size(); i++) { @@ -859,12 +862,12 @@ for (OptionDTO optionDto : questionDto.getOptionDtos()) { boolean answerBoolean = false; if (questionDto.isMultipleAnswersAllowed()) { - String answer = request - .getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getUid()); + String answer = request.getParameter( + AssessmentConstants.ATTR_QUESTION_PREFIX + i + "_" + optionDto.getUid()); answerBoolean = StringUtils.isNotBlank(answer); } else { - String optionUidSelectedStr = request - .getParameter(AssessmentConstants.ATTR_QUESTION_PREFIX + i); + String optionUidSelectedStr = request.getParameter( + AssessmentConstants.ATTR_QUESTION_PREFIX + i); if (optionUidSelectedStr != null) { Long optionUidSelected = Long.parseLong(optionUidSelectedStr); answerBoolean = optionDto.getUid().equals(optionUidSelected); @@ -964,8 +967,8 @@ */ @SuppressWarnings("unchecked") private int validateAnswers(SessionMap sessionMap) { - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); //array of missing required questions boolean isAllQuestionsAnswered = true; @@ -995,10 +998,9 @@ isAnswered |= optionDto.getAnswerInt() != 0; } - } else if ((questionType == QbQuestion.TYPE_VERY_SHORT_ANSWERS) - || (questionType == QbQuestion.TYPE_NUMERICAL) - || (questionType == QbQuestion.TYPE_TRUE_FALSE) - || (questionType == QbQuestion.TYPE_ESSAY)) { + } else if ((questionType == QbQuestion.TYPE_VERY_SHORT_ANSWERS) || (questionType + == QbQuestion.TYPE_NUMERICAL) || (questionType == QbQuestion.TYPE_TRUE_FALSE) || ( + questionType == QbQuestion.TYPE_ESSAY)) { isAnswered |= StringUtils.isNotBlank(questionDto.getAnswer()); } else if (questionType == QbQuestion.TYPE_ORDERING) { @@ -1055,8 +1057,8 @@ */ @SuppressWarnings("unchecked") private void showResults(HttpServletRequest request, SessionMap sessionMap) { - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); Assessment assessment = (Assessment) sessionMap.get(AssessmentConstants.ATTR_ASSESSMENT); AssessmentUser user = (AssessmentUser) sessionMap.get(AssessmentConstants.ATTR_USER); Long userId = user.getUserId(); @@ -1081,8 +1083,8 @@ //question feedback questionDto.setQuestionFeedback(null); for (OptionDTO optionDto : questionDto.getOptionDtos()) { - if (questionResult.getQbOption() != null - && optionDto.getUid().equals(questionResult.getQbOption().getUid())) { + if (questionResult.getQbOption() != null && optionDto.getUid() + .equals(questionResult.getQbOption().getUid())) { questionDto.setQuestionFeedback(optionDto.getFeedback()); break; } @@ -1114,7 +1116,8 @@ } } - Date timeTaken = result.getFinishDate() == null ? new Date(0) + Date timeTaken = result.getFinishDate() == null + ? new Date(0) : new Date(result.getFinishDate().getTime() - result.getStartDate().getTime()); result.setTimeTaken(timeTaken); if (assessment.isAllowOverallFeedbackAfterQuestion()) { @@ -1124,8 +1127,8 @@ int lastBorder = 0; for (int i = overallFeedbacks.size() - 1; i >= 0; i--) { AssessmentOverallFeedback overallFeedback = overallFeedbacks.get(i); - if ((percentageCorrectAnswers >= lastBorder) - && (percentageCorrectAnswers <= overallFeedback.getGradeBoundary())) { + if ((percentageCorrectAnswers >= lastBorder) && (percentageCorrectAnswers + <= overallFeedback.getGradeBoundary())) { result.setOverallFeedback(overallFeedback.getFeedback()); break; } @@ -1200,8 +1203,8 @@ } ToolActivityRatingCriteria criterion = null; if (criteria.isEmpty()) { - criterion = (ToolActivityRatingCriteria) RatingCriteria - .getRatingCriteriaInstance(RatingCriteria.TOOL_ACTIVITY_CRITERIA_TYPE); + criterion = (ToolActivityRatingCriteria) RatingCriteria.getRatingCriteriaInstance( + RatingCriteria.TOOL_ACTIVITY_CRITERIA_TYPE); criterion.setTitle(service.getMessage("label.answer.rating.title")); criterion.setOrderId(1); criterion.setCommentsEnabled(true); @@ -1227,7 +1230,8 @@ Long ratingUserId = null; if (user != null) { - ratingUserId = user.getSession().getGroupLeader() == null ? user.getUserId() + ratingUserId = user.getSession().getGroupLeader() == null + ? user.getUserId() : user.getSession().getGroupLeader().getUserId(); } @@ -1236,8 +1240,8 @@ List> questionResultsPerSession = summary.getQuestionResultsPerSession(); if (questionResultsPerSession != null) { - List questionResults = questionResultsPerSession - .remove((int) userSessionIndex); + List questionResults = questionResultsPerSession.remove( + (int) userSessionIndex); Set questionItemIds = questionResultsPerSession.stream() .filter(l -> l != null && !l.isEmpty() && l.get(l.size() - 1).getUid() != null) @@ -1365,8 +1369,8 @@ private boolean storeUserAnswersIntoDatabase(SessionMap sessionMap, boolean isAutosave) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { - List> pagedQuestionDtos = (List>) sessionMap - .get(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); + List> pagedQuestionDtos = (List>) sessionMap.get( + AssessmentConstants.ATTR_PAGED_QUESTION_DTOS); Long toolSessionId = (Long) sessionMap.get(AssessmentConstants.ATTR_TOOL_SESSION_ID); Long userId = ((AssessmentUser) sessionMap.get(AssessmentConstants.ATTR_USER)).getUserId(); ToolAccessMode mode = (ToolAccessMode) sessionMap.get(AttributeNames.ATTR_MODE); @@ -1393,6 +1397,8 @@ AssessmentSession session = service.getSessionBySessionId(sessionId); assessmentUser = new AssessmentUser(user, session); service.createUser(assessmentUser); + + FluxRegistry.emit(AssessmentConstants.LEARNER_TRAVERSED_SINK_NAME, session.getAssessment().getContentId()); } return assessmentUser; } @@ -1419,4 +1425,4 @@ request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); return (SessionMap) request.getSession().getAttribute(sessionMapID); } -} +} \ No newline at end of file