Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r8993cac8ce6dcb8d8ccb24c1cb387d44c0847199 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 Binary files differ Index: lams_central/web/includes/javascript/progressBar.js =================================================================== diff -u -r0ee859ab5ce221c22245de76fc399e5976665003 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_central/web/includes/javascript/progressBar.js (.../progressBar.js) (revision 0ee859ab5ce221c22245de76fc399e5976665003) +++ lams_central/web/includes/javascript/progressBar.js (.../progressBar.js) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -1053,143 +1053,153 @@ // check if container still exists // it may happen if user quickly changes pages in Monitor var barContainer = $('#' + bar.containerId); + + // if the bar is gone + if (barContainer.length == 0){ + return; + } + // if there is no progress returned for the given user + if (!result) { + barContainer.text(LABELS.PROGRESS_NOT_STARTED); + return; + } // if nothing changed, don't do any calculations - if (barContainer.length > 0 - && (!bar.currentActivityId - || result.currentActivityId != bar.currentActivityId)) { - bar.currentActivityId = result.currentActivityId; - isPreview = result.isPreview; + if (bar.currentActivityId && (result.currentActivityId == bar.currentActivityId)) { + return; + } + + bar.currentActivityId = result.currentActivityId; + isPreview = result.isPreview; - var paper = bar.paper; - if (!paper) { - // create paper only the first time - paper = bar.paper = Snap(isHorizontalBar ? 40 + 60 * result.activities.length : 140, - isHorizontalBar ? 60 : 60 * result.activities.length + 25); - barContainer.append(paper.node); - // first line on the top - paper.path(isHorizontalBar ? PATH_START_LINE_HORIZONTAL : PATH_START_LINE_VERTICAL); - - if (!GLOW_FILTER) { - GLOW_FILTER = paper.filter(Snap.filter.blur(1.5)); - } + var paper = bar.paper; + if (!paper) { + // create paper only the first time + paper = bar.paper = Snap(isHorizontalBar ? 40 + 60 * result.activities.length : 140, + isHorizontalBar ? 60 : 60 * result.activities.length + 25); + barContainer.append(paper.node); + // first line on the top + paper.path(isHorizontalBar ? PATH_START_LINE_HORIZONTAL : PATH_START_LINE_VERTICAL); + + if (!GLOW_FILTER) { + GLOW_FILTER = paper.filter(Snap.filter.blur(1.5)); } + } - // we need this to scroll to the current activity - var currentActivityIndex = 0; + // we need this to scroll to the current activity + var currentActivityIndex = 0; - for (var activityIndex = 0; activityIndex < result.activities.length; activityIndex++) { - var activityData = result.activities[activityIndex], - // prepare the Activity descriptor, but do not draw yet - activity = new Activity(bar, activityIndex, - activityData.id, activityData.type, - activityData.name, activityData.status, - activityData.url, - activityData.childActivities); - if (activity.status == 0) { - currentActivityIndex = activityIndex; - } + for (var activityIndex = 0; activityIndex < result.activities.length; activityIndex++) { + var activityData = result.activities[activityIndex], + // prepare the Activity descriptor, but do not draw yet + activity = new Activity(bar, activityIndex, + activityData.id, activityData.type, + activityData.name, activityData.status, + activityData.url, + activityData.childActivities); + if (activity.status == 0) { + currentActivityIndex = activityIndex; + } - var activities = bar.activities; - if (!activities) { - activities = bar.activities = []; - } + var activities = bar.activities; + if (!activities) { + activities = bar.activities = []; + } - var existingActivity = activities[activityIndex]; - if (existingActivity) { - // if in preview mode, always display all inner - // activities, i.e. never expand - if (!isPreview && existingActivity.type == 'b' && existingActivity.id != activity.id) { - var branchActivityId = activityIndex, - afterBranchActivityId = activityIndex + 1 < activities.length ? - activities[activityIndex + 1].id : null, - branchActivities = []; - - // check if it is an empty branch - if (activity.id != afterBranchActivityId) { - branchActivities.push(activity); - activityIndex++; - - // find which activities are new (branch) - // and which ones already existed - while (activityIndex < result.activities.length) { - activityData = result.activities[activityIndex]; - var activity = new Activity(bar, - activityIndex, - activityData.id, - activityData.type, - activityData.name, - activityData.status, - activityData.url, - activityData.childActivities); - if (activity.id == afterBranchActivityId) { - // prepare for the next big loop - // iteration, which executes - // normally - activityIndex--; - break; - } else { - branchActivities.push(activity); - activityIndex++; - } + var existingActivity = activities[activityIndex]; + if (existingActivity) { + // if in preview mode, always display all inner + // activities, i.e. never expand + if (!isPreview && existingActivity.type == 'b' && existingActivity.id != activity.id) { + var branchActivityId = activityIndex, + afterBranchActivityId = activityIndex + 1 < activities.length ? + activities[activityIndex + 1].id : null, + branchActivities = []; + + // check if it is an empty branch + if (activity.id != afterBranchActivityId) { + branchActivities.push(activity); + activityIndex++; + + // find which activities are new (branch) + // and which ones already existed + while (activityIndex < result.activities.length) { + activityData = result.activities[activityIndex]; + var activity = new Activity(bar, + activityIndex, + activityData.id, + activityData.type, + activityData.name, + activityData.status, + activityData.url, + activityData.childActivities); + if (activity.id == afterBranchActivityId) { + // prepare for the next big loop + // iteration, which executes + // normally + activityIndex--; + break; + } else { + branchActivities.push(activity); + activityIndex++; } - - // resize main paper to accomodate new activities - paper.attr({ - 'width' : isHorizontalBar ? 40 + 60 * (activities.length + branchActivities.length - 1) : 140, - 'height' : isHorizontalBar ? 60 : 60 * (activities.length + branchActivities.length - 1) + 25 - }); } - - ActivityUtils.expandBranch(bar, - branchActivityId, branchActivities); - } else { - // refresh existing bar, transform - // activities if needed - ActivityUtils.transform(existingActivity, - activity); + + // resize main paper to accomodate new activities + paper.attr({ + 'width' : isHorizontalBar ? 40 + 60 * (activities.length + branchActivities.length - 1) : 140, + 'height' : isHorizontalBar ? 60 : 60 * (activities.length + branchActivities.length - 1) + 25 + }); } + + ActivityUtils.expandBranch(bar, + branchActivityId, branchActivities); } else { - // draw new activity - ActivityUtils.drawActivity(activity, true, activityIndex == result.activities.length - 1); + // refresh existing bar, transform + // activities if needed + ActivityUtils.transform(existingActivity, + activity); } + } else { + // draw new activity + ActivityUtils.drawActivity(activity, true, activityIndex == result.activities.length - 1); } + } - // draw support activities if they exist - var supportSeparatorRow = $('#supportSeparatorRow'); - if (result.support && supportSeparatorRow.length > 0 && !supportSeparatorRow.is(':visible')) { - supportSeparatorRow.show(); + // draw support activities if they exist + var supportSeparatorRow = $('#supportSeparatorRow'); + if (result.support && supportSeparatorRow.length > 0 && !supportSeparatorRow.is(':visible')) { + supportSeparatorRow.show(); - // separate paper for Support Activities frame - var supportPaper = Snap(); - $('#supportPart').height(17 + 33 * result.support.length) - .append(supportPaper.node) - .show(); - $.each(result.support, function(activityIndex, - activityData) { - var activity = new SupportActivity( - supportPaper, activityIndex, - activityData.name, activityData.status, - activityData.url); - activity.shape = supportPaper - .path(activity.path); - activity.shape.attr(ActivityUtils - .getShapeAttributes(activity)); - ActivityUtils.addDecoration(activity, null, - true); - ActivityUtils.addEffects(activity); - supportPaper.text(90, 24 + 33 * activityIndex, - activity.name).attr(DEFAULT_TEXT_ATTRIBUTES); - }); - } + // separate paper for Support Activities frame + var supportPaper = Snap(); + $('#supportPart').height(17 + 33 * result.support.length) + .append(supportPaper.node) + .show(); + $.each(result.support, function(activityIndex, + activityData) { + var activity = new SupportActivity( + supportPaper, activityIndex, + activityData.name, activityData.status, + activityData.url); + activity.shape = supportPaper + .path(activity.path); + activity.shape.attr(ActivityUtils + .getShapeAttributes(activity)); + ActivityUtils.addDecoration(activity, null, + true); + ActivityUtils.addEffects(activity); + supportPaper.text(90, 24 + 33 * activityIndex, + activity.name).attr(DEFAULT_TEXT_ATTRIBUTES); + }); + } - resizeElements(); - // scroll to the current activity - if (!isHorizontalBar) { - $('#' + bar.containerId).scrollTop( - Math.max((currentActivityIndex - 1) * 60,0) - ); - } + resizeElements(); + // scroll to the current activity + if (!isHorizontalBar) { + $('#' + bar.containerId).scrollTop( + Math.max((currentActivityIndex - 1) * 60,0) + ); } } }); Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java =================================================================== diff -u -r8993cac8ce6dcb8d8ccb24c1cb387d44c0847199 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java (.../ILearnerProgressDAO.java) (revision 8993cac8ce6dcb8d8ccb24c1cb387d44c0847199) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java (.../ILearnerProgressDAO.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -102,12 +102,11 @@ List getLearnersLatestCompletedForLesson(Long lessonId, Integer limit, Integer offset); /** - * Get learners whose first name, last name or login match any of the tokens from search phrase. Sorts either by - * name or, if orderByCompletion is set, by most progressed first. Used mainly by Learners tab in Monitoring - * interface. + * Get learners whose first name, last name or login match any of the tokens from search phrase. + * Sort by most progressed first, then by name. + * Used by Learners tab in Monitoring interface. */ - List getLearnersByLesson(Long lessonId, String searchPhrase, boolean orderByCompletion, Integer limit, - Integer offset); + List getLearnersByMostProgress(Long lessonId, String searchPhrase, Integer limit, Integer offset); /** * Get all the learner progress records for a lesson where the progress is marked as completed. Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java =================================================================== diff -u -r62b97a5e0fd88110e023f00793a983713296f9b6 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java (.../ILessonDAO.java) (revision 62b97a5e0fd88110e023f00793a983713296f9b6) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java (.../ILessonDAO.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -4,15 +4,15 @@ * License Information: http://lamsfoundation.org/licensing/lams/2.0/ * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2.0 + * it under the terms of the GNU General License version 2.0 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU General License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA @@ -44,12 +44,12 @@ * identifies the lesson to get * @return the lesson */ - public Lesson getLesson(Long lessonId); + Lesson getLesson(Long lessonId); /** Get all the lessons in the database. This includes the disabled lessons. */ - public List getAllLessons(); + List getAllLessons(); - public Lesson getLessonWithJoinFetchedProgress(Long lessonId); + Lesson getLessonWithJoinFetchedProgress(Long lessonId); /** * Gets all lessons that are active for a learner. TODO to be removed when the dummy interface is no longer needed @@ -58,7 +58,7 @@ * a User that identifies the learner. * @return a Set with all active lessons in it. */ - public List getActiveLessonsForLearner(User learner); + List getActiveLessonsForLearner(User learner); /** * Gets all lessons that are active for a learner, in a given organisation @@ -69,30 +69,30 @@ * the desired organisation . * @return a List with all active lessons in it. */ - public List getActiveLessonsForLearner(Integer learnerId, Integer organisationID); + List getActiveLessonsForLearner(Integer learnerId, Integer organisationID); /** * Saves or Updates a Lesson. * * @param lesson * the Lesson to save */ - public void saveLesson(Lesson lesson); + void saveLesson(Lesson lesson); /** * Deletes a Lesson permanently. * * @param lesson * the Lesson to remove. */ - public void deleteLesson(Lesson lesson); + void deleteLesson(Lesson lesson); /** * Update a requested lesson. * * @param createdLesson */ - public void updateLesson(Lesson lesson); + void updateLesson(Lesson lesson); /** * Returns the list of available Lessons created by a given user. Does not return disabled lessons or preview @@ -102,7 +102,7 @@ * The user_id of the user * @return List The list of Lessons for the given user */ - public List getLessonsCreatedByUser(Integer userID); + List getLessonsCreatedByUser(Integer userID); /** * Gets all lessons in the given organisation, for which this user is in the staff group. Does not return disabled @@ -112,7 +112,7 @@ * a User that identifies the teacher/staff member. * @return a List with all appropriate lessons in it. */ - public List getLessonsForMonitoring(int userID, int organisationID); + List getLessonsForMonitoring(int userID, int organisationID); /** * Returns the all the learners that have started the requested lesson. @@ -121,7 +121,7 @@ * the id of the requested lesson. * @return the list of learners. */ - public List getActiveLearnerByLesson(long lessonId); + List getActiveLearnerByLesson(long lessonId); /** * Returns the all the learners that have started the requested lesson and are in the given group. @@ -132,7 +132,7 @@ * the id of the requested group. * @return the list of learners. */ - public List getActiveLearnerByLessonAndGroup(long lessonId, long groupId); + List getActiveLearnerByLessonAndGroup(long lessonId, long groupId); /** * Returns the count of all the learners that have started the requested lesson. @@ -141,12 +141,14 @@ * the id of the requested lesson. * @return the count of the learners. */ - public Integer getCountActiveLearnerByLesson(long lessonId); + Integer getCountActiveLearnerByLesson(long lessonId); + List getLearnersByLesson(Long lessonId, String searchPhrase, Integer limit, Integer offset); + /** * Returns the count of all the learners that are a part of the lesson class. */ - public Integer getCountLearnerByLesson(long lessonId); + Integer getCountLearnersByLesson(long lessonId, String searchPhrase); /** * Get all the preview lessons more with the creation date before the given date. @@ -155,12 +157,12 @@ * UTC date * @return the list of Lessons */ - public List getPreviewLessonsBeforeDate(Date startDate); + List getPreviewLessonsBeforeDate(Date startDate); /** * Get the lesson that applies to this activity. Not all activities have an attached lesson. */ - public Lesson getLessonForActivity(long activityId); + Lesson getLessonForActivity(long activityId); /** * Gets all non-removed lessons for a user in an org; set userRole parameter to learner if you want lessons where @@ -175,8 +177,7 @@ * * @return a List containing a list of tuples containing lesson details and the lesson completed flag for the user. */ - public List getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, - Integer userRole); + List getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, Integer userRole); /** * Gets all non-removed lessons for a user in a group including sub-groups @@ -187,15 +188,15 @@ * an org id that identifies the organisation. * @return a List containing a list of tuples containing lesson details and the lesson completed flag for the user. */ - public List getLessonsByGroupAndUser(Integer userId, Integer orgId); + List getLessonsByGroupAndUser(Integer userId, Integer orgId); /** * Gets all non-removed lessons for a group. * * @param orgId * @return */ - public List getLessonsByGroup(Integer orgId); + List getLessonsByGroup(Integer orgId); /** * Get lessons based on learning designs where the original learning design has the given id. @@ -204,7 +205,7 @@ * @param orgId * @return list of lessons */ - public List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId); + List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId); /** * Finds out which lesson the given tool content belongs to and returns its monitoring users. @@ -213,13 +214,13 @@ * tool session ID * @return list of teachers that monitor the lesson which contains the tool with given session ID */ - public List getMonitorsByToolSessionId(Long sessionId); + List getMonitorsByToolSessionId(Long sessionId); /** * Gets lesson for tools based on toolSessionID * * @param sessionID * @return */ - public Lesson getLessonFromSessionID(Long toolSessionID); + Lesson getLessonFromSessionID(Long toolSessionID); } Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java =================================================================== diff -u -r8993cac8ce6dcb8d8ccb24c1cb387d44c0847199 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java (.../LearnerProgressDAO.java) (revision 8993cac8ce6dcb8d8ccb24c1cb387d44c0847199) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java (.../LearnerProgressDAO.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -45,48 +45,61 @@ protected Logger log = Logger.getLogger(LearnerProgressDAO.class); - private static String LOAD_PROGRESS_BY_LEARNER = "from LearnerProgress p where p.user.id = :learnerId and p.lesson.id = :lessonId"; + private final static String LOAD_PROGRESS_BY_LEARNER = "from LearnerProgress p where p.user.id = :learnerId and p.lesson.id = :lessonId"; - private static String LOAD_PROGRESS_REFFERING_TO_ACTIVITY = "from LearnerProgress p where p.previousActivity = :activity or p.currentActivity = :activity or p.nextActivity = :activity "; + private final static String LOAD_PROGRESS_REFFERING_TO_ACTIVITY = "from LearnerProgress p where p.previousActivity = :activity or p.currentActivity = :activity or p.nextActivity = :activity "; - private static String LOAD_COMPLETED_PROGRESS_BY_LESSON = "from LearnerProgress p where p.lessonComplete > 0 and p.lesson.id = :lessonId"; + private final static String LOAD_COMPLETED_PROGRESS_BY_LESSON = "from LearnerProgress p where p.lessonComplete > 0 and p.lesson.id = :lessonId"; - private static String LOAD_LEARNERS_LATEST_COMPLETED_BY_LESSON = "SELECT p.user FROM LearnerProgress p WHERE " + private final static String LOAD_LEARNERS_LATEST_COMPLETED_BY_LESSON = "SELECT p.user FROM LearnerProgress p WHERE " + "p.lessonComplete > 0 and p.lesson.id = :lessonId ORDER BY p.finishDate DESC"; - private static String COUNT_COMPLETED_PROGRESS_BY_LESSON = "select count(*) from LearnerProgress p " + private final static String COUNT_COMPLETED_PROGRESS_BY_LESSON = "select count(*) from LearnerProgress p " + " where p.lessonComplete > 0 and p.lesson.id = :lessonId"; - private static String COUNT_ATTEMPTED_ACTIVITY = "select count(*) from LearnerProgress prog, " + private final static String COUNT_ATTEMPTED_ACTIVITY = "select count(*) from LearnerProgress prog, " + " Activity act join prog.attemptedActivities attAct " + " where act.id = :activityId and " + " index(attAct) = act"; - private static String COUNT_COMPLETED_ACTIVITY = "select count(*) from LearnerProgress prog, " + + private final static String COUNT_COMPLETED_ACTIVITY = "select count(*) from LearnerProgress prog, " + " Activity act join prog.completedActivities compAct " + " where act.id = :activityId and " + " index(compAct) = act"; - private static String COUNT_CURRENT_ACTIVITY = "select count(*) from LearnerProgress prog WHERE " + private final static String COUNT_CURRENT_ACTIVITY = "select count(*) from LearnerProgress prog WHERE " + " prog.currentActivity = :activity"; - private static String LOAD_PROGRESS_BY_LESSON = "from LearnerProgress p " + private final static String LOAD_PROGRESS_BY_LESSON = "from LearnerProgress p " + " where p.lesson.id = :lessonId order by p.user.lastName, p.user.firstName, p.user.userId"; - private static String LOAD_PROGRESS_BY_LESSON_AND_USER_IDS = "from LearnerProgress p " + private final static String LOAD_PROGRESS_BY_LESSON_AND_USER_IDS = "from LearnerProgress p " + " where p.lesson.id = :lessonId AND p.user.userId IN (:userIds) order by p.user.lastName, p.user.firstName, p.user.userId"; - private static String LOAD_PROGRESSES_BY_LESSON_LIST = "FROM LearnerProgress progress WHERE " + private final static String LOAD_PROGRESSES_BY_LESSON_LIST = "FROM LearnerProgress progress WHERE " + " progress.lesson.lessonId IN (:lessonIds)"; - private static String LOAD_LEARNERS_LATEST_BY_ACTIVITY = "SELECT u.* FROM lams_learner_progress AS prog " + private final static String LOAD_LEARNERS_LATEST_BY_ACTIVITY = "SELECT u.* FROM lams_learner_progress AS prog " + "JOIN lams_progress_attempted AS att USING (learner_progress_id) " + "JOIN lams_user AS u USING (user_id) " + "WHERE prog.current_activity_id = :activityId AND att.activity_id = :activityId " + "ORDER BY att.start_date_time DESC"; - private static String LOAD_LEARNERS_BY_ACTIVITIES = "SELECT p.user FROM LearnerProgress p WHERE " + private final static String LOAD_LEARNERS_BY_ACTIVITIES = "SELECT p.user FROM LearnerProgress p WHERE " + " p.currentActivity.id IN (:activityIds)"; - private static String LOAD_LEARNERS_BY_LESSON = "FROM LearnerProgress prog WHERE prog.lesson.id = :lessonId"; + private final static String COUNT_LEARNERS_BY_LESSON = "COUNT(*) FROM LearnerProgress prog WHERE prog.lesson.id = :lessonId"; + private final static String COUNT_LEARNERS_BY_LESSON_ORDER_CLAUSE = " ORDER BY prog.user.firstName ASC, prog.user.lastName ASC, prog.user.login ASC"; + // find Learners for the given Lesson first, then see if they have Progress, i.e. started the lesson + private final static String LOAD_LEARNERS_BY_MOST_PROGRESS = "SELECT u.*, COUNT(comp.activity_id) AS comp_count FROM lams_lesson AS lesson " + + "JOIN lams_grouping AS grouping ON lesson.class_grouping_id = grouping.grouping_id " + + "JOIN lams_group AS g USING (grouping_id) JOIN lams_user_group AS ug USING (group_id) " + + "JOIN lams_user AS u ON ug.user_id = u.user_id " + + "LEFT JOIN lams_learner_progress AS prog ON prog.lesson_id = lesson.lesson_id AND prog.user_id = u.user_id " + + "LEFT JOIN lams_progress_completed AS comp USING (learner_progress_id) " + + "WHERE lesson.lesson_id = :lessonId AND g.group_name NOT LIKE '%Staff%'"; + private final static String LOAD_LEARNERS_BY_MOST_PROGRESS_ORDER_CLAUSE = " GROUP BY u.user_id " + + "ORDER BY prog.lesson_completed_flag DESC, comp_count DESC, u.first_name ASC, u.last_name ASC, u.login ASC"; + @Override public LearnerProgress getLearnerProgress(Long learnerProgressId) { return (LearnerProgress) getSession().get(LearnerProgress.class, learnerProgressId); @@ -165,11 +178,20 @@ @SuppressWarnings("unchecked") @Override - public List getLearnersByLesson(Long lessonId, String searchPhrase, boolean orderByCompletion, Integer limit, - Integer offset) { - String queryText = LearnerProgressDAO.buildLearnersByLessonQuery(false, searchPhrase, orderByCompletion); + public List getLearnersByMostProgress(Long lessonId, String searchPhrase, Integer limit, Integer offset) { + StringBuilder queryText = new StringBuilder(LearnerProgressDAO.LOAD_LEARNERS_BY_MOST_PROGRESS); + // find the search phrase parts in any of name parts of the user + if (!StringUtils.isBlank(searchPhrase)) { + String[] tokens = searchPhrase.trim().split("\\s+"); + for (String token : tokens) { + queryText.append(" AND (u.firstName LIKE '%").append(token).append("%' OR u.lastName LIKE '%") + .append(token).append("%' OR u.login LIKE '%").append(token).append("%')"); + } + } + queryText.append(LearnerProgressDAO.LOAD_LEARNERS_BY_MOST_PROGRESS_ORDER_CLAUSE); - Query query = getSession().createQuery(queryText).setLong("lessonId", lessonId); + Query query = getSession().createSQLQuery(queryText.toString()).addEntity(User.class).setLong("lessonId", + lessonId); if (limit != null) { query.setMaxResults(limit); } @@ -179,27 +201,6 @@ return query.list(); } - private static String buildLearnersByLessonQuery(boolean count, String searchPhrase, Boolean orderByCompletion) { - StringBuilder queryText = new StringBuilder("SELECT ").append(count ? "COUNT(*) " : "prog.user ") - .append(LearnerProgressDAO.LOAD_LEARNERS_BY_LESSON); - if (!StringUtils.isBlank(searchPhrase)) { - String[] tokens = searchPhrase.trim().split("\\s+"); - for (String token : tokens) { - queryText.append(" AND (prog.user.firstName LIKE '%").append(token) - .append("%' OR prog.user.lastName LIKE '%").append(token) - .append("%' OR prog.user.login LIKE '%").append(token).append("%')"); - } - } - if (!count && (orderByCompletion != null)) { - queryText.append(" ORDER BY"); - if (orderByCompletion) { - queryText.append(" prog.lessonComplete DESC, prog.completedActivities.size DESC,"); - } - queryText.append(" prog.user.firstName ASC, prog.user.lastName ASC"); - } - return queryText.toString(); - } - @SuppressWarnings("unchecked") @Override public List getCompletedLearnerProgressForLesson(Long lessonId) { @@ -254,8 +255,20 @@ @Override public Integer getNumUsersByLesson(Long lessonId, String searchPhrase) { - String queryText = LearnerProgressDAO.buildLearnersByLessonQuery(true, searchPhrase, null); - Object value = getSession().createQuery(queryText).setLong("lessonId", lessonId.longValue()).uniqueResult(); + StringBuilder queryText = new StringBuilder(LearnerProgressDAO.COUNT_LEARNERS_BY_LESSON); + // find the search phrase parts in any of name parts of the user + if (!StringUtils.isBlank(searchPhrase)) { + String[] tokens = searchPhrase.trim().split("\\s+"); + for (String token : tokens) { + queryText.append(" AND (prog.user.firstName LIKE '%").append(token) + .append("%' OR prog.user.lastName LIKE '%").append(token) + .append("%' OR prog.user.login LIKE '%").append(token).append("%')"); + } + } + queryText.append(LearnerProgressDAO.COUNT_LEARNERS_BY_LESSON_ORDER_CLAUSE); + + Object value = getSession().createQuery(queryText.toString()).setLong("lessonId", lessonId.longValue()) + .uniqueResult(); return ((Number) value).intValue(); } Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java =================================================================== diff -u -r251b7ee0e6167f913e587201457c722d36ebfb2c -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java (.../LessonDAO.java) (revision 251b7ee0e6167f913e587201457c722d36ebfb2c) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java (.../LessonDAO.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -26,6 +26,7 @@ import java.util.Date; import java.util.List; +import org.apache.commons.lang.StringUtils; import org.hibernate.FetchMode; import org.hibernate.Query; import org.hibernate.criterion.Restrictions; @@ -65,9 +66,11 @@ + " where organisation.organisationId=? and lessonStateId <= 6"; private final static String LESSON_BY_SESSION_ID = "select lesson from Lesson lesson, ToolSession session where " + "session.lesson=lesson and session.toolSessionId=:toolSessionID"; - private final static String COUNT_LEARNERS_CLASS = "SELECT COUNT(*) FROM Lesson AS lesson " + + private final static String LOAD_LEARNERS_BY_LESSON = "FROM Lesson AS lesson " + "INNER JOIN lesson.lessonClass AS lessonClass INNER JOIN lessonClass.groups AS groups " - + "INNER JOIN groups.users AS users" + " WHERE lesson.id = :lessonId"; + + "INNER JOIN groups.users AS users " + + "WHERE lesson.id = :lessonId AND groups.groupName NOT LIKE '%Staff%'"; /** * Retrieves the Lesson. Used in instances where it cannot be lazy loaded so it forces an initialize. @@ -83,7 +86,7 @@ } @Override - public Lesson getLessonWithJoinFetchedProgress(final Long lessonId) { + public Lesson getLessonWithJoinFetchedProgress(Long lessonId) { return (Lesson) getSession().createCriteria(Lesson.class).add(Restrictions.like("lessonId", lessonId)) .setFetchMode("learnerProgresses", FetchMode.JOIN).uniqueResult(); @@ -103,7 +106,7 @@ * @return a List with all active lessons in it. */ @Override - public List getActiveLessonsForLearner(final User learner) { + public List getActiveLessonsForLearner(User learner) { Query query = getSession().getNamedQuery("activeLessonsAllOrganisations"); query.setInteger("userId", learner.getUserId().intValue()); @@ -121,7 +124,7 @@ * @return a List with all active lessons in it. */ @Override - public List getActiveLessonsForLearner(final Integer learnerId, final Integer organisationId) { + public List getActiveLessonsForLearner(Integer learnerId, Integer organisationId) { Query query = getSession().getNamedQuery("activeLessons"); query.setInteger("userId", learnerId); @@ -134,7 +137,7 @@ * @see org.lamsfoundation.lams.lesson.dao.ILessonDAO#getActiveLearnerByLesson(long) */ @Override - public List getActiveLearnerByLesson(final long lessonId) { + public List getActiveLearnerByLesson(long lessonId) { Query query = getSession().getNamedQuery("activeLearners"); query.setLong("lessonId", lessonId); @@ -146,7 +149,7 @@ * @see org.lamsfoundation.lams.lesson.dao.ILessonDAO#getActiveLearnerByLessonAndGroup(long, long) */ @Override - public List getActiveLearnerByLessonAndGroup(final long lessonId, final long groupId) { + public List getActiveLearnerByLessonAndGroup(long lessonId, long groupId) { Query query = getSession().getNamedQuery("activeLearnersByGroup"); query.setLong("lessonId", lessonId); query.setLong("groupId", groupId); @@ -159,16 +162,31 @@ * query.uniqueResult() returns Integer, Hibernate 3.2 query.uniqueResult() returns Long */ @Override - public Integer getCountActiveLearnerByLesson(final long lessonId) { + public Integer getCountActiveLearnerByLesson(long lessonId) { Query query = getSession().createQuery(LessonDAO.COUNT_ACTIVE_LEARNERS); query.setLong("lessonId", lessonId); Object value = query.uniqueResult(); return new Integer(((Number) value).intValue()); } + @SuppressWarnings("unchecked") @Override - public Integer getCountLearnerByLesson(final long lessonId) { - Query query = getSession().createQuery(LessonDAO.COUNT_LEARNERS_CLASS).setLong("lessonId", lessonId); + public List getLearnersByLesson(Long lessonId, String searchPhrase, Integer limit, Integer offset) { + String queryText = LessonDAO.buildLearnersByLessonQuery(false, searchPhrase); + Query query = getSession().createQuery(queryText).setLong("lessonId", lessonId); + if (limit != null) { + query.setMaxResults(limit); + } + if (offset != null) { + query.setFirstResult(offset); + } + return query.list(); + } + + @Override + public Integer getCountLearnersByLesson(long lessonId, String searchPhrase) { + String queryText = LessonDAO.buildLearnersByLessonQuery(true, searchPhrase); + Query query = getSession().createQuery(queryText).setLong("lessonId", lessonId); Object value = query.uniqueResult(); return ((Number) value).intValue(); } @@ -226,7 +244,7 @@ * @return a List with all appropriate lessons in it. */ @Override - public List getLessonsForMonitoring(final int userID, final int organisationID) { + public List getLessonsForMonitoring(int userID, int organisationID) { Query query = getSession().getNamedQuery("lessonsForMonitoring"); query.setInteger("userId", userID); query.setInteger("organisationId", organisationID); @@ -242,7 +260,7 @@ * @return the list of Lessons */ @Override - public List getPreviewLessonsBeforeDate(final Date startDate) { + public List getPreviewLessonsBeforeDate(Date startDate) { List lessons = this.doFind(LessonDAO.FIND_PREVIEW_BEFORE_START_DATE, startDate); return lessons; } @@ -251,7 +269,7 @@ * Get the lesson that applies to this activity. Not all activities have an attached lesson. */ @Override - public Lesson getLessonForActivity(final long activityId) { + public Lesson getLessonForActivity(long activityId) { Query query = getSession().createQuery(LessonDAO.FIND_LESSON_FOR_ACTIVITY); query.setLong("activityId", activityId); return (Lesson) query.uniqueResult(); @@ -262,8 +280,7 @@ * boolean) */ @Override - public List getLessonsByOrgAndUserWithCompletedFlag(final Integer userId, final Integer orgId, - final Integer userRole) { + public List getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, Integer userRole) { String queryName; if (Role.ROLE_MONITOR.equals(userRole)) { @@ -287,7 +304,7 @@ * boolean) */ @Override - public List getLessonsByGroupAndUser(final Integer userId, final Integer orgId) { + public List getLessonsByGroupAndUser(Integer userId, Integer orgId) { Query query = getSession().getNamedQuery("lessonsByOrgAndUserWithChildOrgs"); query.setInteger("userId", userId.intValue()); query.setInteger("orgId", orgId.intValue()); @@ -296,15 +313,15 @@ } @Override - public List getLessonsByGroup(final Integer orgId) { + public List getLessonsByGroup(Integer orgId) { return this.doFind(LessonDAO.LESSONS_BY_GROUP, orgId); } /** * @see org.lamsfoundation.lams.lesson.dao.ILessonDAO#getLessonsByOriginalLearningDesign(Integer) */ @Override - public List getLessonsByOriginalLearningDesign(final Long ldId, final Integer orgId) { + public List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId) { Object[] args = { ldId.longValue(), orgId.intValue() }; List lessons = this.doFind(LessonDAO.LESSONS_WITH_ORIGINAL_LEARNING_DESIGN, args); return lessons; @@ -323,9 +340,25 @@ * @see org.lamsfoundation.lams.lesson.dao.ILessonDAO#getLessonDetailsFromSessionID(java.lang.Long) */ @Override - public Lesson getLessonFromSessionID(final Long toolSessionID) { + public Lesson getLessonFromSessionID(Long toolSessionID) { Query query = getSession().createQuery(LessonDAO.LESSON_BY_SESSION_ID); query.setLong("toolSessionID", toolSessionID); return (Lesson) query.uniqueResult(); } + + private static String buildLearnersByLessonQuery(boolean count, String searchPhrase) { + StringBuilder queryText = new StringBuilder("SELECT ").append(count ? "COUNT(*) " : "users ") + .append(LessonDAO.LOAD_LEARNERS_BY_LESSON); + if (!StringUtils.isBlank(searchPhrase)) { + String[] tokens = searchPhrase.trim().split("\\s+"); + for (String token : tokens) { + queryText.append(" AND (users.firstName LIKE '%").append(token).append("%' OR users.lastName LIKE '%") + .append(token).append("%' OR users.login LIKE '%").append(token).append("%')"); + } + } + if (!count) { + queryText.append(" ORDER BY users.firstName ASC, users.lastName ASC, users.login ASC"); + } + return queryText.toString(); + } } Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java =================================================================== diff -u -r62b97a5e0fd88110e023f00793a983713296f9b6 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 62b97a5e0fd88110e023f00793a983713296f9b6) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -74,10 +74,12 @@ */ Integer getCountActiveLessonLearners(Long lessonId); + List getLessonLearners(Long lessonId, String searchPhrase, Integer limit, Integer offset); + /** * Get the count of all the learners who are a part of the lesson class. */ - Integer getCountLessonLearners(Long lessonId); + Integer getCountLessonLearners(Long lessonId, String searchPhrase); /** * Get the lesson details for the LAMS client. Suitable for the monitoring client. Contains a count of the total Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java =================================================================== diff -u -r62b97a5e0fd88110e023f00793a983713296f9b6 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 62b97a5e0fd88110e023f00793a983713296f9b6) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -120,11 +120,15 @@ public Integer getCountActiveLessonLearners(Long lessonId) { return lessonDAO.getCountActiveLearnerByLesson(lessonId); } - @Override - public Integer getCountLessonLearners(Long lessonId) { - return lessonDAO.getCountLearnerByLesson(lessonId); + public List getLessonLearners(Long lessonId, String searchPhrase, Integer limit, Integer offset) { + return lessonDAO.getLearnersByLesson(lessonId, searchPhrase, limit, offset); } + + @Override + public Integer getCountLessonLearners(Long lessonId, String searchPhrase) { + return lessonDAO.getCountLearnersByLesson(lessonId, searchPhrase); + } @Override public LessonDetailsDTO getLessonDetails(Long lessonId) { Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -r6f762597a7a0333d56b1e5d6e802333af681df31 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 6f762597a7a0333d56b1e5d6e802333af681df31) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -280,8 +280,7 @@ *

