Index: lams_tool_assessment/conf/language/lams/ApplicationResources.properties =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/conf/language/lams/ApplicationResources.properties,v diff -u -r1.34.2.18 -r1.34.2.19 --- lams_tool_assessment/conf/language/lams/ApplicationResources.properties 9 Mar 2017 00:09:18 -0000 1.34.2.18 +++ lams_tool_assessment/conf/language/lams/ApplicationResources.properties 10 Apr 2017 12:41:56 -0000 1.34.2.19 @@ -287,7 +287,7 @@ label.activity.completion =End of activity label.notifications =Notifications label.ask.for.hedging.justification =Ask for hedging justification? -label.number.learners.per.session =Number of learners per session +label.number.learners.per.session =Number of learners label.tool.output =Tool Output output.desc.best.score =Best score label.tool.output.has.been.changed =Tool Output has been changed @@ -300,6 +300,8 @@ label.file =File errors.maxfilesize =File exceeds maximum file size {0} label.summary.downloaded =Summary downloaded - - +label.lowest.mark=Lowest Mark +label.highest.mark=Highest Mark +label.number.learners=Number of Learners +label.percentage=Percentage #======= End labels: Exported 294 labels for en AU ===== Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java,v diff -u -r1.27.2.7 -r1.27.2.8 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java 17 Mar 2017 18:03:02 -0000 1.27.2.7 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java 10 Apr 2017 12:41:56 -0000 1.27.2.8 @@ -245,6 +245,8 @@ public static final String ATTR_TOOL_OUTPUT_DEFINITIONS = "toolOutputDefinitions"; + public static final String ATTR_MARK_SUMMARY = "markSummary"; + //output definitions public static final String OUTPUT_NAME_LEARNER_TOTAL_SCORE = "learner.total.score"; public static final String OUTPUT_NAME_LEARNER_TIME_TAKEN = "learner.time.taken"; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentUserDAO.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentUserDAO.java,v diff -u -r1.1.10.3 -r1.1.10.4 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentUserDAO.java 11 May 2016 07:15:06 -0000 1.1.10.3 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/AssessmentUserDAO.java 10 Apr 2017 12:41:56 -0000 1.1.10.4 @@ -43,4 +43,7 @@ List getPagedUsersBySessionAndQuestion(Long sessionId, Long questionUid, int page, int size, String sortBy, String sortOrder, String searchString); + + List getRawUserMarksBySession(Long sessionId); + Object[] getStatsMarksBySession(Long sessionId); } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentUserDAOHibernate.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentUserDAOHibernate.java,v diff -u -r1.1.10.8 -r1.1.10.9 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentUserDAOHibernate.java 31 Aug 2016 14:54:22 -0000 1.1.10.8 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentUserDAOHibernate.java 10 Apr 2017 12:41:56 -0000 1.1.10.9 @@ -28,6 +28,8 @@ import org.hibernate.Query; import org.hibernate.SQLQuery; +import org.hibernate.type.FloatType; +import org.hibernate.type.IntegerType; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.tool.assessment.dao.AssessmentUserDAO; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentUserDTO; @@ -44,6 +46,12 @@ private static final String FIND_BY_SESSION_ID = "from " + AssessmentUser.class.getName() + " as u where u.session.sessionId=?"; + private static final String LOAD_MARKS_FOR_SESSION = "SELECT grade FROM tl_laasse10_assessment_result " + + " WHERE finish_date IS NOT NULL AND latest = 1 AND session_id = :sessionId"; + private static final String FIND_MARK_STATS_FOR_SESSION = "SELECT MIN(grade) min_grade, AVG(grade) avg_grade, MAX(grade) max_grade FROM tl_laasse10_assessment_result " + + " WHERE finish_date IS NOT NULL AND latest = 1 AND session_id = :sessionId"; + + @Override public AssessmentUser getUserByUserIDAndSessionID(Long userID, Long sessionId) { List list = doFind(FIND_BY_USER_ID_SESSION_ID, new Object[] { userID, sessionId }); @@ -68,26 +76,31 @@ return (List) this.doFind(FIND_BY_SESSION_ID, sessionId); } + private static String LOAD_USERS_ORDERED_BY_SESSION = "SELECT DISTINCT user.user_id, user.last_name, user.first_name, user.login_name, result.grade" + + " FROM tl_laasse10_user user INNER JOIN tl_laasse10_session session" + + " ON user.session_uid=session.uid LEFT OUTER JOIN tl_laasse10_assessment_result result " + + " ON result.user_uid = user.uid AND result.finish_date IS NOT NULL" + + " AND result.latest = 1 WHERE session.session_id = :sessionId " + + " AND (CONCAT(user.last_name, ' ', user.first_name) LIKE CONCAT('%', :searchString, '%')) "; + private static String LOAD_USERS_ORDERED_ORDER_BY_NAME = "ORDER BY (CONCAT(user.last_name, ' ', user.first_name)) "; + private static String LOAD_USERS_ORDERED_ORDER_BY_TOTAL = "ORDER BY result.grade "; + @Override public List getPagedUsersBySession(Long sessionId, int page, int size, String sortBy, String sortOrder, String searchString) { - String LOAD_USERS_ORDERED_BY_NAME = "SELECT DISTINCT user.user_id, user.last_name, user.first_name, user.login_name, result.grade" - + " FROM tl_laasse10_user user" + " INNER JOIN tl_laasse10_session session" - + " ON user.session_uid=session.uid" + " LEFT OUTER JOIN tl_laasse10_assessment_result result " - + " ON result.user_uid = user.uid" + " AND result.finish_date IS NOT NULL" - + " AND result.latest = 1" + " WHERE session.session_id = :sessionId " - + " AND (CONCAT(user.last_name, ' ', user.first_name) LIKE CONCAT('%', :searchString, '%')) " - + " ORDER BY " + " CASE " - + " WHEN :sortBy='userName' THEN CONCAT(user.last_name, ' ', user.first_name) " - + " WHEN :sortBy='total' THEN result.grade " + " END " + sortOrder; - - SQLQuery query = getSession().createSQLQuery(LOAD_USERS_ORDERED_BY_NAME); + StringBuilder bldr = new StringBuilder(LOAD_USERS_ORDERED_BY_SESSION); + if ( "total".equalsIgnoreCase(sortBy) ) + bldr.append(LOAD_USERS_ORDERED_ORDER_BY_TOTAL); + else + bldr.append(LOAD_USERS_ORDERED_ORDER_BY_NAME); + bldr.append(sortOrder); + + SQLQuery query = getSession().createSQLQuery(bldr.toString()); query.setLong("sessionId", sessionId); // support for custom search from a toolbar searchString = searchString == null ? "" : searchString; query.setString("searchString", searchString); - query.setString("sortBy", sortBy); query.setFirstResult(page * size); query.setMaxResults(size); List list = query.list(); @@ -137,11 +150,24 @@ } } + @SuppressWarnings("unchecked") @Override - public List getPagedUsersBySessionAndQuestion(Long sessionId, Long questionUid, int page, - int size, String sortBy, String sortOrder, String searchString) { + public Object[] getStatsMarksBySession(Long sessionId) { - String LOAD_USERS_ORDERED_BY_NAME = "SELECT DISTINCT question_result.uid, user.last_name, user.first_name, user.login_name, question_result.mark" + Query query = getSession().createSQLQuery(FIND_MARK_STATS_FOR_SESSION) + .addScalar("min_grade", FloatType.INSTANCE) + .addScalar("avg_grade", FloatType.INSTANCE) + .addScalar("max_grade", FloatType.INSTANCE); + query.setLong("sessionId", sessionId); + List list = query.list(); + if ((list == null) || (list.size() == 0)) { + return null; + } else { + return (Object[]) list.get(0); + } + } + + private static String LOAD_USERS_ORDERED_BY_SESSION_QUESTION = "SELECT DISTINCT question_result.uid, user.last_name, user.first_name, user.login_name, question_result.mark" + " FROM tl_laasse10_user user" + " INNER JOIN tl_laasse10_session session" + " ON user.session_uid=session.uid" + @@ -152,18 +178,26 @@ + " AND question_result.assessment_question_uid = :questionUid" + " WHERE session.session_id = :sessionId " - + " AND (CONCAT(user.last_name, ' ', user.first_name) LIKE CONCAT('%', :searchString, '%')) " - + " ORDER BY " + " CASE " - + " WHEN :sortBy='userName' THEN CONCAT(user.last_name, ' ', user.first_name) " - + " WHEN :sortBy='grade' THEN question_result.mark " + " END " + sortOrder; + + " AND (CONCAT(user.last_name, ' ', user.first_name) LIKE CONCAT('%', :searchString, '%')) "; + private static String LOAD_USERS_ORDERED_ORDER_BY_RESULT = "ORDER BY question_result.mark "; - SQLQuery query = getSession().createSQLQuery(LOAD_USERS_ORDERED_BY_NAME); + @Override + public List getPagedUsersBySessionAndQuestion(Long sessionId, Long questionUid, int page, + int size, String sortBy, String sortOrder, String searchString) { + + StringBuilder bldr = new StringBuilder(LOAD_USERS_ORDERED_BY_SESSION_QUESTION); + if ( "grade".equalsIgnoreCase(sortBy) ) + bldr.append(LOAD_USERS_ORDERED_ORDER_BY_RESULT); + else + bldr.append(LOAD_USERS_ORDERED_ORDER_BY_NAME); + bldr.append(sortOrder); + + SQLQuery query = getSession().createSQLQuery(bldr.toString()); query.setLong("sessionId", sessionId); query.setLong("questionUid", questionUid); // support for custom search from a toolbar searchString = searchString == null ? "" : searchString; query.setString("searchString", searchString); - query.setString("sortBy", sortBy); query.setFirstResult(page * size); query.setMaxResults(size); List list = query.list(); @@ -193,4 +227,13 @@ return userDtos; } + @Override + public List getRawUserMarksBySession(Long sessionId) { + + SQLQuery query = getSession().createSQLQuery(LOAD_MARKS_FOR_SESSION); + query.setLong("sessionId", sessionId); + List list = query.list(); + return list; + } + } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/SessionDTO.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/SessionDTO.java,v diff -u -r1.1.2.4 -r1.1.2.5 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/SessionDTO.java 11 May 2016 07:15:07 -0000 1.1.2.4 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/SessionDTO.java 10 Apr 2017 12:41:56 -0000 1.1.2.5 @@ -38,6 +38,9 @@ private Long sessionId; private String sessionName; private int numberLearners; + private String minMark; + private String maxMark; + private String avgMark; //used for export purposes only private List assessmentResults; @@ -91,4 +94,28 @@ this.numberLearners = numberLearners; } + public String getAvgMark() { + return avgMark; + } + + public void setAvgMark(String avgMark) { + this.avgMark = avgMark; + } + + public String getMinMark() { + return minMark; + } + + public void setMinMark(String minMark) { + this.minMark = minMark; + } + + public String getMaxMark() { + return maxMark; + } + + public void setMaxMark(String maxMark) { + this.maxMark = maxMark; + } + } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java,v diff -u -r1.48.2.49 -r1.48.2.50 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java 4 Apr 2017 12:26:38 -0000 1.48.2.49 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java 10 Apr 2017 12:41:56 -0000 1.48.2.50 @@ -34,10 +34,12 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; +import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Pattern; @@ -105,6 +107,7 @@ import org.lamsfoundation.lams.util.ExcelCell; import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.NumberUtil; import org.lamsfoundation.lams.util.audit.IAuditService; /** @@ -965,7 +968,7 @@ } @Override - public List getSessionDtos(Long contentId) { + public List getSessionDtos(Long contentId, boolean includeStatistics) { List sessionDtos = new ArrayList(); List sessionList = assessmentSessionDao.getByContentId(contentId); @@ -974,8 +977,16 @@ SessionDTO sessionDto = new SessionDTO(sessionId, session.getSessionName()); //for statistics tab - int countUsers = assessmentUserDao.getCountUsersBySession(sessionId, ""); - sessionDto.setNumberLearners(countUsers); + if ( includeStatistics ) { + int countUsers = assessmentUserDao.getCountUsersBySession(sessionId, ""); + sessionDto.setNumberLearners(countUsers); + Object[] markStats = assessmentUserDao.getStatsMarksBySession(sessionId); + if ( markStats != null ) { + sessionDto.setMinMark(NumberUtil.formatLocalisedNumber((Float)markStats[0], (Locale)null, 2)); + sessionDto.setAvgMark(NumberUtil.formatLocalisedNumber((Float)markStats[1], (Locale)null, 2)); + sessionDto.setMaxMark(NumberUtil.formatLocalisedNumber((Float)markStats[2], (Locale)null, 2)); + } + } sessionDtos.add(sessionDto); } @@ -1175,13 +1186,7 @@ ExcelCell[] sessionTitle = new ExcelCell[1]; sessionTitle[0] = new ExcelCell(sessionDTO.getSessionName(), true); summaryTab.add(sessionTitle); - - ExcelCell[] summaryRowTitle = new ExcelCell[3]; - summaryRowTitle[0] = new ExcelCell(getMessage("label.export.user.id"), true); - summaryRowTitle[1] = new ExcelCell(getMessage("label.monitoring.summary.user.name"), true); - summaryRowTitle[2] = new ExcelCell(getMessage("label.monitoring.summary.total"), true); - summaryTab.add(summaryRowTitle); - + List userDtos = new ArrayList(); // in case of UseSelectLeaderToolOuput - display only one user if (assessment.isUseSelectLeaderToolOuput()) { @@ -1208,15 +1213,74 @@ userDtos = getPagedUsersBySession(sessionId, 0, countSessionUsers, "userName", "ASC", ""); } + ArrayList summaryTabLearnerList = new ArrayList(); + + ExcelCell[] summaryRowTitle = new ExcelCell[3]; + summaryRowTitle[0] = new ExcelCell(getMessage("label.export.user.id"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[1] = new ExcelCell(getMessage("label.monitoring.summary.user.name"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[2] = new ExcelCell(getMessage("label.monitoring.summary.total"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryTabLearnerList.add(summaryRowTitle); + + float minGrade = 0; + float maxGrade = 0; + for (AssessmentUserDTO userDto : userDtos) { + float grade = userDto.getGrade(); + ExcelCell[] userResultRow = new ExcelCell[3]; userResultRow[0] = new ExcelCell(userDto.getLogin(), false); userResultRow[1] = new ExcelCell(userDto.getFirstName() + " " + userDto.getLastName(), false); - userResultRow[2] = new ExcelCell(userDto.getGrade(), false); - summaryTab.add(userResultRow); + userResultRow[2] = new ExcelCell(grade, false); + summaryTabLearnerList.add(userResultRow); + + if ( minGrade == 0 || grade < minGrade ) + minGrade = grade; + if ( grade > maxGrade ) + maxGrade = grade; + } + LinkedHashMap markSummary = getMarksSummaryForSession(userDtos, minGrade, maxGrade, 10); + // work out total marks so we can do percentages. need as float for the correct divisions + int totalNumEntries = 0; + for ( Map.Entry entry : markSummary.entrySet() ) { + totalNumEntries += entry.getValue(); + } + + // Mark Summary Min, Max + Grouped Percentages summaryTab.add(EMPTY_ROW); + ExcelCell[] minMaxRow = new ExcelCell[2]; + minMaxRow[0] = new ExcelCell(getMessage("label.number.learners"), true); + minMaxRow[1] = new ExcelCell(totalNumEntries, false); + summaryTab.add(minMaxRow); + minMaxRow = new ExcelCell[2]; + minMaxRow[0] = new ExcelCell(getMessage("label.lowest.mark"), true); + minMaxRow[1] = new ExcelCell((double)minGrade, false); + summaryTab.add(minMaxRow); + minMaxRow = new ExcelCell[2]; + minMaxRow[0] = new ExcelCell(getMessage("label.highest.mark"), true); + minMaxRow[1] = new ExcelCell((double)maxGrade, false); + summaryTab.add(minMaxRow); + + summaryTab.add(EMPTY_ROW); + ExcelCell[] binSummaryRow = new ExcelCell[3]; + binSummaryRow[0] = new ExcelCell(getMessage("label.authoring.basic.list.header.mark"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + binSummaryRow[1] = new ExcelCell(getMessage("label.number.learners"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + binSummaryRow[2] = new ExcelCell(getMessage("label.percentage"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryTab.add(binSummaryRow); + float totalNumEntriesAsFloat = (float) totalNumEntries; + for ( Map.Entry entry : markSummary.entrySet() ) { + binSummaryRow = new ExcelCell[3]; + binSummaryRow[0] = new ExcelCell(entry.getKey(),false); + binSummaryRow[1] = new ExcelCell(entry.getValue(),false); + binSummaryRow[2] = new ExcelCell(Math.round(entry.getValue() / totalNumEntriesAsFloat * 100),false); + summaryTab.add(binSummaryRow); + } + summaryTab.add(EMPTY_ROW); + + summaryTab.add(EMPTY_ROW); + summaryTab.addAll(summaryTabLearnerList); + summaryTab.add(EMPTY_ROW); } } @@ -1241,19 +1305,28 @@ int count = 0; // question row title ExcelCell[] questionTitleRow = showUserNames ? new ExcelCell[10] : new ExcelCell[9]; - questionTitleRow[count++] = new ExcelCell(getMessage("label.monitoring.question.summary.question"), true); - questionTitleRow[count++] = new ExcelCell(getMessage("label.authoring.basic.list.header.type"), true); - questionTitleRow[count++] = new ExcelCell(getMessage("label.authoring.basic.penalty.factor"), true); + questionTitleRow[count++] = new ExcelCell(getMessage("label.monitoring.question.summary.question"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + questionTitleRow[count++] = new ExcelCell(getMessage("label.authoring.basic.list.header.type"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + questionTitleRow[count++] = new ExcelCell(getMessage("label.authoring.basic.penalty.factor"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); questionTitleRow[count++] = new ExcelCell(getMessage("label.monitoring.question.summary.default.mark"), - true); - questionTitleRow[count++] = new ExcelCell(getMessage("label.export.user.id"), true); + true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + questionTitleRow[count++] = new ExcelCell(getMessage("label.export.user.id"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); if (showUserNames) { - questionTitleRow[count++] = new ExcelCell(getMessage("label.monitoring.user.summary.user.name"), true); + questionTitleRow[count++] = new ExcelCell(getMessage("label.monitoring.user.summary.user.name"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); } - questionTitleRow[count++] = new ExcelCell(getMessage("label.export.date.attempted"), true); - questionTitleRow[count++] = new ExcelCell(getMessage("label.authoring.basic.option.answer"), true); - questionTitleRow[count++] = new ExcelCell(getMessage("label.export.time.taken"), true); - questionTitleRow[count++] = new ExcelCell(getMessage("label.export.mark"), true); + questionTitleRow[count++] = new ExcelCell(getMessage("label.export.date.attempted"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + questionTitleRow[count++] = new ExcelCell(getMessage("label.authoring.basic.option.answer"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + questionTitleRow[count++] = new ExcelCell(getMessage("label.export.time.taken"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); + questionTitleRow[count++] = new ExcelCell(getMessage("label.export.mark"), true, + ExcelCell.BORDER_STYLE_BOTTOM_THIN); for (AssessmentQuestion question : questions) { int colsNum = showUserNames ? 10 : 9; @@ -1413,11 +1486,11 @@ userSummaryTab.add(userSummaryTitle); ExcelCell[] summaryRowTitle = new ExcelCell[5]; - summaryRowTitle[0] = new ExcelCell(getMessage("label.monitoring.question.summary.question"), true); - summaryRowTitle[1] = new ExcelCell(getMessage("label.authoring.basic.list.header.type"), true); - summaryRowTitle[2] = new ExcelCell(getMessage("label.authoring.basic.penalty.factor"), true); - summaryRowTitle[3] = new ExcelCell(getMessage("label.monitoring.question.summary.default.mark"), true); - summaryRowTitle[4] = new ExcelCell(getMessage("label.monitoring.question.summary.average.mark"), true); + summaryRowTitle[0] = new ExcelCell(getMessage("label.monitoring.question.summary.question"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[1] = new ExcelCell(getMessage("label.authoring.basic.list.header.type"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[2] = new ExcelCell(getMessage("label.authoring.basic.penalty.factor"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[3] = new ExcelCell(getMessage("label.monitoring.question.summary.default.mark"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + summaryRowTitle[4] = new ExcelCell(getMessage("label.monitoring.question.summary.average.mark"), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); userSummaryTab.add(summaryRowTitle); Float totalGradesPossible = new Float(0); Float totalAverage = new Float(0); @@ -1969,6 +2042,74 @@ eventNotificationService.notifyLessonMonitors(sessionId, message, false); } + + @Override + public List getMarksArray(Long sessionId) { + return assessmentUserDao.getRawUserMarksBySession(sessionId); + } + + private LinkedHashMap getMarksSummaryForSession(List userDtos, float minGrade, float maxGrade, Integer numBuckets) { + + LinkedHashMap summary = new LinkedHashMap(); + TreeMap inProgress = new TreeMap(); + + if ( numBuckets == null ) + numBuckets = 10; + + int bucketSize = 1; + int intMinGrade = (int)Math.floor(minGrade); + float gradeDifference = maxGrade - minGrade; + if ( gradeDifference <= 10 ) { + for ( int i= intMinGrade; i <= (int)Math.ceil(maxGrade); i++ ) { + inProgress.put(i, 0); + } + } else { + int intGradeDifference = (int) Math.ceil(gradeDifference); + bucketSize = (int) Math.ceil(intGradeDifference / numBuckets); + for ( int i=intMinGrade; i <= maxGrade; i = i+bucketSize ) { + inProgress.put(i, 0); + } + } + + // TODO optimise. At least start with the top bucket! + for (AssessmentUserDTO userDto : userDtos) { + float grade = userDto.getGrade(); + int bucketStart = intMinGrade; + int bucketStop = bucketStart+bucketSize; + boolean looking = true; + while ( bucketStart <= maxGrade && looking ) { + if ( grade >= bucketStart && grade < bucketStop ) { + inProgress.put(bucketStart, inProgress.get(bucketStart) + 1); + looking = false; + } else { + bucketStart = bucketStop; + bucketStop = bucketStart+bucketSize; + } + } + } + + // TODO get locale + for ( Map.Entry entry : inProgress.entrySet() ) { + String key; + if ( bucketSize == 1 ) + key = entry.getKey().toString(); + else { + if ( maxGrade >= entry.getKey() && maxGrade <= entry.getKey()+bucketSize-1) { + if ( (int)maxGrade == entry.getKey() ) + key = NumberUtil.formatLocalisedNumber(maxGrade, (Locale)null, 2); + else + key = new StringBuilder().append(entry.getKey()).append(" - ") + .append(NumberUtil.formatLocalisedNumber(maxGrade, (Locale)null, 2)).toString(); + } else { + key = new StringBuilder().append(entry.getKey()).append(" - ").append(entry.getKey()+bucketSize-.01).toString(); + } + } + summary.put(key, entry.getValue()); + } + + return summary; + } + // ***************************************************************************** // private methods // ***************************************************************************** Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java,v diff -u -r1.26.2.19 -r1.26.2.20 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java 4 Apr 2017 12:26:38 -0000 1.26.2.19 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java 10 Apr 2017 12:41:56 -0000 1.26.2.20 @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import org.lamsfoundation.lams.notebook.model.NotebookEntry; import org.lamsfoundation.lams.tool.assessment.dto.AssessmentUserDTO; @@ -356,7 +357,7 @@ * @param contentId * @return */ - List getSessionDtos(Long contentId); + List getSessionDtos(Long contentId, boolean includeStatistics); AssessmentResult getUserMasterDetail(Long sessionId, Long userId); @@ -398,6 +399,14 @@ LinkedHashMap exportSummary(Assessment assessment, List sessionDtos, boolean showUserNames); + /** + * Prepares data for the marks summary graph on the statistics page + * @param assessment + * @param sessionDtos + * @return + */ + List getMarksArray(Long sessionId); + void changeQuestionResultMark(Long questionResultUid, float newMark); void notifyTeachersOnAttemptCompletion(Long sessionId, String userName); Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java,v diff -u -r1.25.2.10 -r1.25.2.11 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java 8 Mar 2017 03:58:51 -0000 1.25.2.10 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/MonitoringAction.java 10 Apr 2017 12:41:55 -0000 1.25.2.11 @@ -29,8 +29,10 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.TreeMap; import java.util.TreeSet; import javax.servlet.ServletException; @@ -118,7 +120,13 @@ if (param.equals("exportSummary")) { return exportSummary(mapping, form, request, response); } - + if (param.equals("getMarkChartData")) { + return getMarkChartData(mapping, form, request, response); + } + if (param.equals("statistic")) { + return statistic(mapping, form, request, response); + } + return mapping.findForward(AssessmentConstants.ERROR); } @@ -132,7 +140,7 @@ request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMap.getSessionID()); Long contentId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); - List sessionDtos = service.getSessionDtos(contentId); + List sessionDtos = service.getSessionDtos(contentId, false); Assessment assessment = service.getAssessmentByContentId(contentId); @@ -194,7 +202,7 @@ WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID)); return mapping.findForward(AssessmentConstants.SUCCESS); } - + private ActionForward userMasterDetail(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { initAssessmentService(); @@ -510,6 +518,42 @@ return null; } + /** + * Get the mark summary with data arranged in bands. Can be displayed graphically or in a table. + */ + public ActionForward getMarkChartData(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse res) throws IOException, ServletException, JSONException { + + initAssessmentService(); + + String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMap.getSessionID()); + + Long sessionId = WebUtil.readLongParam(request, AssessmentConstants.ATTR_TOOL_SESSION_ID); + List results = service.getMarksArray(sessionId); +// +// log.debug("fudging results to get more data for transmission. New results will have "+(origResults.length*50)+" entries"); +// Float[] results = new Float[origResults.length*50]; +// for (int i=0; i<50; i++) { +// for ( int j=0; j < origResults.length; j++ ) { +// results[i*origResults.length + j] = origResults[j]; +// } +// } + + JSONObject responseJSON = new JSONObject(); + if ( results != null ) + responseJSON.put("data", results); + else + responseJSON.put("data", new Float[0]); + + res.setContentType("application/json;charset=utf-8"); + res.getWriter().write(responseJSON.toString()); + return null; + + } + /** * Excel Summary Export. * @@ -541,7 +585,7 @@ contentId = WebUtil.readLongParam(request, "toolContentID"); fileName = WebUtil.readStrParam(request, "fileName"); showUserNames = false; - sessionDtos = service.getSessionDtos(contentId); + sessionDtos = service.getSessionDtos(contentId, true); } Assessment assessment = service.getAssessmentByContentId(contentId); @@ -572,7 +616,23 @@ return null; } + + private ActionForward statistic(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + initAssessmentService(); + String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession() + .getAttribute(sessionMapID); + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMap.getSessionID()); + + Long contentId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); + List sessionDtos = service.getSessionDtos(contentId, true); + sessionMap.put("sessionDtos", sessionDtos); + return mapping.findForward(AssessmentConstants.SUCCESS); + } + + // ************************************************************************************* // Private method // ************************************************************************************* Index: lams_tool_assessment/web/WEB-INF/struts-config.xml =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/WEB-INF/Attic/struts-config.xml,v diff -u -r1.1.2.4 -r1.1.2.5 --- lams_tool_assessment/web/WEB-INF/struts-config.xml 17 Mar 2017 18:03:02 -0000 1.1.2.4 +++ lams_tool_assessment/web/WEB-INF/struts-config.xml 10 Apr 2017 12:41:55 -0000 1.1.2.5 @@ -344,6 +344,15 @@ type="org.lamsfoundation.lams.tool.assessment.web.action.MonitoringAction" parameter="exportSummary" > + + + + + Index: lams_tool_assessment/web/includes/css/assessment.css =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/includes/css/assessment.css,v diff -u -r1.7.2.7 -r1.7.2.8 --- lams_tool_assessment/web/includes/css/assessment.css 9 Dec 2016 07:31:57 -0000 1.7.2.7 +++ lams_tool_assessment/web/includes/css/assessment.css 10 Apr 2017 12:41:56 -0000 1.7.2.8 @@ -155,3 +155,28 @@ .comments { font-size: small; font-style: italic; margin-top: -8px; } + +.chartDiv { + margin-top: 10px; + margin-left: 10px; + margin-bottom: 10px; + width: 95%; + height: 500px; +} + +.bar rect { + fill: steelblue; +} + +.bar text { + fill: #fff; + font: 14px sans-serif; +} +.zoom { + cursor: move; + fill: none; + pointer-events: all; +} + + + Index: lams_tool_assessment/web/pages/monitoring/monitoring.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/pages/monitoring/monitoring.jsp,v diff -u -r1.11.2.8 -r1.11.2.9 --- lams_tool_assessment/web/pages/monitoring/monitoring.jsp 8 Mar 2017 03:58:51 -0000 1.11.2.8 +++ lams_tool_assessment/web/pages/monitoring/monitoring.jsp 10 Apr 2017 12:41:56 -0000 1.11.2.9 @@ -1,6 +1,8 @@ <%@ include file="/common/taglibs.jsp"%> <%@ page import="org.lamsfoundation.lams.tool.assessment.AssessmentConstants"%> + + @@ -15,7 +17,7 @@ height:auto; vertical-align:text-top; padding-top:2px; - } + } + + Index: lams_tool_assessment/web/pages/monitoring/statistic.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/pages/monitoring/statistic.jsp,v diff -u -r1.5.2.4 -r1.5.2.5 --- lams_tool_assessment/web/pages/monitoring/statistic.jsp 15 Jun 2016 08:01:14 -0000 1.5.2.4 +++ lams_tool_assessment/web/pages/monitoring/statistic.jsp 10 Apr 2017 12:41:56 -0000 1.5.2.5 @@ -1,71 +1,5 @@ <%@ include file="/common/taglibs.jsp"%> - - - - - - - - - - - - - - -
- -
- - - - - - - - - - - - - -
- - - -
-  ${sessionDto.sessionName} - - ${sessionDto.numberLearners} -
- -
-
- -<%@ include file="parts/toolOutput.jsp"%> +
+<%-- Do not include anything to start with as we do not want to display the charts yet. +--%> +
\ No newline at end of file Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_tool_assessment/web/pages/monitoring/statisticpart.jsp'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_assessment/web/pages/monitoring/summary.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/pages/monitoring/summary.jsp,v diff -u -r1.25.2.9 -r1.25.2.10 --- lams_tool_assessment/web/pages/monitoring/summary.jsp 8 Mar 2017 03:58:51 -0000 1.25.2.9 +++ lams_tool_assessment/web/pages/monitoring/summary.jsp 10 Apr 2017 12:41:56 -0000 1.25.2.10 @@ -6,6 +6,7 @@