Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/UserManageAction.java =================================================================== diff -u -r1d2ff22c947ab0d5646bb02b8189ca668020bdbc -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/UserManageAction.java (.../UserManageAction.java) (revision 1d2ff22c947ab0d5646bb02b8189ca668020bdbc) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/UserManageAction.java (.../UserManageAction.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -57,115 +57,111 @@ /** * struts doclets * - * @struts:action path="/usermanage" - * validate="false" + * @struts:action path="/usermanage" validate="false" * - * @struts:action-forward name="userlist" - * path=".userlist" + * @struts:action-forward name="userlist" path=".userlist" */ public class UserManageAction extends Action { - - private static final Logger log = Logger.getLogger(UserManageAction.class); - private static IUserManagementService service; - private static MessageService messageService; - - @SuppressWarnings("unchecked") - public ActionForward execute(ActionMapping mapping, - ActionForm form, - HttpServletRequest request, - HttpServletResponse response) throws Exception { - - service = AdminServiceProxy.getService(getServlet().getServletContext()); - messageService = AdminServiceProxy.getMessageService(getServlet().getServletContext()); - - // get id of org to list users for - Integer orgId = WebUtil.readIntParam(request,"org",true); - if(orgId==null){ - orgId = (Integer)request.getAttribute("org"); - } - if((orgId==null)||(orgId<=0)){ - return forwardError(mapping, request, "error.org.invalid"); - } - log.debug("orgId: "+orgId); - - // get org name - Organisation organisation = (Organisation)service.findById(Organisation.class,orgId); - if(organisation==null) { - return forwardError(mapping, request, "error.org.invalid"); - } - String orgName = organisation.getName(); - log.debug("orgName: "+orgName); - - Organisation pOrg = organisation.getParentOrganisation(); - if(pOrg!=null){ - request.setAttribute("pOrgId",pOrg.getOrganisationId()); - request.setAttribute("pOrgName",pOrg.getName()); - } - OrganisationType orgType = organisation.getOrganisationType(); - request.setAttribute("orgType",orgType.getOrganisationTypeId()); - - // create form object - UserListDTO userManageForm = new UserListDTO(); - - Integer userId = ((UserDTO)SessionManager.getSession().getAttribute(AttributeNames.USER)).getUserID(); - Organisation orgOfCourseAdmin = (orgType.getOrganisationTypeId().equals(OrganisationType.CLASS_TYPE)) ? pOrg : organisation; - // check permission - Integer rootOrgId = service.getRootOrganisation().getOrganisationId(); - if(request.isUserInRole(Role.SYSADMIN) - || (service.isUserGlobalGroupAdmin() && !orgId.equals(rootOrgId))){ - userManageForm.setCourseAdminCanAddNewUsers(true); - userManageForm.setCourseAdminCanBrowseAllUsers(true); - request.setAttribute("canDeleteUser", true); - }else if((service.isUserInRole(userId,orgOfCourseAdmin.getOrganisationId(),Role.GROUP_ADMIN) - || service.isUserInRole(userId,orgOfCourseAdmin.getOrganisationId(),Role.GROUP_MANAGER)) - && !orgId.equals(rootOrgId)){ - userManageForm.setCourseAdminCanAddNewUsers(orgOfCourseAdmin.getCourseAdminCanAddNewUsers()); - userManageForm.setCourseAdminCanBrowseAllUsers(orgOfCourseAdmin.getCourseAdminCanBrowseAllUsers()); - }else{ - return forwardError(mapping, request, "error.authorisation"); - } - - userManageForm.setOrgId(orgId); - userManageForm.setOrgName(orgName); - List userManageBeans = service.getUserManageBeans(orgId); - Collections.sort(userManageBeans); - userManageForm.setUserManageBeans(userManageBeans); - request.setAttribute("UserManageForm", userManageForm); - - // heading - String[] args = { orgName }; - request.setAttribute("heading", messageService.getMessage("heading.manage.group.users", args)); - - // count roles in the org - HashMap roleCount = new HashMap(); - if (orgId.equals(rootOrgId)) { - roleCount.put(Role.SYSADMIN, Role.ROLE_SYSADMIN); - roleCount.put(Role.GROUP_ADMIN, Role.ROLE_GROUP_ADMIN); - } else { - roleCount.put(Role.LEARNER, Role.ROLE_LEARNER); - roleCount.put(Role.MONITOR, Role.ROLE_MONITOR); - roleCount.put(Role.AUTHOR, Role.ROLE_AUTHOR); - roleCount.put(Role.GROUP_MANAGER, Role.ROLE_GROUP_MANAGER); - roleCount.put(Role.GROUP_ADMIN, Role.ROLE_GROUP_ADMIN); - } - for (String role : roleCount.keySet()) { - Integer count = service.getCountRoleForOrg(orgId, roleCount.get(role)); - request.setAttribute(role.replace(' ', '_'), count); - } - - // count users in the org - // TODO use hql that does a count instead of getting whole objects - Integer numUsers = Integer.valueOf(service.getUsersFromOrganisation(orgId).size()); - args[0] = numUsers.toString(); - request.setAttribute("numUsers", messageService.getMessage("label.users.in.group", args)); - - return mapping.findForward("userlist"); + + private static final Logger log = Logger.getLogger(UserManageAction.class); + private static IUserManagementService service; + private static MessageService messageService; + + @SuppressWarnings("unchecked") + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + + service = AdminServiceProxy.getService(getServlet().getServletContext()); + messageService = AdminServiceProxy.getMessageService(getServlet().getServletContext()); + + // get id of org to list users for + Integer orgId = WebUtil.readIntParam(request, "org", true); + if (orgId == null) { + orgId = (Integer) request.getAttribute("org"); } - - private ActionForward forwardError(ActionMapping mapping, HttpServletRequest request, String key) { - request.setAttribute("errorName","UserManageAction"); - request.setAttribute("errorMessage",messageService.getMessage(key)); - return mapping.findForward("error"); + if ((orgId == null) || (orgId <= 0)) { + return forwardError(mapping, request, "error.org.invalid"); } + log.debug("orgId: " + orgId); + // get org name + Organisation organisation = (Organisation) service.findById(Organisation.class, orgId); + if (organisation == null) { + return forwardError(mapping, request, "error.org.invalid"); + } + String orgName = organisation.getName(); + log.debug("orgName: " + orgName); + + Organisation pOrg = organisation.getParentOrganisation(); + if (pOrg != null) { + request.setAttribute("pOrgId", pOrg.getOrganisationId()); + request.setAttribute("pOrgName", pOrg.getName()); + } + OrganisationType orgType = organisation.getOrganisationType(); + request.setAttribute("orgType", orgType.getOrganisationTypeId()); + + // create form object + UserListDTO userManageForm = new UserListDTO(); + + Integer userId = ((UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER)).getUserID(); + Organisation orgOfCourseAdmin = (orgType.getOrganisationTypeId().equals(OrganisationType.CLASS_TYPE)) ? pOrg + : organisation; + // check permission + Integer rootOrgId = service.getRootOrganisation().getOrganisationId(); + if (request.isUserInRole(Role.SYSADMIN) || (service.isUserGlobalGroupAdmin() && !orgId.equals(rootOrgId))) { + userManageForm.setCourseAdminCanAddNewUsers(true); + userManageForm.setCourseAdminCanBrowseAllUsers(true); + request.setAttribute("canDeleteUser", true); + } else if ((service.isUserInRole(userId, orgOfCourseAdmin.getOrganisationId(), Role.GROUP_ADMIN) + || service.isUserInRole(userId, orgOfCourseAdmin.getOrganisationId(), Role.GROUP_MANAGER)) + && !orgId.equals(rootOrgId)) { + userManageForm.setCourseAdminCanAddNewUsers(orgOfCourseAdmin.getCourseAdminCanAddNewUsers()); + userManageForm.setCourseAdminCanBrowseAllUsers(orgOfCourseAdmin.getCourseAdminCanBrowseAllUsers()); + } else { + return forwardError(mapping, request, "error.authorisation"); + } + + userManageForm.setOrgId(orgId); + userManageForm.setOrgName(orgName); + List userManageBeans = service.getUserManageBeans(orgId); + Collections.sort(userManageBeans); + userManageForm.setUserManageBeans(userManageBeans); + request.setAttribute("UserManageForm", userManageForm); + + // heading + String[] args = { orgName }; + request.setAttribute("heading", messageService.getMessage("heading.manage.group.users", args)); + + // count roles in the org + HashMap roleCount = new HashMap(); + if (orgId.equals(rootOrgId)) { + roleCount.put(Role.SYSADMIN, Role.ROLE_SYSADMIN); + roleCount.put(Role.GROUP_ADMIN, Role.ROLE_GROUP_ADMIN); + } else { + roleCount.put(Role.LEARNER, Role.ROLE_LEARNER); + roleCount.put(Role.MONITOR, Role.ROLE_MONITOR); + roleCount.put(Role.AUTHOR, Role.ROLE_AUTHOR); + roleCount.put(Role.GROUP_MANAGER, Role.ROLE_GROUP_MANAGER); + roleCount.put(Role.GROUP_ADMIN, Role.ROLE_GROUP_ADMIN); + } + for (String role : roleCount.keySet()) { + Integer count = service.getCountRoleForOrg(orgId, roleCount.get(role), null); + request.setAttribute(role.replace(' ', '_'), count); + } + + // count users in the org + // TODO use hql that does a count instead of getting whole objects + Integer numUsers = Integer.valueOf(service.getUsersFromOrganisation(orgId).size()); + args[0] = numUsers.toString(); + request.setAttribute("numUsers", messageService.getMessage("label.users.in.group", args)); + + return mapping.findForward("userlist"); + } + + private ActionForward forwardError(ActionMapping mapping, HttpServletRequest request, String key) { + request.setAttribute("errorName", "UserManageAction"); + request.setAttribute("errorMessage", messageService.getMessage(key)); + return mapping.findForward("error"); + } + } Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -reb8cf79579303048eefce860e543f36186d3ce10 -r41bb651a1488681fd9ca663ead283b47defdc408 Binary files differ Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java =================================================================== diff -u -r2e5d858e9dd95ddc9aa092c307b2039c9cb62930 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java (.../ILessonDAO.java) (revision 2e5d858e9dd95ddc9aa092c307b2039c9cb62930) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java (.../ILessonDAO.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -25,6 +25,7 @@ import java.util.Date; import java.util.List; +import java.util.Map; import org.lamsfoundation.lams.dao.IBaseDAO; import org.lamsfoundation.lams.lesson.Lesson; @@ -144,6 +145,13 @@ Integer getCountLearnersByLesson(long lessonId, String searchPhrase); /** + * Maps users from an organisation with the given role to a boolean value saying whether they participate in the + * given lesson. + */ + Map getUsersWithLessonParticipation(Long lessonId, String role, String searchPhrase, Integer limit, + Integer offset, boolean orderAscending); + + /** * Get all the preview lessons more with the creation date before the given date. * * @param startDate Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java =================================================================== diff -u -r2e5d858e9dd95ddc9aa092c307b2039c9cb62930 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java (.../LessonDAO.java) (revision 2e5d858e9dd95ddc9aa092c307b2039c9cb62930) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java (.../LessonDAO.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -24,7 +24,9 @@ package org.lamsfoundation.lams.lesson.dao.hibernate; import java.util.Date; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import org.apache.commons.lang.StringUtils; import org.hibernate.FetchMode; @@ -69,9 +71,17 @@ 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 AND groups.groupName NOT LIKE '%Staff%'"; + + "INNER JOIN groups.users AS users WHERE lesson.id = :lessonId AND lessonClass.staffGroup != groups"; + private final static String LOAD_USERS_WITH_LESSON_PARTICIPATION = "SELECT users.*, ug.user_id IS NOT NULL AS participant " + + "FROM lams_lesson AS l " + + "JOIN lams_user_organisation AS uo ON l.lesson_id = :lessonId AND l.organisation_id = uo.organisation_id " + + "JOIN lams_user_organisation_role AS r ON r.role_id = :roleId AND r.user_organisation_id = uo.user_organisation_id " + + "JOIN lams_user AS users ON uo.user_id = users.user_id " + + "JOIN lams_grouping AS ging ON l.class_grouping_id = ging.grouping_id " + + "JOIN lams_group AS g ON g.group_id ging.staff_group_id AND g.grouping_id = ging.grouping_id " + + "LEFT JOIN lams_user_group AS ug ON ug.group_id = g.group_id AND users.user_id = ug.user_id"; + /** * Retrieves the Lesson. Used in instances where it cannot be lazy loaded so it forces an initialize. * @@ -161,8 +171,19 @@ @Override public List getLearnersByLesson(Long lessonId, String searchPhrase, Integer limit, Integer offset, boolean orderAscending) { - String queryText = LessonDAO.buildLearnersByLessonQuery(false, searchPhrase, orderAscending); - Query query = getSession().createQuery(queryText).setLong("lessonId", lessonId); + StringBuilder queryTextBuilder = new StringBuilder("SELECT users ").append(LessonDAO.LOAD_LEARNERS_BY_LESSON); + if (!StringUtils.isBlank(searchPhrase)) { + String[] tokens = searchPhrase.trim().split("\\s+"); + for (String token : tokens) { + queryTextBuilder.append(" AND (users.firstName LIKE '%").append(token) + .append("%' OR users.lastName LIKE '%").append(token).append("%' OR users.login LIKE '%") + .append(token).append("%')"); + } + } + String order = orderAscending ? "ASC" : "DESC"; + queryTextBuilder.append(" ORDER BY users.firstName ").append(order).append(", users.lastName ").append(order) + .append(", users.login ").append(order); + Query query = getSession().createQuery(queryTextBuilder.toString()).setLong("lessonId", lessonId); if (limit != null) { query.setMaxResults(limit); } @@ -174,8 +195,18 @@ @Override public Integer getCountLearnersByLesson(long lessonId, String searchPhrase) { - String queryText = LessonDAO.buildLearnersByLessonQuery(true, searchPhrase, true); - Query query = getSession().createQuery(queryText).setLong("lessonId", lessonId); + StringBuilder queryTextBuilder = new StringBuilder("SELECT COUNT(*) ") + .append(LessonDAO.LOAD_LEARNERS_BY_LESSON); + if (!StringUtils.isBlank(searchPhrase)) { + String[] tokens = searchPhrase.trim().split("\\s+"); + for (String token : tokens) { + queryTextBuilder.append(" AND (users.firstName LIKE '%").append(token) + .append("%' OR users.lastName LIKE '%").append(token).append("%' OR users.login LIKE '%") + .append(token).append("%')"); + } + } + + Query query = getSession().createQuery(queryTextBuilder.toString()).setLong("lessonId", lessonId); Object value = query.uniqueResult(); return ((Number) value).intValue(); } @@ -335,21 +366,51 @@ return (Lesson) query.uniqueResult(); } - private static String buildLearnersByLessonQuery(boolean count, String searchPhrase, boolean orderAscending) { - StringBuilder queryText = new StringBuilder("SELECT ").append(count ? "COUNT(*) " : "users ") - .append(LessonDAO.LOAD_LEARNERS_BY_LESSON); + /** + * Maps users from an organisation with the given role to a boolean value saying whether they participate in the + * given lesson. + */ + @SuppressWarnings("unchecked") + @Override + public Map getUsersWithLessonParticipation(final Long lessonId, final String role, + String searchPhrase, final Integer limit, final Integer offset, boolean orderAscending) { + String queryTextBase = LessonDAO.LOAD_USERS_WITH_LESSON_PARTICIPATION; + // whether to exclude staff group or make it the only group that counts + queryTextBase = queryTextBase.replace("", role.equals(Role.MONITOR) ? "=" : "<>"); + StringBuilder queryTextBuilder = new StringBuilder(queryTextBase); + // is it a result of a search? if (!StringUtils.isBlank(searchPhrase)) { + queryTextBuilder.append(" WHERE"); 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("%')"); + queryTextBuilder.append(" (users.first_name LIKE '%").append(token) + .append("%' OR users.last_name LIKE '%").append(token).append("%' OR users.login LIKE '%") + .append(token).append("%') AND"); } + queryTextBuilder.delete(queryTextBuilder.length() - 4, queryTextBuilder.length()); } - if (!count) { - String order = orderAscending ? "ASC" : "DESC"; - queryText.append(" ORDER BY users.firstName ").append(order).append(", users.lastName ").append(order) - .append(", users.login ").append(order); + String order = orderAscending ? "ASC" : "DESC"; + queryTextBuilder.append(" ORDER BY users.first_name ").append(order).append(", users.last_name ").append(order) + .append(", users.login ").append(order); + + Query query = getSession().createSQLQuery(queryTextBuilder.toString()).addEntity(User.class) + .addScalar("participant").setLong("lessonId", lessonId) + .setInteger("roleId", role.equals(Role.MONITOR) ? Role.ROLE_MONITOR : Role.ROLE_LEARNER); + if (limit != null) { + query.setMaxResults(limit); } - return queryText.toString(); + if (offset != null) { + query.setFirstResult(offset); + } + + List resultQuery = query.list(); + + // this map keeps the insertion order + Map result = new LinkedHashMap(); + // make the result easier to process + for (Object[] entry : resultQuery) { + result.put((User) entry[0], ((Integer) entry[1]).equals(1)); + } + return result; } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java =================================================================== diff -u -reb8cf79579303048eefce860e543f36186d3ce10 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision eb8cf79579303048eefce860e543f36186d3ce10) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -76,6 +76,13 @@ boolean orderAscending); /** + * Maps users from an organisation with the given role to a boolean value saying whether they participate in the + * given lesson. + */ + Map getUsersWithLessonParticipation(Long lessonId, String role, String searchPhrase, Integer limit, + Integer offset, boolean orderAscending); + + /** * Get the count of all the learners who are a part of the lesson class. */ Integer getCountLessonLearners(Long lessonId, String searchPhrase); @@ -243,6 +250,11 @@ void addLearners(Lesson lesson, Collection users) throws LessonServiceException; /** + * Removes the learner from the lesson. + */ + boolean removeLearner(Long lessonId, Integer userId); + + /** * Set the learners in a lesson class. Learners not in the users collection will be removed. To be called within * LAMS. * @@ -285,6 +297,9 @@ */ void addStaffMembers(Lesson lesson, Collection users) throws LessonServiceException; + // removes the staff member from the lesson + boolean removeStaffMember(Long lessonId, Integer userId); + /** * Set the staff members in a lesson class. Staff members not in the users collection will be removed. To be called * within LAMS. Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java =================================================================== diff -u -reb8cf79579303048eefce860e543f36186d3ce10 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision eb8cf79579303048eefce860e543f36186d3ce10) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -123,6 +123,12 @@ } @Override + public Map getUsersWithLessonParticipation(Long lessonId, String role, String searchPhrase, + Integer limit, Integer offset, boolean orderAscending) { + return lessonDAO.getUsersWithLessonParticipation(lessonId, role, searchPhrase, limit, offset, orderAscending); + } + + @Override public Integer getCountLessonLearners(Long lessonId, String searchPhrase) { return lessonDAO.getCountLearnersByLesson(lessonId, searchPhrase); } @@ -341,6 +347,20 @@ } @Override + public boolean removeLearner(Long lessonId, Integer userId) { + Lesson lesson = lessonDAO.getLesson(lessonId); + LessonClass lessonClass = lesson.getLessonClass(); + User user = (User) baseDAO.find(User.class, userId); + Group learnerGroup = lessonClass.getGroupBy(user); + boolean result = learnerGroup.getUsers().remove(user); + + if (result) { + lessonClassDAO.updateLessonClass(lessonClass); + } + return result; + } + + @Override public void addLearners(Long lessonId, Integer[] userIds) throws LessonServiceException { Lesson lesson = lessonDAO.getLesson(lessonId); @@ -420,6 +440,20 @@ } @Override + public boolean removeStaffMember(Long lessonId, Integer userId) { + Lesson lesson = lessonDAO.getLesson(lessonId); + LessonClass lessonClass = lesson.getLessonClass(); + User user = (User) baseDAO.find(User.class, userId); + Group staffGroup = lessonClass.getStaffGroup(); + boolean result = staffGroup.getUsers().remove(user); + + if (result) { + lessonClassDAO.updateLessonClass(lessonClass); + } + return result; + } + + @Override public void addStaffMembers(Long lessonId, Integer[] userIds) throws LessonServiceException { Lesson lesson = lessonDAO.getLesson(lessonId); Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/dao/IRoleDAO.java =================================================================== diff -u -r7ab9e2377fd1ff4c3c5554bd1f6dffe3384f6f9a -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/dao/IRoleDAO.java (.../IRoleDAO.java) (revision 7ab9e2377fd1ff4c3c5554bd1f6dffe3384f6f9a) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/dao/IRoleDAO.java (.../IRoleDAO.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -23,41 +23,17 @@ /* $$Id$$ */ package org.lamsfoundation.lams.usermanagement.dao; -import java.util.List; - import org.lamsfoundation.lams.dao.IBaseDAO; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.User; /** - * Inteface defines Lesson DAO Methods - * @author chris + * Inteface defines Role DAO Methods */ -public interface IRoleDAO extends IBaseDAO -{ - /** - * - * @param userId - * @param roleId - * @param organisation - * @return - */ - public User getUserByOrganisationAndRole(final Integer userId, final Integer roleId, final Organisation organisation); - - - /** - * - * @param roleId - * @return - */ - public Integer getCountRoleForSystem(final Integer roleId); - - /** - * Get number of users with roleId in orgId. - * @param roleId - * @param orgId - * @return - */ - public Integer getCountRoleForOrg(final Integer roleId, final Integer orgId); +public interface IRoleDAO extends IBaseDAO { + User getUserByOrganisationAndRole(Integer userId, Integer roleId, Organisation organisation); -} + Integer getCountRoleForSystem(final Integer roleId); + + Integer getCountRoleForOrg(Integer roleId, Integer orgId, String searchPhrase); +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/dao/hibernate/RoleDAO.java =================================================================== diff -u -rb6ed1309cf89ecede6717145c629d7cb3b842582 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/dao/hibernate/RoleDAO.java (.../RoleDAO.java) (revision b6ed1309cf89ecede6717145c629d7cb3b842582) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/dao/hibernate/RoleDAO.java (.../RoleDAO.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -23,60 +23,66 @@ /* $$Id$$ */ package org.lamsfoundation.lams.usermanagement.dao.hibernate; +import org.apache.commons.lang.StringUtils; import org.hibernate.Query; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.UserOrganisationRole; import org.lamsfoundation.lams.usermanagement.dao.IRoleDAO; import org.springframework.stereotype.Repository; + /** * Hibernate implementation of IRoleDAO + * * @author chris */ @Repository -public class RoleDAO extends LAMSBaseDAO implements IRoleDAO -{ - private final static String LOAD_USER_BY_ORG_AND_ROLE = - "select u " - +"from User u, UserOrganisation uo, UserOrganisationRole uor " - +"where u.id = :userId and " - +"u.id = uo.user.id and " - +"uo.organisation = :org and " - +"uor.userOrganisation.id = uo.id and " - +"uor.role.id = :roleId"; - - private final static String COUNT_ROLE = "select count(distinct userOrganisationRole.userOrganisation.user)" - + " from "+UserOrganisationRole.class.getName()+" userOrganisationRole" - + " where userOrganisationRole.role.roleId = :roleId"; +public class RoleDAO extends LAMSBaseDAO implements IRoleDAO { + private final static String LOAD_USER_BY_ORG_AND_ROLE = "select u " + + "from User u, UserOrganisation uo, UserOrganisationRole uor " + "where u.id = :userId and " + + "u.id = uo.user.id and " + "uo.organisation = :org and " + "uor.userOrganisation.id = uo.id and " + + "uor.role.id = :roleId"; - private final static String COUNT_ROLE_FOR_ORG = "select count(distinct uor.userOrganisation.user)" - + " from "+UserOrganisationRole.class.getName()+" uor" - + " where uor.role.roleId = :roleId" - + " and uor.userOrganisation.organisation.organisationId = :orgId"; - - public User getUserByOrganisationAndRole(final Integer userId, final Integer roleId, final Organisation organisation) - { - return (User) getSession().createQuery(LOAD_USER_BY_ORG_AND_ROLE).setInteger("userId", userId) - .setEntity("org", organisation).setInteger("roleId", roleId).uniqueResult(); + private final static String COUNT_ROLE = "select count(distinct userOrganisationRole.userOrganisation.user)" + + " from " + UserOrganisationRole.class.getName() + " userOrganisationRole" + + " where userOrganisationRole.role.roleId = :roleId"; + + private final static String COUNT_ROLE_FOR_ORG = "select count(distinct uor.userOrganisation.user) from " + + UserOrganisationRole.class.getName() + " uor where uor.role.roleId = :roleId" + + " and uor.userOrganisation.organisation.organisationId = :orgId"; + + @Override + public User getUserByOrganisationAndRole(Integer userId, Integer roleId, Organisation organisation) { + return (User) getSession().createQuery(RoleDAO.LOAD_USER_BY_ORG_AND_ROLE).setInteger("userId", userId) + .setEntity("org", organisation).setInteger("roleId", roleId).uniqueResult(); } - - public Integer getCountRoleForSystem(final Integer roleId) - { - Query query = getSession().createQuery(COUNT_ROLE); - query.setInteger("roleId", roleId.intValue()); - Object value = query.uniqueResult(); - return new Integer(((Number) value).intValue()); + @Override + public Integer getCountRoleForSystem(Integer roleId) { + + Query query = getSession().createQuery(RoleDAO.COUNT_ROLE); + query.setInteger("roleId", roleId.intValue()); + Object value = query.uniqueResult(); + return new Integer(((Number) value).intValue()); } - - public Integer getCountRoleForOrg(final Integer roleId, final Integer orgId) { - Query query = getSession().createQuery(COUNT_ROLE_FOR_ORG); - query.setInteger("roleId", roleId.intValue()); - query.setInteger("orgId", orgId.intValue()); - Object value = query.uniqueResult(); - return new Integer(((Number) value).intValue()); + + @Override + public Integer getCountRoleForOrg(Integer roleId, Integer orgId, String searchPhrase) { + StringBuilder queryTextBuilder = new StringBuilder(RoleDAO.COUNT_ROLE_FOR_ORG); + if (!StringUtils.isBlank(searchPhrase)) { + String[] tokens = searchPhrase.trim().split("\\s+"); + for (String token : tokens) { + queryTextBuilder.append(" AND (uor.userOrganisation.user.firstName LIKE '%").append(token) + .append("%' OR uor.userOrganisation.user.lastName LIKE '%").append(token) + .append("%' OR uor.userOrganisation.user.login LIKE '%").append(token).append("%')"); + } } - -} + Query query = getSession().createQuery(queryTextBuilder.toString()); + query.setInteger("roleId", roleId.intValue()); + query.setInteger("orgId", orgId.intValue()); + Object value = query.uniqueResult(); + return new Integer(((Number) value).intValue()); + } +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/IUserManagementService.java =================================================================== diff -u -r4ef740155321a3d46583770e5ea58e56719597b2 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/IUserManagementService.java (.../IUserManagementService.java) (revision 4ef740155321a3d46583770e5ea58e56719597b2) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/IUserManagementService.java (.../IUserManagementService.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -271,8 +271,8 @@ * filters results by course name. It can be null and then doesn't affect results * @return */ - List getPagedCourses(final Integer parentOrgId, final Integer typeId, final Integer stateId, - int page, int size, String sortBy, String sortOrder, String searchString); + List getPagedCourses(final Integer parentOrgId, final Integer typeId, final Integer stateId, int page, + int size, String sortBy, String sortOrder, String searchString); /** * Counts courses with specified type, state and parent course. @@ -456,7 +456,7 @@ * @param roleId * @return */ - Integer getCountRoleForOrg(Integer orgId, Integer roleId); + Integer getCountRoleForOrg(Integer orgId, Integer roleId, String searchPhrase); /** * Get default flash theme of server. Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java =================================================================== diff -u -ra939bcf145b0e4deab5838f87b047df5ca48c92d -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java (.../UserManagementService.java) (revision a939bcf145b0e4deab5838f87b047df5ca48c92d) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java (.../UserManagementService.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -1093,8 +1093,8 @@ } @Override - public Integer getCountRoleForOrg(Integer orgId, Integer roleId) { - Integer count = roleDAO.getCountRoleForOrg(roleId, orgId); + public Integer getCountRoleForOrg(Integer orgId, Integer roleId, String searchPhrase) { + Integer count = roleDAO.getCountRoleForOrg(roleId, orgId, searchPhrase); if (count != null) { return count; } else { Index: lams_monitoring/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r00543f0a53b57ce5434e45f197ba38232fa72020 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_monitoring/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 00543f0a53b57ce5434e45f197ba38232fa72020) +++ lams_monitoring/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -298,7 +298,6 @@ lesson.learner.url =Learner URL: button.select =Select lesson.copy.prompt =(now press Ctrl+C to copy to clipboard) -learner.group.select.all =Select/Unselect all email.notifications.problems.sending.emails =Some problems occurred while sending emails. Please, contact your system administrator. learner.group.remove.progress =You are about to remove student(s) from a lesson. The student(s) will not have access to this lesson any longer. Do you also want to remove the student(s) progress? force.complete.remove.content =You are moving learner "[0]" to activity "[1]". You can opt to delete the content of activities that have been previously done, so the learner has to enter the content/answers again. Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -reb8cf79579303048eefce860e543f36186d3ce10 -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision eb8cf79579303048eefce860e543f36186d3ce10) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -38,6 +38,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; @@ -136,8 +137,9 @@ private static final String ERROR = "error"; private static final DateFormat LESSON_SCHEDULING_DATETIME_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm"); - private static final Integer LATEST_LEARNER_PROGRESS_LESSON_DISPLAY_LIMIT = 53; - private static final Integer LATEST_LEARNER_PROGRESS_ACTIVITY_DISPLAY_LIMIT = 7; + private static final int LATEST_LEARNER_PROGRESS_LESSON_DISPLAY_LIMIT = 53; + private static final int LATEST_LEARNER_PROGRESS_ACTIVITY_DISPLAY_LIMIT = 7; + private static final int USER_PAGE_SIZE = 10; private static IAuditService auditService; @@ -149,6 +151,8 @@ private static IMonitoringService monitoringService; + private static IUserManagementService userManagementService; + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); @@ -668,8 +672,8 @@ boolean orderAscending = WebUtil.readBooleanParam(request, "orderAscending", true); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - List learners = getLessonService().getLessonLearners(lessonId, null, 10, (pageNumber - 1) * 10, - orderAscending); + List learners = getLessonService().getLessonLearners(lessonId, null, MonitoringAction.USER_PAGE_SIZE, + (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); JSONArray learnersJSON = new JSONArray(); for (User learner : learners) { learnersJSON.put(WebUtil.userToJSON(learner)); @@ -688,40 +692,46 @@ /** * Gets learners or monitors of the lesson and organisation containing it. */ - @SuppressWarnings("unchecked") public ActionForward getClassMembers(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, JSONException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - String role = WebUtil.readStrParam(request, AttributeNames.PARAM_ROLE); - boolean getMonitors = Role.MONITOR.equalsIgnoreCase(role); Lesson lesson = getLessonService().getLesson(lessonId); - Set classUsers = getMonitors ? lesson.getLessonClass().getStaffGroup().getUsers() - : lesson.getLessonClass().getLearners(); - JSONArray responseJSON = new JSONArray(); + String role = WebUtil.readStrParam(request, AttributeNames.PARAM_ROLE); + boolean isMonitor = role.equals(Role.MONITOR); + User creator = isMonitor ? lesson.getUser() : null; + Integer currentUserId = isMonitor ? getUserId() : null; + String searchPhrase = request.getParameter("searchPhrase"); + Integer pageNumber = WebUtil.readIntParam(request, "pageNumber", true); + if (pageNumber == null) { + pageNumber = 1; + } + boolean orderAscending = WebUtil.readBooleanParam(request, "orderAscending", true); + JSONObject responseJSON = new JSONObject(); - for (User user : classUsers) { + // find organisation users and whether they participate in the current lesson + Map users = getLessonService().getUsersWithLessonParticipation(lessonId, role, searchPhrase, + MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); + + // if the result is less then page size, then no need for full check of user count + Integer userCount = users.size() < MonitoringAction.USER_PAGE_SIZE ? users.size() + : getUserManagementService().getCountRoleForOrg(lesson.getOrganisation().getOrganisationId(), + isMonitor ? Role.ROLE_MONITOR : Role.ROLE_LEARNER, searchPhrase); + + responseJSON.put("userCount", userCount); + + JSONArray usersJSON = new JSONArray(); + for (Entry userEntry : users.entrySet()) { + User user = userEntry.getKey(); JSONObject userJSON = WebUtil.userToJSON(user); - // mark that this user is a class member - userJSON.put("classMember", true); - if (lesson.getUser().equals(user)) { - // mark this user is lesson author - userJSON.put("lessonCreator", true); - } - responseJSON.put(userJSON); + userJSON.put("classMember", userEntry.getValue()); + // teacher can't remove lesson creator and himself from the lesson staff + if (isMonitor && (creator.getUserId().equals(user.getUserId()) || currentUserId.equals(user.getUserId()))) { + userJSON.put("readonly", true); + } + usersJSON.put(userJSON); } + responseJSON.put("users", usersJSON); - IUserManagementService userManagementService = MonitoringServiceProxy - .getUserManagementService(getServlet().getServletContext()); - List orgUsers = userManagementService.getUsersFromOrganisationByRole( - lesson.getOrganisation().getOrganisationId(), getMonitors ? Role.MONITOR : Role.LEARNER, false, true); - for (User user : orgUsers) { - if (!classUsers.contains(user)) { - JSONObject userJSON = WebUtil.userToJSON(user); - userJSON.put("classMember", false); - responseJSON.put(userJSON); - } - } - response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); return null; @@ -744,7 +754,8 @@ Long activityId = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID, true); if (activityId == null) { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - List learners = getMonitoringService().getUsersCompletedLesson(lessonId, 10, (pageNumber - 1) * 10, + List learners = getMonitoringService().getUsersCompletedLesson(lessonId, + MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, orderAscending); for (User learner : learners) { learnersJSON.put(WebUtil.userToJSON(learner)); @@ -767,7 +778,8 @@ } List learners = getMonitoringService().getLearnersByActivities(activities.toArray(new Long[] {}), - null, null, orderAscending); + MonitoringAction.USER_PAGE_SIZE, (pageNumber - 1) * MonitoringAction.USER_PAGE_SIZE, + orderAscending); for (User learner : learners) { learnersJSON.put(WebUtil.userToJSON(learner)); } @@ -789,28 +801,34 @@ public ActionForward updateLessonClass(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, JSONException { long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - Lesson lesson = getLessonService().getLesson(lessonId); + int userId = WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID); + String role = WebUtil.readStrParam(request, AttributeNames.PARAM_ROLE); + boolean add = WebUtil.readBooleanParam(request, "add"); + boolean result = false; - // monitor user opted for removing lesson progress for following users - IUserManagementService userManagementService = MonitoringServiceProxy - .getUserManagementService(getServlet().getServletContext()); - List allUsers = userManagementService - .getUsersFromOrganisation(lesson.getOrganisation().getOrganisationId()); - List removedLearners = parseUserList(request, "removedLearners", allUsers); - for (User removedLearner : removedLearners) { - getLessonService().removeLearnerProgress(lessonId, removedLearner.getUserId()); - if (LamsDispatchAction.log.isDebugEnabled()) { - LamsDispatchAction.log.debug( - "Removed progress for user ID: " + removedLearner.getUserId() + " in lesson ID: " + lessonId); + if (role.equals(Role.MONITOR)) { + if (add) { + result = getLessonService().addStaffMember(lessonId, userId); + } else { + result = getLessonService().removeStaffMember(lessonId, userId); } + } else if (role.equals(Role.LEARNER)) { + if (add) { + result = getLessonService().addLearner(lessonId, userId); + } else { + getLessonService().removeLearnerProgress(lessonId, userId); + result = getLessonService().removeLearner(lessonId, userId); + } } - List learners = parseUserList(request, "learners", allUsers); - getLessonService().updateLearners(lesson, learners); + if (result) { + LamsDispatchAction.log.info((add ? "Added a " : "Removed a ") + role + " with ID " + userId + + (add ? " to" : " from") + " lesson " + lessonId); + } else { + LamsDispatchAction.log.warn("Failed when trying to " + (add ? "add a " : "remove a ") + role + " with ID " + + userId + (add ? " to" : " from") + " lesson " + lessonId); + } - List staff = parseUserList(request, "monitors", allUsers); - getLessonService().updateStaffMembers(lesson, staff); - return null; } @@ -1299,7 +1317,8 @@ long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); String searchPhrase = request.getParameter("term"); - List learners = getLessonService().getLessonLearners(lessonId, searchPhrase, 10, null, true); + List learners = getLessonService().getLessonLearners(lessonId, searchPhrase, + MonitoringAction.USER_PAGE_SIZE, null, true); JSONArray responseJSON = new JSONArray(); for (User learner : learners) { JSONObject learnerJSON = new JSONObject(); @@ -1498,6 +1517,15 @@ return MonitoringAction.securityService; } + private IUserManagementService getUserManagementService() { + if (MonitoringAction.userManagementService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + MonitoringAction.userManagementService = (IUserManagementService) ctx.getBean("userManagementService"); + } + return MonitoringAction.userManagementService; + } + /** * Set whether or not the export portfolio button is available in learner. Expects parameters lessonID and * learnerExportPortfolio. @@ -1670,9 +1698,8 @@ return result; } - /** - * Puts the searched learner in front of other learners in the list. + * Puts the searched learner in front of other learners in the list. */ private static List insertSearchedLearner(User searchedLearner, List latestLearners, int limit) { latestLearners.remove(searchedLearner); Index: lams_monitoring/web/css/monitorLesson.css =================================================================== diff -u -r2f67a20e73128f03e7b4221ca09426c14bef2abf -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_monitoring/web/css/monitorLesson.css (.../monitorLesson.css) (revision 2f67a20e73128f03e7b4221ca09426c14bef2abf) +++ lams_monitoring/web/css/monitorLesson.css (.../monitorLesson.css) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -43,9 +43,8 @@ border: none; } -.dialogList { +.dialogContainer .dialogList { overflow: auto; - border: thin solid black; padding: 5px; } @@ -71,31 +70,24 @@ text-align: center; } -.dialogListSortButton { - text-align: right; - padding-right: 3px; - float: right; - cursor: pointer; -} - -#learnerGroupDialog td { +div.dialogContainer td { padding: 0; } -#learnerGroupDialog td.learnerGroupNav { +div.dialogContainer td.navCell { padding: 5px 0; cursor: pointer; } -#learnerGroupDialog td.learnerGroupNav:hover { +div.dialogContainer td.navCell:hover { background-color: #D0E5F5; } -td.learnerGroupNav span { +div.dialogContainer td.navCell span { margin: auto; } -#learnerGroupPage { +div.dialogContainer td.pageCell { text-align: center; width: 100px; } @@ -171,20 +163,42 @@ float: right; } -#classDialogTable { - border-spacing: 5px 0; -} - #classDialogTable td { - width: 50%; vertical-align: top; } +#classDialogTable #classMonitorSearchRow { + height: 23px; +} + +#classDialogTable #classSearchPhrase { + width: 90%; +} + +#classDialogTable #classSearchPhraseIcon { + margin-top: 2px; +} + +#classDialogTable #classSearchPhraseClear { + visibility: hidden; + margin-top: 3px; + cursor: pointer; +} + #classDialogTable input[type="checkbox"] { margin: 0 5px 0px 0px; border: none; } +#classLearnerTable { + width: 320px; + border-right: thin solid black; +} + +#classMonitorTable { + margin-left: 10px; +} + #emailDialog { width: 100%; } Index: lams_monitoring/web/includes/javascript/monitorLesson.js =================================================================== diff -u -r2f67a20e73128f03e7b4221ca09426c14bef2abf -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 2f67a20e73128f03e7b4221ca09426c14bef2abf) +++ lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -13,11 +13,6 @@ sequenceInfoTimeout = 10000, // which learner was selected in the search box sequenceSearchedLearner = null, -// how learners in pop up lists are currently sorted - sortOrderAsc = { - classLearner : false, - classMonitor : false - }, // container for learners' progress bars metadata bars = null, // placeholder for single learner's progress bar and title @@ -188,7 +183,7 @@ // sets up dialog for editing class $('#classDialog').dialog({ 'autoOpen' : false, - 'height' : 360, + 'height' : 435, 'width' : 700, 'minWidth' : 700, 'modal' : true, @@ -197,74 +192,52 @@ 'hide' : 'fold', 'open' : function(){ autoRefreshBlocked = true; - // reset sort order - sortOrderAsc['classLearner'] = false; - sortOrderAsc['classMonitor'] = false; - sortLessonClassDialogList('classLearner'); - sortLessonClassDialogList('classMonitor'); - colorDialogList('classLearner'); - colorDialogList('classMonitor'); - - var selectedLearners = getSelectedClassUserList('classLearnerList'); - $(this).dialog('option', 'initSelectedLearners', selectedLearners); }, 'close' : function(){ autoRefreshBlocked = false; + refreshMonitor(); }, 'buttons' : [ { - 'text' : LABELS.SAVE_BUTTON, - 'id' : 'classDialogSaveButton', + 'text' : LABELS.CANCEL_BUTTON, + 'id' : 'classDialogCancelButton', 'click' : function() { - var removedLearners = [], - dialog = $(this), - initSelectedLearners = dialog.dialog('option', 'initSelectedLearners'), - learners = getSelectedClassUserList('classLearnerList'), - monitors = getSelectedClassUserList('classMonitorList'); - - // check for learners removed from lesson - $.each(initSelectedLearners, function(index, selectedLearnerId){ - if ($.inArray(selectedLearnerId, learners) == -1) { - removedLearners.push(selectedLearnerId); + $(this).dialog('close'); + } } + ] }); - // check if monitoring user really wants to remove progress - if (removedLearners.length > 0 && !confirm(LABELS.LEARNER_GROUP_REMOVE_PROGRESS)){ - removedLearners = []; + + // search for users with the term the Monitor entered + $("#classSearchPhrase").autocomplete({ + 'source' : LAMS_URL + "monitoring/monitoring.do?method=autocompleteMonitoringLearners&lessonID=" + lessonId, + 'delay' : 700, + 'select' : function(event, ui){ + var phraseField = $(this); + // learner's ID in ui.item.value is not used here + phraseField.val(ui.item.label); + $('#classSearchPhraseClear').css('visibility', 'visible'); + // reset to page 1 + $('#classDialog').dialog('option','LearnerAjaxProperties').pageNumber = 1; + showClassDialog('Learner'); + return false; } + }) + // run the real search when the Monitor presses Enter + .keypress(function(e){ + if (e.which == 13) { + var phraseField = $(this); - $.ajax({ - url : LAMS_URL + 'monitoring/monitoring.do', - type : 'POST', - cache : false, - data : { - 'method' : 'updateLessonClass', - 'lessonID' : lessonId, - 'learners' : learners.join(), - 'monitors' : monitors.join(), - 'removedLearners' : removedLearners.join() - }, - success : function() { - dialog.dialog('close'); - if (removedLearners.length > 0) { - refreshMonitor(); - } else { - refreshMonitor('lesson'); + phraseField.autocomplete("close"); + if (phraseField.val()) { + $('#classSearchPhraseClear').css('visibility', 'visible'); } + // reset to page 1 + $('#classDialog').dialog('option','LearnerAjaxProperties').pageNumber = 1; + showClassDialog('Learner'); } }); - } - }, - { - 'text' : LABELS.CANCEL_BUTTON, - 'id' : 'classDialogCancelButton', - 'click' : function() { - $(this).dialog('close'); - } - } - ] - }); // sets up dialog for emailing learners $('#emailDialog').dialog({ @@ -596,7 +569,7 @@ // initialise lesson dialog $('#learnerGroupDialog').dialog({ 'autoOpen' : false, - 'height' : 360, + 'height' : 365, 'width' : 400, 'minWidth' : 400, 'modal' : true, @@ -1391,115 +1364,134 @@ /** * Shows Edit Class dialog for class manipulation. */ -function showClassDialog(){ - var learners = []; - var monitors = []; - +function showClassDialog(role){ // fetch available and already participating learners and monitors - $.ajax({ - dataType : 'json', - url : LAMS_URL + 'monitoring/monitoring.do', - cache : false, - async : false, - data : { - 'method' : 'getClassMembers', - 'lessonID' : lessonId, - 'role' : 'LEARNER' - }, - success : function(response) { - learners = response; + if (!role) { + // first time show, fill both lists + fillClassList('Learner', false); + fillClassList('Monitor', true); + + $('#classDialog') + .dialog('option', + { + 'title' : LABELS.LESSON_EDIT_CLASS + }) + .dialog('open'); + } else { + // refresh after page shift or search + fillClassList(role, role.toLowerCase() == 'monitor'); + } } - }); - $.ajax({ + + +/** + * Fills class member list with user information. + */ +function fillClassList(role, disableCreator) { + var dialog = $('#classDialog'), + tableID = 'class' + role + 'Table', + table = $('#' + tableID, dialog), + list = $('.dialogList', table).empty(), + searchPhrase = role == 'Learner' ? $('#classSearchPhrase', table).val() : null, + ajaxProperties = dialog.dialog('option', role + 'AjaxProperties'), + users = null, + userCount = null; + + if (!ajaxProperties) { + // initialise ajax config + ajaxProperties = { dataType : 'json', url : LAMS_URL + 'monitoring/monitoring.do', cache : false, async : false, data : { 'method' : 'getClassMembers', 'lessonID' : lessonId, - 'role' : 'MONITOR' - }, - success : function(response) { - monitors = response; + 'role' : role.toUpperCase(), + 'pageNumber' : 1, + 'orderAscending' : true } - }); + }; - // fill lists - fillClassDialogList('classLearner', learners, false); - fillClassDialogList('classMonitor', monitors, true); + dialog.dialog('option', role + 'AjaxProperties', ajaxProperties); + } - $('#classDialog') - .dialog('option', - { - 'title' : LABELS.LESSON_EDIT_CLASS - }) - .dialog('open'); + // add properties for this call only + if (searchPhrase && searchPhrase.trim() == ''){ + searchPhrase = null; + } + ajaxProperties.data.searchPhrase = searchPhrase; + ajaxProperties.success = function(response) { + users = response.users; + userCount = response.userCount; } + $.ajax(ajaxProperties); -/** - * Fills class member list with user information. - */ -function fillClassDialogList(listId, users, disableCreator) { - var list = $('#' + listId + 'List').empty(); - var selectAllInitState = true; + // hide unnecessary controls + togglePagingCells(table, ajaxProperties.data.pageNumber, Math.ceil(userCount / 10)); $.each(users, function(userIndex, user) { var checkbox = $('').attr({ 'type' : 'checkbox' }).change(function(){ - var itemState = $(this).is(':checked'); - if (itemState) { - var selectAllState = true; - $('input', list).each(function(){ - if (!$(this).is(':checked')) { - selectAllState = false; - return false; - } - }); + editClassMember($(this)); + }), - if (selectAllState) { - $('#' + listId + 'SelectAll').prop('checked', 'checked'); - } - } else { - $('#' + listId + 'SelectAll').prop('checked', null); - } + userDiv = $('
').attr({ + 'userId' : user.id + }) + .addClass('dialogListItem') + .html(getLearnerDisplayName(user)) + .prepend(checkbox) + .appendTo(list); - }); if (user.classMember) { checkbox.prop('checked', 'checked'); - if (disableCreator && user.lessonCreator) { + if (user.readonly) { // user creator must not be deselected checkbox.attr('disabled', 'disabled'); } - } else { - selectAllInitState = false; } - var userDiv = $('
').attr({ - 'userId' : user.id - }) - .addClass('dialogListItem') - .html(getLearnerDisplayName(user)) - .prepend(checkbox) - .appendTo(list); - if (disableCreator && user.lessonCreator) { userDiv.addClass('dialogListItemDisabled'); } else { userDiv.click(function(event){ - if (event.target == this) { + if (event.target == this && !checkbox.is(':disabled')) { checkbox.prop('checked', checkbox.is(':checked') ? null : 'checked'); + checkbox.change(); } }) } }); - $('#' + listId + 'SelectAll').prop('checked', selectAllInitState ? 'checked' : null); + colorDialogList(tableID); } +/** + * Adds/removes a Learner/Monitor to/from the class. + */ +function editClassMember(userCheckbox){ + var userID = userCheckbox.parent().attr('userId'), + role = userCheckbox.closest('table').is('#classMonitorTable') ? 'MONITOR' : 'LEARNER', + add = userCheckbox.is(':checked'); + + $.ajax({ + url : LAMS_URL + 'monitoring/monitoring.do', + type : 'POST', + cache : false, + data : { + 'method' : 'updateLessonClass', + 'lessonID' : lessonId, + 'userID' : userID, + 'role' : role, + 'add' : add + } + }); +} + /** * Opens Authoring for live edit. */ @@ -1802,6 +1794,15 @@ $('#learnersSearchPhraseClear').hide(); } +/** + * Clears previous run search for phrase. + */ +function classClearSearchPhrase(){ + $('#classSearchPhrase').val('').autocomplete("close"); + $('#classDialog').dialog('option', 'LearnerAjaxProperties').pageNumber = 1; + showClassDialog('Learner'); + $('#classSearchPhraseClear').css('visibility', 'hidden'); +} //********** COMMON FUNCTIONS ********** /** @@ -1852,7 +1853,7 @@ */ function showLearnerGroupDialog(ajaxProperties, dialogTitle, allowForceComplete, allowView, allowEmail) { var learnerGroupDialog = $('#learnerGroupDialog'), - learnerGroupList = $('#learnerGroupList', learnerGroupDialog).empty(), + learnerGroupList = $('.dialogList', learnerGroupDialog).empty(), // no parameters provided? just work on what we saved isRefresh = ajaxProperties == null, learners = null, @@ -1907,31 +1908,7 @@ } // hide unnecessary controls - if (pageNumber + 10 <= maxPageNumber) { - $('#learnerGroupPagePlus10', learnerGroupDialog).css('visibility', 'visible'); - } else { - $('#learnerGroupPagePlus10', learnerGroupDialog).css('visibility', 'hidden'); - } - if (pageNumber - 10 < 1) { - $('#learnerGroupPageMinus10', learnerGroupDialog).css('visibility', 'hidden'); - } else { - $('#learnerGroupPageMinus10', learnerGroupDialog).css('visibility', 'visible'); - } - if (pageNumber + 1 <= maxPageNumber) { - $('#learnerGroupPagePlus1', learnerGroupDialog).css('visibility', 'visible'); - } else { - $('#learnerGroupPagePlus1', learnerGroupDialog).css('visibility', 'hidden'); - } - if (pageNumber - 1 < 1) { - $('#learnerGroupPageMinus1', learnerGroupDialog).css('visibility', 'hidden'); - } else { - $('#learnerGroupPageMinus1', learnerGroupDialog).css('visibility', 'visible'); - } - if (maxPageNumber < 2) { - $('#learnerGroupPage', learnerGroupDialog).css('visibility', 'hidden'); - } else { - $('#learnerGroupPage', learnerGroupDialog).css('visibility', 'visible').text(pageNumber + ' / ' + maxPageNumber); - } + togglePagingCells(learnerGroupDialog, pageNumber, maxPageNumber); $.each(learners, function(learnerIndex, learner) { var viewUrl = allowView ? LAMS_URL + 'monitoring/monitoring.do?method=getLearnerActivityURL&userID=' @@ -1964,7 +1941,7 @@ } }); - colorDialogList('learnerGroup'); + colorDialogList('learnerGroupDialog'); if (!isRefresh) { // show buttons depending on parameters @@ -2017,42 +1994,34 @@ /** - * Change order of learner sorting in class dialog. + * Change order of learner sorting in group dialog. */ -function sortLessonClassDialogList(listId) { - var list = $('#' + listId + 'List'), - items = list.children('div.dialogListItem'), - orderAsc = sortOrderAsc[listId]; - if (items.length > 1) { - items.each(function(){ - $(this).detach(); - }).sort(function(a, b){ - var keyA = $(a).text().toLowerCase(); - var keyB = $(b).text().toLowerCase(); - var result = keyA > keyB ? 1 : keyA < keyB ? -1 : 0; - return orderAsc ? -result : result; - }).each(function(){ - $(this).appendTo(list); - }); +function sortLearnerGroupList() { + var learnerGroupDialog = $('#learnerGroupDialog'), + sortIcon = $('td.sortCell span', learnerGroupDialog), + ajaxProperties = learnerGroupDialog.dialog('option', 'ajaxProperties'), + // reverse current order after click + orderAscending = !ajaxProperties.data.orderAscending; - var button = $('#' + listId + 'SortButton'); - if (orderAsc) { - button.html('▼'); - sortOrderAsc[listId] = false; + if (orderAscending) { + sortIcon.removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-n'); } else { - button.html('▲'); - sortOrderAsc[listId] = true; + sortIcon.removeClass('ui-icon-triangle-1-n').addClass('ui-icon-triangle-1-s'); } + + ajaxProperties.data.orderAscending = orderAscending; + // refresh the list + showLearnerGroupDialog(); } -} /** - * Change order of learner sorting in group dialog. + * Change order of learner sorting in Edit Class dialog. */ -function sortLearnerGroupDialogList() { - var learnerGroupDialog = $('#learnerGroupDialog'), - sortIcon = $('#learnerGroupSort span', learnerGroupDialog), - ajaxProperties = learnerGroupDialog.dialog('option', 'ajaxProperties'), +function sortClassList(role) { + var classDialog = $('#classDialog'), + table = $('#class' + role + 'Table', classDialog), + sortIcon = $('td.sortCell span', table), + ajaxProperties = classDialog.dialog('option', role + 'AjaxProperties'), // reverse current order after click orderAscending = !ajaxProperties.data.orderAscending; @@ -2064,21 +2033,14 @@ ajaxProperties.data.orderAscending = orderAscending; // refresh the list - showLearnerGroupDialog(); + showClassDialog(role); } -function selectAllInDialogList(listId) { - var targetState = $('#' + listId + 'SelectAll').is(':checked') ? 'checked' : null; - $('#' + listId + 'List input').each(function(){ - if (!$(this).is(':disabled')) { - $(this).prop('checked', targetState); - } - }); -} - - -function colorDialogList(listId) { - $('#' + listId + 'List div.dialogListItem').each(function(userIndex, userDiv){ +/** + * Colours a list of users + */ +function colorDialogList(parent) { + $('#' + parent + ' .dialogList div.dialogListItem').each(function(userIndex, userDiv){ // every odd learner has different background $(userDiv).css('background-color', userIndex % 2 ? '#dfeffc' : 'inherit'); }); @@ -2099,8 +2061,55 @@ showLearnerGroupDialog(); } +/** +* Change page in the Edit Class dialog. +*/ +function shiftClassList(role, shift) { + var classDialog = $('#classDialog'), + ajaxProperties = classDialog.dialog('option', role + 'AjaxProperties'), + pageNumber = ajaxProperties.data.pageNumber + shift; + if (pageNumber < 0) { + pageNumber = 1; + } + ajaxProperties.data.pageNumber = pageNumber; + // refresh the dialog with new parameters + showClassDialog(role); +} + /** + * Hides/shows paging controls + */ +function togglePagingCells(parent, pageNumber, maxPageNumber) { + if (pageNumber + 10 <= maxPageNumber) { + $('td.pagePlus10Cell', parent).css('visibility', 'visible'); + } else { + $('td.pagePlus10Cell', parent).css('visibility', 'hidden'); + } + if (pageNumber - 10 < 1) { + $('td.pageMinus10Cell', parent).css('visibility', 'hidden'); + } else { + $('td.pageMinus10Cell', parent).css('visibility', 'visible'); + } + if (pageNumber + 1 <= maxPageNumber) { + $('td.pagePlus1Cell', parent).css('visibility', 'visible'); + } else { + $('td.pagePlus1Cell', parent).css('visibility', 'hidden'); + } + if (pageNumber - 1 < 1) { + $('td.pageMinus1Cell', parent).css('visibility', 'hidden'); + } else { + $('td.pageMinus1Cell', parent).css('visibility', 'visible'); + } + if (maxPageNumber < 2) { + $('td.pageCell', parent).css('visibility', 'hidden'); + } else { + $('td.pageCell', parent).css('visibility', 'visible').text(pageNumber + ' / ' + maxPageNumber); + } +} + + +/** * Makes a XML element with given attributes. * jQuery does not work well with SVG in Chrome, so all this manipulation need to be done manually. */ Index: lams_monitoring/web/monitor.jsp =================================================================== diff -u -r2f67a20e73128f03e7b4221ca09426c14bef2abf -r41bb651a1488681fd9ca663ead283b47defdc408 --- lams_monitoring/web/monitor.jsp (.../monitor.jsp) (revision 2f67a20e73128f03e7b4221ca09426c14bef2abf) +++ lams_monitoring/web/monitor.jsp (.../monitor.jsp) (revision 41bb651a1488681fd9ca663ead283b47defdc408) @@ -510,78 +510,151 @@
- - - - - - - + - +
+ + onClick="javascript:sortLearnerGroupList()">
- -
+ + + + + + + + + + + + + + + + + + + + +
- +
+ + + + + +
+
+
+ + + + - + + + + + + + - - - +
-
- - +  
+ - - +
+ +