* In terms of an started lesson, the learner progress will be returned without calculation. Tool session will be * initialized if necessary. Note that we won't initialize tool session for current activity because we assume tool - * session will always initialize before it becomes a current activity. - *

entryIterator = branchSequence.getBranchEntries().iterator(); while (entryIterator.hasNext()) { BranchActivityEntry entry = entryIterator.next(); @@ -1178,16 +1181,15 @@ if (LearnerService.log.isDebugEnabled()) { LearnerService.log .debug("No branches match and no default branch exists. Uable to allocate learner to a branch for the branching activity" - + branchingActivity.getActivityId() - + ":" - + branchingActivity.getTitle() + + branchingActivity.getActivityId() + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + learner.getLogin()); } return null; } } - private SequenceActivity determineGroupBasedBranch(Lesson lesson, BranchingActivity branchingActivity, User learner) { + private SequenceActivity determineGroupBasedBranch(Lesson lesson, BranchingActivity branchingActivity, + User learner) { SequenceActivity sequenceActivity = null; if (branchingActivity.getGrouping() != null) { @@ -1261,12 +1263,9 @@ toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, learner.getUserId()); if (toolOutput == null) { - LearnerService.log - .warn("Condition " - + condition - + " refers to a tool output " - + conditionName - + " but tool doesn't return any tool output for that name. Skipping this condition."); + LearnerService.log.warn("Condition " + condition + " refers to a tool output " + + conditionName + + " but tool doesn't return any tool output for that name. Skipping this condition."); } else { toolOutputMap.put(conditionName, toolOutput); } @@ -1415,8 +1414,8 @@ int desiredGroupCount = learnerCount / maxNumberOfLearnersPerGroup + (learnerCount % maxNumberOfLearnersPerGroup == 0 ? 0 : 1); if (desiredGroupCount > groupCount) { - ((LearnerChoiceGrouper) grouping.getGrouper()).createGroups(learnerChoiceGrouping, desiredGroupCount - - groupCount); + ((LearnerChoiceGrouper) grouping.getGrouper()).createGroups(learnerChoiceGrouping, + desiredGroupCount - groupCount); groupingDAO.update(grouping); } } @@ -1446,8 +1445,8 @@ */ @Override public ToolOutput getToolInput(Long requestingToolContentId, Integer assigmentId, Integer learnerId) { - DataFlowObject dataFlowObject = getDataFlowDAO() - .getAssignedDataFlowObject(requestingToolContentId, assigmentId); + DataFlowObject dataFlowObject = getDataFlowDAO().getAssignedDataFlowObject(requestingToolContentId, + assigmentId); User learner = (User) getUserManagementService().findById(User.class, learnerId); Activity activity = dataFlowObject.getDataTransition().getFromActivity(); String outputName = dataFlowObject.getName(); @@ -1499,16 +1498,17 @@ // this is tricky: the activity is the last one only if parent is and after completing it, // there are no more optional activities to do // (for example, it's 4th out of 5 optional activities) - OptionsActivity parentOptionsActivity = (OptionsActivity) getActivity(parentActivity - .getActivityId()); + OptionsActivity parentOptionsActivity = (OptionsActivity) getActivity( + parentActivity.getActivityId()); Integer learnerId = LearningWebUtil.getUserId(); Lesson lesson = getLessonByActivity(activity); LearnerProgress learnerProgress = getProgress(learnerId, lesson.getLessonId()); if (learnerProgress != null) { int completedSubactivities = 0; for (Activity subactivity : (Set) parentOptionsActivity.getActivities()) { - if (LearnerProgress.ACTIVITY_COMPLETED == learnerProgress.getProgressState(subactivity)) { + if (LearnerProgress.ACTIVITY_COMPLETED == learnerProgress + .getProgressState(subactivity)) { completedSubactivities++; } } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java =================================================================== diff -u -r715b8aae1297fe15f7a0a65c52e39b50cae4c157 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java (.../LearnerAction.java) (revision 715b8aae1297fe15f7a0a65c52e39b50cae4c157) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java (.../LearnerAction.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -166,11 +166,11 @@ // security check Lesson lesson = learnerService.getLesson(lessonID); - User user = (User) LearnerServiceProxy.getUserManagementService(getServlet().getServletContext()).findById( - User.class, learner); + User user = (User) LearnerServiceProxy.getUserManagementService(getServlet().getServletContext()) + .findById(User.class, learner); if ((lesson.getLessonClass() == null) || !lesson.getLessonClass().getLearners().contains(user)) { - request.setAttribute("messageKey", "User " + user.getLogin() - + " is not a learner in the requested lesson."); + request.setAttribute("messageKey", + "User " + user.getLogin() + " is not a learner in the requested lesson."); return mapping.findForward("message"); } // check lesson's state if its suitable for learner's access @@ -193,15 +193,15 @@ LearningWebUtil.putLearnerProgressInRequest(request, learnerProgress); - ActivityMapping activityMapping = LearnerServiceProxy.getActivityMapping(this.getServlet() - .getServletContext()); + ActivityMapping activityMapping = LearnerServiceProxy + .getActivityMapping(this.getServlet().getServletContext()); String url = "learning/" + activityMapping.getDisplayActivityAction(lessonID); redirectToURL(mapping, response, url); } catch (Exception e) { - LearnerAction.log - .error("An error occurred while learner " + learner + " attempting to join the lesson.", e); + LearnerAction.log.error("An error occurred while learner " + learner + " attempting to join the lesson.", + e); return mapping.findForward(ActivityMapping.ERROR); } @@ -258,8 +258,8 @@ // serialize a acknowledgement flash message with the path of display next // activity - ActivityMapping activityMapping = LearnerServiceProxy.getActivityMapping(this.getServlet() - .getServletContext()); + ActivityMapping activityMapping = LearnerServiceProxy + .getActivityMapping(this.getServlet().getServletContext()); message = new FlashMessage("joinLesson", activityMapping.getDisplayActivityAction(null)); } catch (Exception e) { @@ -429,8 +429,8 @@ // getting requested object according to coming parameters Integer learnerId = LearningWebUtil.getUserId(); - User learner = (User) LearnerServiceProxy.getUserManagementService(getServlet().getServletContext()).findById( - User.class, learnerId); + User learner = (User) LearnerServiceProxy.getUserManagementService(getServlet().getServletContext()) + .findById(User.class, learnerId); Activity requestedActivity = learnerService.getActivity(new Long(activityId)); Lesson lesson = learnerService.getLessonByActivity(requestedActivity); @@ -460,6 +460,10 @@ Long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); Object[] ret = learnerService.getStructuredActivityURLs(learnerId, lessonId); + if (ret == null) { + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + return null; + } JSONObject responseJSON = new JSONObject(); responseJSON.put("currentActivityId", ret[1]); @@ -660,8 +664,8 @@ */ private IAuditService getAuditService() { if (LearnerAction.auditService == null) { - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() - .getServletContext()); + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); LearnerAction.auditService = (IAuditService) ctx.getBean("auditService"); } return LearnerAction.auditService; @@ -685,8 +689,8 @@ * @throws IOException * @throws ServletException */ - public ActionForward forwardToLearnerActivityURL(ActionMapping mapping, ActionForm form, - HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + public ActionForward forwardToLearnerActivityURL(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { long activityId = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); if (LearnerAction.log.isDebugEnabled()) { LearnerAction.log.debug("Forwarding to the url for learner activity..." + activityId); Index: lams_monitoring/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r02418977fdc6024dae9ea2b9872a6ef50198deef -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_monitoring/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 02418977fdc6024dae9ea2b9872a6ef50198deef) +++ lams_monitoring/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -258,6 +258,7 @@ label.learner.progress.activity.attempted.tooltip =The user have attempted but not yet finished this activity label.learner.progress.activity.tostart.tooltip =The user need to complete the activities before this activity to access it label.learner.progress.activity.support.tooltip =Double click to open this support activity +label.learner.progress.not.started =The user has not started the lesson yet button.export.learner.tooltip =Export this learner portfolio and save it on your computer for future reference button.timechart =View Time Chart button.timechart.tooltip =View a chart of the selected learner progress against time for each activity Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java =================================================================== diff -u -r8993cac8ce6dcb8d8ccb24c1cb387d44c0847199 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java (.../IMonitoringService.java) (revision 8993cac8ce6dcb8d8ccb24c1cb387d44c0847199) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java (.../IMonitoringService.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -690,8 +690,7 @@ * name or, if orderByCompletion is set, by most progressed first. Used mainly by Learners tab in Monitoring * interface. */ - List getLearnersFromProgress(Long lessonId, String searchPhrase, boolean orderByCompletion, Integer limit, - Integer offset); + List getLearnersByMostProgress(Long lessonId, String searchPhrase, Integer limit, Integer offset); /** * Get learners who most recently entered the activity. Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== diff -u -r8993cac8ce6dcb8d8ccb24c1cb387d44c0847199 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 8993cac8ce6dcb8d8ccb24c1cb387d44c0847199) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -2370,9 +2370,8 @@ } @Override - public List getLearnersFromProgress(Long lessonId, String searchPhrase, boolean orderByCompletion, - Integer limit, Integer offset) { - return learnerProgressDAO.getLearnersByLesson(lessonId, searchPhrase, orderByCompletion, limit, offset); + public List getLearnersByMostProgress(Long lessonId, String searchPhrase, Integer limit, Integer offset) { + return learnerProgressDAO.getLearnersByMostProgress(lessonId, searchPhrase, limit, offset); } @Override Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -r184121401ec92fa82a32c0f5b1f094d30dc4699e -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 184121401ec92fa82a32c0f5b1f094d30dc4699e) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -983,16 +983,17 @@ // are the learners sorted by the most completed first? boolean isProgressSorted = WebUtil.readBooleanParam(request, "isProgressSorted", false); - List learners = getMonitoringService().getLearnersFromProgress(lessonId, searchPhrase, isProgressSorted, - 10, (pageNumber - 1) * 10); + // either sort by name or how much a learner progressed into the lesson + List learners = isProgressSorted + ? getMonitoringService().getLearnersByMostProgress(lessonId, searchPhrase, 10, (pageNumber - 1) * 10) + : getLessonService().getLessonLearners(lessonId, searchPhrase, 10, (pageNumber - 1) * 10); JSONObject responseJSON = new JSONObject(); for (User learner : learners) { responseJSON.append("learners", WebUtil.userToJSON(learner)); } // get all possible learners matching the given phrase, if any; used for max page number - responseJSON.put("numberActiveLearners", - getMonitoringService().getCountLearnersFromProgress(lessonId, searchPhrase)); + responseJSON.put("learnerPossibleNumber", getLessonService().getCountLessonLearners(lessonId, searchPhrase)); response.setContentType("application/json;charset=utf-8"); response.getWriter().print(responseJSON.toString()); return null; @@ -1020,7 +1021,7 @@ Locale userLocale = new Locale(user.getLocaleLanguage(), user.getLocaleCountry()); responseJSON.put(AttributeNames.PARAM_LEARNINGDESIGN_ID, learningDesign.getLearningDesignId()); - responseJSON.put("numberPossibleLearners", getLessonService().getCountLessonLearners(lessonId)); + responseJSON.put("numberPossibleLearners", getLessonService().getCountLessonLearners(lessonId, null)); responseJSON.put("lessonStateID", lesson.getLessonStateId()); Date startOrScheduleDate = lesson.getStartDateTime() == null ? lesson.getScheduleStartDate() @@ -1132,6 +1133,7 @@ LearnerProgress searchedLearnerProgress = null; if (searchedLearnerId != null) { searchedLearnerProgress = getLessonService().getUserProgressForLesson(searchedLearnerId, lessonId); + responseJSON.put("searchedLearnerFound", searchedLearnerProgress != null); } JSONArray activitiesJSON = new JSONArray(); @@ -1245,7 +1247,7 @@ responseJSON.append("completedLearners", learnerJSON); } - responseJSON.put("numberPossibleLearners", getLessonService().getCountLessonLearners(lessonId)); + responseJSON.put("numberPossibleLearners", getLessonService().getCountLessonLearners(lessonId, null)); // on first fetch get transitions metadata so Monitoring can set their SVG elems IDs if (WebUtil.readBooleanParam(request, "getTransitions", false)) { @@ -1275,7 +1277,7 @@ long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); String searchPhrase = request.getParameter("term"); - List learners = getMonitoringService().getLearnersFromProgress(lessonId, searchPhrase, false, 10, null); + List learners = getLessonService().getLessonLearners(lessonId, searchPhrase, 10, null); JSONArray responseJSON = new JSONArray(); for (User learner : learners) { JSONObject learnerJSON = new JSONObject(); Index: lams_monitoring/web/includes/javascript/monitorLesson.js =================================================================== diff -u -r18e02f01797801899d908e25ae9fd0bbeda7cc78 -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 18e02f01797801899d908e25ae9fd0bbeda7cc78) +++ lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -28,7 +28,7 @@ sequenceRefreshInProgress = false, // total number of learners with ongoing progress - numberActiveLearners = 0, + learnerPossibleNumber = 0, // page in Learners tab learnerProgressCurrentPageNumber = 1, @@ -53,8 +53,7 @@ 'activate' : function(event, ui) { var sequenceInfoDialog = $('#sequenceInfoDialog'); if (ui.newPanel.attr('id') == 'tabSequence') { - if (sequenceInfoDialog.length > 0 - && !sequenceInfoDialog.dialog('option', 'showed')) { + if (sequenceTabShowInfo && !sequenceInfoDialog.dialog('option', 'showed')) { sequenceInfoDialog.dialog('open'); } } else if (sequenceInfoDialog.dialog('isOpen')) { @@ -896,6 +895,12 @@ sequenceCanvas.html(sequenceCanvas.html()); } + if (sequenceSearchedLearner != null && !response.searchedLearnerFound) { + // the learner has not started the lesson yet, display an info box + sequenceClearSearchPhrase(); + $('#sequenceInfoDialog').text(LABELS.PROGRESS_NOT_STARTED).dialog('open'); + } + var learnerTotalCount = learnerCount + response.completedLearnerCount; $('#learnersStartedPossibleCell').text(learnerTotalCount + ' / ' + response.numberPossibleLearners); addCompletedLearnerIcons(response.completedLearners, response.completedLearnerCount, learnerTotalCount); @@ -1378,13 +1383,15 @@ /** * Cancels the performed search. */ -function sequenceClearSearchPhrase(){ +function sequenceClearSearchPhrase(refresh){ $('#sequenceSearchPhrase').val(''); $('#sequenceSearchPhraseClear').css('visibility', 'hidden'); $('#sequenceSearchedLearnerHighlighter').hide(); sequenceSearchedLearner = null; + if (refresh) { updateSequenceTab(); } +} /** @@ -1619,8 +1626,8 @@ * Do the actual shifting of page numbers bar. */ function shiftLearnerProgressPageHeader(startIndex, endIndex) { - var pageLeftCell = $('#learnersPageLeft'); - var pageCount = Math.ceil(numberActiveLearners / 10); + var pageLeftCell = $('#learnersPageLeft'), + pageCount = Math.ceil(learnerPossibleNumber / 10); $('#tabLearnerControlTable td.learnersHeaderPageCell').remove(); if (startIndex < 1) { @@ -1658,15 +1665,15 @@ function updateLearnerProgressHeader(pageNumber) { var controlRow = $('#tabLearnerControlTable tr'), learnersSearchPhrase = $('#learnersSearchPhrase').val(); - if (numberActiveLearners < 10 && (!learnersSearchPhrase || learnersSearchPhrase.trim() == '')) { + if (learnerPossibleNumber < 10 && (!learnersSearchPhrase || learnersSearchPhrase.trim() == '')) { // do not show the bar at all $('.learnersHeaderCell', controlRow).hide(); return; } // show the bar $('.learnersHeaderCell', controlRow).show(); - var pageCount = Math.ceil(numberActiveLearners / 10); + var pageCount = Math.ceil(learnerPossibleNumber / 10); if (!pageNumber) { pageNumber = 1; } else if (pageNumber > pageCount) { @@ -1743,7 +1750,7 @@ }, success : function(response) { - numberActiveLearners = response.numberActiveLearners; + learnerPossibleNumber = response.learnerPossibleNumber; updateLearnerProgressHeader(pageNumber); if (response.learners) { Index: lams_monitoring/web/monitor.jsp =================================================================== diff -u -r184121401ec92fa82a32c0f5b1f094d30dc4699e -r8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9 --- lams_monitoring/web/monitor.jsp (.../monitor.jsp) (revision 184121401ec92fa82a32c0f5b1f094d30dc4699e) +++ lams_monitoring/web/monitor.jsp (.../monitor.jsp) (revision 8cb13884a046af1fee45dc7ab6e6f5a7f21c07c9) @@ -41,6 +41,7 @@ presenceEnabled = false, hasDialog = false, enableExportPortfolio = ${enableExportPortfolio}, + sequenceTabShowInfo = ${sequenceTabShowInfo eq true}, LAMS_URL = '', @@ -136,6 +137,8 @@ TOSTART_ACTIVITY : '', SUPPORT_ACTIVITY : '', + + PROGRESS_NOT_STARTED : '', EXPORT_PORTFOLIO : '', @@ -432,7 +435,7 @@ @@ -544,11 +547,9 @@ - -
- -
-
+
+ +