Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java =================================================================== diff -u -r21c27a799a8473c3a8844258ac269683831db33e -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 21c27a799a8473c3a8844258ac269683831db33e) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -51,6 +51,8 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.lesson.Lesson; +import org.lamsfoundation.lams.lesson.service.ILessonService; import org.lamsfoundation.lams.notebook.model.NotebookEntry; import org.lamsfoundation.lams.qb.model.QbOption; import org.lamsfoundation.lams.qb.model.QbQuestion; @@ -59,6 +61,7 @@ import org.lamsfoundation.lams.rating.model.RatingCriteria; import org.lamsfoundation.lams.rating.model.ToolActivityRatingCriteria; import org.lamsfoundation.lams.rating.service.IRatingService; +import org.lamsfoundation.lams.security.ISecurityService; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.dto.OptionDTO; @@ -121,6 +124,12 @@ @Autowired private IUserManagementService userManagementService; + @Autowired + private ILessonService lessonService; + + @Autowired + private ISecurityService securityService; + /** * Read assessment data from database and put them into HttpSession. It will redirect to init.do directly after this * method run successfully. @@ -151,7 +160,7 @@ user = getSpecifiedUser(service, toolSessionId, WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID, false)); } else { - user = getCurrentUser(toolSessionId); + user = getCurrentAssessmentUser(toolSessionId); } Assessment assessment = service.getAssessmentBySessionId(toolSessionId); @@ -1094,111 +1103,180 @@ // if answers are going to be disclosed, prepare data for the table in results page if (assessment.isAllowDiscloseAnswers()) { - // such entities should not go into session map, but as request attributes instead - SortedSet sessions = new TreeSet<>(new AssessmentSessionComparator()); - sessions.addAll(service.getSessionsByContentId(assessment.getContentId())); + populateDisclosedAnswers(request, assessment, user); + } + } - Long userSessionId = user.getSession().getSessionId(); - Integer userSessionIndex = null; - int sessionIndex = 0; - // find user session in order to put it first - List sessionList = new ArrayList<>(); - for (AssessmentSession session : sessions) { - if (userSessionId.equals(session.getSessionId())) { - userSessionIndex = sessionIndex; - } else { - sessionList.add(session); - } - sessionIndex++; - } - // put user's own group first - sessionList.add(0, user.getSession()); - request.setAttribute("sessions", sessionList); + //calculate whether isResubmitAllowed + int attemptsAllowed = assessment.getAttemptsAllowed(); + boolean isResubmitAllowed = ((attemptsAllowed > dbResultCount) | (attemptsAllowed == 0)); + sessionMap.put(AssessmentConstants.ATTR_IS_RESUBMIT_ALLOWED, isResubmitAllowed); + } - Map questionSummaries = service.getQuestionSummaryForExport(assessment); - request.setAttribute("questionSummaries", questionSummaries); + private void populateDisclosedAnswers(HttpServletRequest request, Assessment assessment, AssessmentUser user) { + // such entities should not go into session map, but as request attributes instead + SortedSet sessions = new TreeSet<>(new AssessmentSessionComparator()); + sessions.addAll(service.getSessionsByContentId(assessment.getContentId())); - // Assessment currently supports only one place for ratings. - // It is rating other groups' answers on results page. - // Criterion gets automatically created and there must be only one. - List criteria = ratingService.getCriteriasByToolContentId(assessment.getContentId()); - if (criteria.size() >= 2) { - throw new IllegalArgumentException("There can be only one criterion for an Assessment activity. " - + "If other criteria are introduced, the criterion for rating other groups' answers needs to become uniquely identifiable."); - } - ToolActivityRatingCriteria criterion = null; - if (criteria.isEmpty()) { - criterion = (ToolActivityRatingCriteria) RatingCriteria - .getRatingCriteriaInstance(RatingCriteria.TOOL_ACTIVITY_CRITERIA_TYPE); - criterion.setTitle(service.getMessage("label.answer.rating.title")); - criterion.setOrderId(1); - criterion.setCommentsEnabled(true); - criterion.setRatingStyle(RatingCriteria.RATING_STYLE_STAR); - criterion.setToolContentId(assessment.getContentId()); + Long userSessionId = user == null ? null : user.getSession().getSessionId(); + Integer userSessionIndex = null; + int sessionIndex = 0; + // find user session in order to put it first + List sessionList = new ArrayList<>(); + for (AssessmentSession session : sessions) { + if (userSessionId != null && userSessionId.equals(session.getSessionId())) { + userSessionIndex = sessionIndex; + } else { + sessionList.add(session); + } + sessionIndex++; + } + // put user's own group first + if (user != null) { + sessionList.add(0, user.getSession()); + } + request.setAttribute("sessions", sessionList); - userManagementService.save(criterion); - } else { - criterion = (ToolActivityRatingCriteria) criteria.get(0); - } + Map questionSummaries = service.getQuestionSummaryForExport(assessment); + request.setAttribute("questionSummaries", questionSummaries); - // Item IDs are AssessmentQuestionResults UIDs, i.e. a user answer for a particular question - // Get all item IDs no matter which session they belong to. - Set itemIds = questionSummaries.values().stream() - .flatMap(s -> s.getQuestionResultsPerSession().stream()) - .collect(Collectors.mapping(l -> l.get(l.size() - 1).getUid(), Collectors.toSet())); + // Assessment currently supports only one place for ratings. + // It is rating other groups' answers on results page. + // Criterion gets automatically created and there must be only one. + List criteria = ratingService.getCriteriasByToolContentId(assessment.getContentId()); + if (criteria.size() >= 2) { + throw new IllegalArgumentException("There can be only one criterion for an Assessment activity. " + + "If other criteria are introduced, the criterion for rating other groups' answers needs to become uniquely identifiable."); + } + ToolActivityRatingCriteria criterion = null; + if (criteria.isEmpty()) { + criterion = (ToolActivityRatingCriteria) RatingCriteria + .getRatingCriteriaInstance(RatingCriteria.TOOL_ACTIVITY_CRITERIA_TYPE); + criterion.setTitle(service.getMessage("label.answer.rating.title")); + criterion.setOrderId(1); + criterion.setCommentsEnabled(true); + criterion.setRatingStyle(RatingCriteria.RATING_STYLE_STAR); + criterion.setToolContentId(assessment.getContentId()); - List itemRatingDtos = ratingService.getRatingCriteriaDtos(assessment.getContentId(), - null, itemIds, true, userId); - // Mapping of Item ID -> DTO - Map itemRatingDtoMap = itemRatingDtos.stream() - .collect(Collectors.toMap(ItemRatingDTO::getItemId, Function.identity())); + userManagementService.save(criterion); + } else { + criterion = (ToolActivityRatingCriteria) criteria.get(0); + } - Long ratingUserId = user.getSession().getGroupLeader() == null ? userId - : user.getSession().getGroupLeader().getUserId(); + // Item IDs are AssessmentQuestionResults UIDs, i.e. a user answer for a particular question + // Get all item IDs no matter which session they belong to. + Set itemIds = questionSummaries.values().stream().flatMap(s -> s.getQuestionResultsPerSession().stream()) + .collect(Collectors.mapping(l -> l.get(l.size() - 1).getUid(), Collectors.toSet())); - for (QuestionSummary summary : questionSummaries.values()) { + List itemRatingDtos = ratingService.getRatingCriteriaDtos(assessment.getContentId(), null, + itemIds, true, user == null ? null : user.getUserId()); + // Mapping of Item ID -> DTO + Map itemRatingDtoMap = itemRatingDtos.stream() + .collect(Collectors.toMap(ItemRatingDTO::getItemId, Function.identity())); - List> questionResultsPerSession = summary - .getQuestionResultsPerSession(); - if (questionResultsPerSession != null) { - List questionResults = questionResultsPerSession - .remove((int) userSessionIndex); - // user or his leader should rate all other groups' answers in order to show ratings left for own group - int expectedRatedItemCount = questionResultsPerSession.size(); + Long ratingUserId = null; + if (user != null) { + ratingUserId = user.getSession().getGroupLeader() == null ? user.getUserId() + : user.getSession().getGroupLeader().getUserId(); + } - Set questionItemIds = questionResultsPerSession.stream() - .collect(Collectors.mapping(l -> l.get(l.size() - 1).getUid(), Collectors.toSet())); + for (QuestionSummary summary : questionSummaries.values()) { - // question results need to be in the same order as sessions, i.e. user group first - questionResultsPerSession.add(0, questionResults); + List> questionResultsPerSession = summary.getQuestionResultsPerSession(); + if (questionResultsPerSession != null) { + List questionResults = userSessionIndex == null ? null + : questionResultsPerSession.remove((int) userSessionIndex); + // user or his leader should rate all other groups' answers in order to show ratings left for own group + int expectedRatedItemCount = questionResultsPerSession.size(); - // count how many ratings user or his leader left - // maybe exact session ID matching should be used here to make sure - int ratedItemCount = 0; - for (Long questionItemId : questionItemIds) { - ItemRatingDTO itemRatingDTO = itemRatingDtoMap.get(questionItemId); - for (RatingCommentDTO ratingCommentDTO : itemRatingDTO.getCommentDtos()) { - if (ratingCommentDTO.getUserId().equals(ratingUserId)) { - ratedItemCount++; - } - } - } + Set questionItemIds = questionResultsPerSession.stream() + .collect(Collectors.mapping(l -> l.get(l.size() - 1).getUid(), Collectors.toSet())); - summary.setShowOwnGroupRating(ratedItemCount == expectedRatedItemCount); + if (questionResults != null) { + // question results need to be in the same order as sessions, i.e. user group first + questionResultsPerSession.add(0, questionResults); + } + + // count how many ratings user or his leader left + // maybe exact session ID matching should be used here to make sure + int ratedItemCount = 0; + for (Long questionItemId : questionItemIds) { + ItemRatingDTO itemRatingDTO = itemRatingDtoMap.get(questionItemId); + for (RatingCommentDTO ratingCommentDTO : itemRatingDTO.getCommentDtos()) { + if (ratingCommentDTO.getUserId().equals(ratingUserId)) { + ratedItemCount++; + } } } - request.setAttribute("itemRatingDtos", itemRatingDtoMap); + summary.setShowOwnGroupRating(ratedItemCount == expectedRatedItemCount); } } - //calculate whether isResubmitAllowed - int attemptsAllowed = assessment.getAttemptsAllowed(); - boolean isResubmitAllowed = ((attemptsAllowed > dbResultCount) | (attemptsAllowed == 0)); - sessionMap.put(AssessmentConstants.ATTR_IS_RESUBMIT_ALLOWED, isResubmitAllowed); + request.setAttribute("itemRatingDtos", itemRatingDtoMap); } /** + * A view to show other groups' answers and correct answers without specyfing a learner + */ + @RequestMapping("/showResultsForTeacher") + public String showResultsForTeacher(HttpServletRequest request) { + long toolContentId = WebUtil.readLongParam(request, AssessmentConstants.PARAM_TOOL_CONTENT_ID); + UserDTO user = LearningController.getCurrentUser(); + Lesson lesson = lessonService.getLessonByToolContentId(toolContentId); + + securityService.isLessonMonitor(lesson.getLessonId(), user.getUserID(), "show Assessment results for teacher", + true); + + // initialize Session Map + SessionMap sessionMap = new SessionMap<>(); + request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); + + Assessment assessment = service.getAssessmentByContentId(toolContentId); + + Set questionReferences = new TreeSet<>(new SequencableComparator()); + questionReferences.addAll(assessment.getQuestionReferences()); + HashMap questionToReferenceMap = new HashMap<>(); + + //add non-random questions + for (QuestionReference questionReference : questionReferences) { + if (!questionReference.isRandomQuestion()) { + AssessmentQuestion question = questionReference.getQuestion(); + questionToReferenceMap.put(questionReference.getUid(), question); + } + } + + LinkedList questionDtos = new LinkedList<>(); + for (QuestionReference questionReference : questionReferences) { + AssessmentQuestion question = questionToReferenceMap.get(questionReference.getUid()); + + QuestionDTO questionDto = question.getQuestionDTO(); + questionDto.setMaxMark(questionReference.getMaxMark()); + questionDtos.add(questionDto); + } + + // paging - always all questions on a single page for teachers + List> pagedQuestionDtos = new ArrayList<>(); + LinkedHashSet questionsForOnePage = new LinkedHashSet<>(questionDtos); + pagedQuestionDtos.add(questionsForOnePage); + + populateDisclosedAnswers(request, assessment, null); + + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMap.getSessionID()); + request.setAttribute(AttributeNames.ATTR_MODE, ToolAccessMode.TEACHER); + sessionMap.put(AssessmentConstants.ATTR_TITLE, assessment.getTitle()); + sessionMap.put(AssessmentConstants.ATTR_INSTRUCTIONS, assessment.getInstructions()); + sessionMap.put(AssessmentConstants.ATTR_PAGED_QUESTION_DTOS, pagedQuestionDtos); + sessionMap.put(AssessmentConstants.ATTR_QUESTION_NUMBERING_OFFSET, 1); + sessionMap.put(AssessmentConstants.ATTR_PAGE_NUMBER, 1); + sessionMap.put(AssessmentConstants.ATTR_ASSESSMENT, assessment); + sessionMap.put(AssessmentConstants.CONFIG_KEY_HIDE_TITLES, + Boolean.valueOf(service.getConfigValue(AssessmentConstants.CONFIG_KEY_HIDE_TITLES))); + + return "pages/learning/results"; + } + + /** * Store user answers in DB in last unfinished attempt and notify teachers about it. */ @SuppressWarnings("unchecked") @@ -1217,21 +1295,18 @@ // notify teachers if ((mode != null) && !mode.isTeacher() && !isAutosave && isResultsStored && assessment.isNotifyTeachersOnAttemptCompletion()) { - AssessmentUser assessmentUser = getCurrentUser(toolSessionId); + AssessmentUser assessmentUser = getCurrentAssessmentUser(toolSessionId); String fullName = assessmentUser.getLastName() + " " + assessmentUser.getFirstName(); service.notifyTeachersOnAttemptCompletion(toolSessionId, fullName); } return isResultsStored; } - private AssessmentUser getCurrentUser(Long sessionId) { - // try to get form system session - HttpSession ss = SessionManager.getSession(); - // get back login user DTO - UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); - AssessmentUser assessmentUser = service.getUserByIDAndSession(user.getUserID().longValue(), sessionId); + private AssessmentUser getCurrentAssessmentUser(Long sessionId) { + UserDTO user = LearningController.getCurrentUser(); + AssessmentUser assessmentUser = service.getUserByIDAndSession(user.getUserID().longValue(), sessionId); if (assessmentUser == null) { AssessmentSession session = service.getSessionBySessionId(sessionId); assessmentUser = new AssessmentUser(user, session); @@ -1240,6 +1315,13 @@ return assessmentUser; } + private static UserDTO getCurrentUser() { + // try to get form system session + HttpSession ss = SessionManager.getSession(); + // get back login user DTO + return (UserDTO) ss.getAttribute(AttributeNames.USER); + } + private AssessmentUser getSpecifiedUser(IAssessmentService service, Long sessionId, Integer userId) { AssessmentUser assessmentUser = service.getUserByIDAndSession(userId.longValue(), sessionId); if (assessmentUser == null) { Index: lams_tool_assessment/web/pages/learning/results.jsp =================================================================== diff -u -r94e96499672682a3f2abcde0f4127648a71e1c2c -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/web/pages/learning/results.jsp (.../results.jsp) (revision 94e96499672682a3f2abcde0f4127648a71e1c2c) +++ lams_tool_assessment/web/pages/learning/results.jsp (.../results.jsp) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -45,20 +45,23 @@ @@ -135,14 +138,16 @@ - +
- <%@ include file="results/attemptsummary.jsp"%> + + <%@ include file="results/attemptsummary.jsp"%> +
Index: lams_tool_assessment/web/pages/learning/results/essay.jsp =================================================================== diff -u -r9007e50ca508c5ec3312cd880e6df2d1ec3dab1e -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/web/pages/learning/results/essay.jsp (.../essay.jsp) (revision 9007e50ca508c5ec3312cd880e6df2d1ec3dab1e) +++ lams_tool_assessment/web/pages/learning/results/essay.jsp (.../essay.jsp) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -1,19 +1,21 @@ <%@ include file="/common/taglibs.jsp"%> -
- -
+ +
+ +
+ +
+ + + + +
+ ${question.answer} +
+
+
-
- - - - -
- ${question.answer} -
-
- Index: lams_tool_assessment/web/pages/learning/results/markhedging.jsp =================================================================== diff -u -r2b3d3b2f61d37cf2fa7cccc0cf4565e5dfc4b88e -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/web/pages/learning/results/markhedging.jsp (.../markhedging.jsp) (revision 2b3d3b2f61d37cf2fa7cccc0cf4565e5dfc4b88e) +++ lams_tool_assessment/web/pages/learning/results/markhedging.jsp (.../markhedging.jsp) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -26,17 +26,18 @@ @@ -51,7 +52,7 @@
- - + + +
- + @@ -81,15 +82,17 @@
- -
- - - ${question.maxMark} - - - - + + +
+ + + ${question.maxMark} - -
+ + + + + +
+
\ No newline at end of file Index: lams_tool_assessment/web/pages/learning/results/matchingpairs.jsp =================================================================== diff -u -r9c3a64b840753192b333afb73c8fe7bdb54be638 -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/web/pages/learning/results/matchingpairs.jsp (.../matchingpairs.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) +++ lams_tool_assessment/web/pages/learning/results/matchingpairs.jsp (.../matchingpairs.jsp) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -1,8 +1,10 @@ <%@ include file="/common/taglibs.jsp"%> -
- -
+ +
+ +
+
Index: lams_tool_assessment/web/pages/learning/results/multiplechoice.jsp =================================================================== diff -u -r9c3a64b840753192b333afb73c8fe7bdb54be638 -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/web/pages/learning/results/multiplechoice.jsp (.../multiplechoice.jsp) (revision 9c3a64b840753192b333afb73c8fe7bdb54be638) +++ lams_tool_assessment/web/pages/learning/results/multiplechoice.jsp (.../multiplechoice.jsp) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -1,15 +1,17 @@ <%@ include file="/common/taglibs.jsp"%> -
- - - - - - - - -
+ +
+ + + + + + + + +
+
@@ -32,20 +34,23 @@
- - - checked="checked" - disabled="disabled" - /> - - - checked="checked" - disabled="disabled" - /> - - + + + + checked="checked" + disabled="disabled" + /> + + + checked="checked" + disabled="disabled" + /> + + + +  ${option.formatPrefixLetter(answerStatus.index)} Index: lams_tool_assessment/web/pages/learning/results/numerical.jsp =================================================================== diff -u -r2b3d3b2f61d37cf2fa7cccc0cf4565e5dfc4b88e -r3437878235018c207f602ea0464c109dd8e077c9 --- lams_tool_assessment/web/pages/learning/results/numerical.jsp (.../numerical.jsp) (revision 2b3d3b2f61d37cf2fa7cccc0cf4565e5dfc4b88e) +++ lams_tool_assessment/web/pages/learning/results/numerical.jsp (.../numerical.jsp) (revision 3437878235018c207f602ea0464c109dd8e077c9) @@ -1,30 +1,32 @@ <%@ include file="/common/taglibs.jsp"%> -
- -
+ +
+ +
+ +
+ + + + + + +
+ + + + + + + + +
+
+
-
- - - - - - -
- - - - - - - - -
-
-