Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -radd7948dbdf9451fb5bb7839e22d2f22ca8b54f1 -refd67298c7f0ea03a8fc9d670329812589db742a --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision add7948dbdf9451fb5bb7839e22d2f22ca8b54f1) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision efd67298c7f0ea03a8fc9d670329812589db742a) @@ -519,7 +519,10 @@ authoring.fla.properties.dialog.title =Properties authoring.fla.group.naming.dialog.title =Group Naming authoring.fla.groups.to.branches.match.dialog_title =Match Groups to Branches +authoring.fla.course.groups.to.branches.match.dialog.title =Match Course Groups to Branching Groups authoring.fla.branch.mapping.groups.header =Groups +authoring.fla.branch.mapping.course.groups.header =Course groups +authoring.fla.branch.mapping.branching.groups.header =Branching groups authoring.fla.branch.mapping.group.header =Group authoring.fla.conditions.dialog.title =Select Output Conditions for Input authoring.fla.branch.mapping.conditions.header =Conditions Index: lams_central/src/java/org/lamsfoundation/lams/web/OrganisationGroupAction.java =================================================================== diff -u -rbda1ae3773b097fded724ec9010fb2a271b76d0c -refd67298c7f0ea03a8fc9d670329812589db742a --- lams_central/src/java/org/lamsfoundation/lams/web/OrganisationGroupAction.java (.../OrganisationGroupAction.java) (revision bda1ae3773b097fded724ec9010fb2a271b76d0c) +++ lams_central/src/java/org/lamsfoundation/lams/web/OrganisationGroupAction.java (.../OrganisationGroupAction.java) (revision efd67298c7f0ea03a8fc9d670329812589db742a) @@ -20,7 +20,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.web; import java.io.IOException; @@ -33,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; @@ -76,12 +76,6 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; -/** - * - * - * - * - */ public class OrganisationGroupAction extends DispatchAction { private static Logger log = Logger.getLogger(OrganisationGroupAction.class); @@ -98,7 +92,7 @@ /** * Shows course grouping list or redirects to groups if a grouping was already chosen. - * + * * @throws Exception */ @SuppressWarnings("unchecked") @@ -136,41 +130,39 @@ // if this is a chosen group and lesson is created using integrations - show groups received from LMS instead of actual LAMS ones if (getIntegrationService().isIntegratedServerGroupFetchingAvailable(lessonId)) { - + if (lessonId == null) { //it's when a learner clicks back button on groups page Activity activity = getLearnerService().getActivity(activityID); lessonId = getLearnerService().getLessonByActivity(activity).getLessonId(); request.setAttribute("lessonID", lessonId); } - + List extGroups = getIntegrationService().getExtGroups(lessonId, null); request.setAttribute("extGroups", extGroups); // TODO ? show only with user number >0 return mapping.findForward(OrganisationGroupAction.MAPPING_VIEW_EXT_GROUPS); - } else { + } - boolean isGroupSuperuser = getUserManagementService().isUserInRole(userId, organisationId, Role.GROUP_ADMIN) - || getUserManagementService().isUserInRole(userId, organisationId, Role.GROUP_MANAGER); - request.setAttribute("canEdit", isGroupSuperuser || (activityID != null)); + boolean isGroupSuperuser = getUserManagementService().isUserInRole(userId, organisationId, Role.GROUP_ADMIN) + || getUserManagementService().isUserInRole(userId, organisationId, Role.GROUP_MANAGER); + request.setAttribute("canEdit", isGroupSuperuser || (activityID != null)); - Set orgGroupingDTOs = new TreeSet(); - List orgGroupings = getUserManagementService() - .findByProperty(OrganisationGrouping.class, "organisationId", organisationId); - for (OrganisationGrouping orgGrouping : orgGroupings) { - orgGroupingDTOs.add(new OrganisationGroupingDTO(orgGrouping)); - } - request.setAttribute("groupings", orgGroupingDTOs); - - return mapping.findForward(OrganisationGroupAction.MAPPING_VIEW_GROUPINGS); + Set orgGroupingDTOs = new TreeSet(); + List orgGroupings = getUserManagementService().findByProperty(OrganisationGrouping.class, + "organisationId", organisationId); + for (OrganisationGrouping orgGrouping : orgGroupings) { + orgGroupingDTOs.add(new OrganisationGroupingDTO(orgGrouping)); } + request.setAttribute("groupings", orgGroupingDTOs); + return mapping.findForward(OrganisationGroupAction.MAPPING_VIEW_GROUPINGS); } /** * View groups of the given grouping. - * + * * @throws Exception */ @SuppressWarnings("unchecked") @@ -425,7 +417,7 @@ /** * Deletes course grouping with the given ID. - * + * * @throws Exception */ public ActionForward removeGrouping(ActionMapping mapping, ActionForm form, HttpServletRequest request, @@ -450,6 +442,70 @@ } /** + * Fetches course and branching so they can get matched by user. + */ + @SuppressWarnings("unchecked") + public ActionForward getGroupsForMapping(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, JSONException { + Long orgGroupingId = WebUtil.readLongParam(request, "groupingId"); + Long activityID = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); + + OrganisationGrouping orgGrouping = (OrganisationGrouping) getUserManagementService() + .findById(OrganisationGrouping.class, orgGroupingId); + JSONArray groupsJSON = new JSONArray(); + SortedSet orgGroups = new TreeSet(orgGrouping.getGroups()); + for (OrganisationGroup group : orgGroups) { + JSONObject groupJSON = new JSONObject(); + groupJSON.put("id", group.getGroupId()); + groupJSON.put("name", group.getName()); + groupsJSON.put(groupJSON); + } + + GroupingActivity branchingGrouping = (GroupingActivity) getUserManagementService().findById(Activity.class, + activityID); + JSONArray branchesJSON = new JSONArray(); + Grouping grouping = branchingGrouping.getCreateGrouping(); + SortedSet groups = new TreeSet(grouping.getGroups()); + for (Group group : groups) { + JSONObject groupJSON = new JSONObject(); + groupJSON.put("id", group.getGroupId()); + groupJSON.put("name", group.getGroupName()); + branchesJSON.put(groupJSON); + } + + JSONObject responseJSON = new JSONObject(); + responseJSON.put("branches", branchesJSON); + responseJSON.put("groups", groupsJSON); + + response.setContentType("application/json;charset=utf-8"); + response.getWriter().write(responseJSON.toString()); + return null; + } + + /** + * Stores course groups to branching groups mapping. + */ + public ActionForward saveGroupMappings(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, JSONException { + JSONArray groupMapping = new JSONArray(request.getParameter("mapping")); + for (int index = 0; index < groupMapping.length(); index++) { + JSONObject entry = groupMapping.getJSONObject(index); + Long orgGroupID = entry.getLong("groupID"); + Long branchingGroupID = entry.getLong("branchID"); + OrganisationGroup orgGroup = (OrganisationGroup) getUserManagementService() + .findById(OrganisationGroup.class, orgGroupID); + Group branchingGroup = (Group) getUserManagementService().findById(Group.class, branchingGroupID); + // put all users from course group to mapped branching group + branchingGroup.getUsers().addAll(orgGroup.getUsers()); + getUserManagementService().save(branchingGroup); + } + response.setContentType("text/plain;charset=utf-8"); + // Javascript waits for this response + response.getWriter().write("OK"); + return null; + } + + /** * Build JSON objects based on existing lesson-level groups. */ private JSONArray getLessonGroupsDetails(Set groups, Collection learners) throws JSONException { @@ -496,7 +552,7 @@ return comparator.compare(grp1Name, grp2Name); } }; - + // serialize database group objects into JSON JSONArray groupsJSON = new JSONArray(); if (groups != null) { @@ -542,16 +598,15 @@ request.setAttribute(GroupingAJAXAction.PARAM_USED_FOR_BRANCHING, isUsedForBranching); // check if it is immutable (for branching) or default groups are allowed - return !groups.isEmpty() && (isUsedForBranching || allowDefault || !isDefaultChosenGrouping(grouping)) - ? grouping : null; + return !groups.isEmpty() && (allowDefault || !isDefaultChosenGrouping(grouping)) ? grouping : null; } } return null; } /** - * Check if the give groups are default for chosen grouping. There is actually no good way to detect this, but even + * Check if the given groups are default for chosen grouping. There is actually no good way to detect this, but even * if a custom grouping is mistaken for the default one, it should bring little harm. */ @SuppressWarnings("unchecked") @@ -583,13 +638,12 @@ } return OrganisationGroupAction.userManagementService; } - + private ICoreLearnerService getLearnerService() { if (OrganisationGroupAction.learnerService == null) { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(getServlet().getServletContext()); - OrganisationGroupAction.learnerService = (ICoreLearnerService) ctx - .getBean("learnerService"); + OrganisationGroupAction.learnerService = (ICoreLearnerService) ctx.getBean("learnerService"); } return OrganisationGroupAction.learnerService; } Index: lams_central/web/includes/javascript/orgGrouping.js =================================================================== diff -u -r6ad3d1341b3dc1f066c69c7129a8c1dff15980a5 -refd67298c7f0ea03a8fc9d670329812589db742a --- lams_central/web/includes/javascript/orgGrouping.js (.../orgGrouping.js) (revision 6ad3d1341b3dc1f066c69c7129a8c1dff15980a5) +++ lams_central/web/includes/javascript/orgGrouping.js (.../orgGrouping.js) (revision efd67298c7f0ea03a8fc9d670329812589db742a) @@ -1,4 +1,6 @@ -$(document).ready(function() { +var gtbDialog = null; + +$(document).ready(function() { $(".ui-button").button(); }); @@ -9,7 +11,7 @@ } } -function showGroups(groupingId) { +function viewGroups(groupingId, force) { var url = LAMS_URL + 'OrganisationGroup.do?method=viewGroups&organisationID=' + organisationId; if (lessonId) { @@ -22,7 +24,7 @@ if (lessonMode) { var executeShow = true; - if (groupingId) { + if (groupingId && !force) { // make sure user want to use this grouping var groupingName = $('#grouping-' + groupingId + ' .groupingName').text().trim(); executeShow = confirm(LABELS.USE_GROUPING_CONFIRM_LABEL.replace('[0]', groupingName)); @@ -35,4 +37,196 @@ // load to dialog window.parent.showOrgGroupDialogContents(null, 880, 500, url); } +} +/** + * Opens dialog for matching course groups to groups assigned to branches in a branching activity. + */ +function openGroupMappingDialog(groupingId) { + /* dialog and labels are called "branching" because + * 1) it was taken from Authoring dialog for groups-to-branches mapping + * 2) two types of groups: course and branching could easily get mixed + */ + if (!gtbDialog) { + // create the dialog + gtbDialog = $('#groupMappingDialog') + .dialog({ + 'autoOpen' : false, + 'modal' : true, + 'show' : 'fold', + 'hide' : 'fold', + 'width' : 650, + 'height' : 400, + 'title' : LABELS.COURSE_GROUPS_TO_BRANCHES_MATCH_DIALOG_TITLE, + 'buttons' : [ + { + 'text' : LABELS.OK_BUTTON, + 'click' : function() { + var dialog = $(this), + groupsToBranches = []; + + // fill JSON with group pairs + $('.branchMappingBoundItemCell div, .branchMappingFreeItemCell div', dialog) + .each(function(){ + var groupID = $(this).attr('id'), + boundItem = $(this).data('boundItem'), + branchID = boundItem ? boundItem.attr('id') : null; + + // add the mapping + if (branchID) { + groupsToBranches.push({ + 'groupID' : groupID, + 'branchID' : branchID + }); + } + }); + + // save the mapping + $.ajax({ + url : LAMS_URL + 'OrganisationGroup.do', + data : { + 'method' : 'saveGroupMappings', + 'mapping' : JSON.stringify(groupsToBranches) + }, + success : function(response) { + // LAMS can reply 200 even if there is an error, so we need OK response + if (response == 'OK') { + // go straight to branching groups for final check + viewGroups(groupingId, true); + } + } + }); + } + } + ], + 'open' : function(){ + var dialog = $(this), + groupsCell = $('.branchMappingFreeItemCell', dialog), + branchesCell = $('.branchMappingFreeBranchCell', dialog), + groupCell = $('.branchMappingBoundItemCell', dialog), + branchCell = $('.branchMappingBoundBranchCell', dialog); + + // clear out previous entries + $('.branchMappingListCell', dialog).empty(); + + // fetch course and branching groups + $.ajax({ + url : LAMS_URL + 'OrganisationGroup.do', + data : { + 'method' : 'getGroupsForMapping', + 'groupingId' : groupingId, + 'activityID' : groupingActivityId + }, + dataType : 'json', + success : function(response) { + // fill table with course and branching groups + $.each(response.groups, function(){ + var group = this, + groupElem = $('
').click(selectGroupMappingListItem) + .text(group.name).attr('id', group.id); + + $.each(response.branches, function() { + // check if a branching group alread exists with the same name as a course group + if (this.name == group.name) { + var branchElem = $('
').click(selectGroupMappingListItem) + .appendTo(branchCell) + .text(this.name) + .attr('id', this.id) + .data('boundItem', groupElem); + groupElem.appendTo(groupCell).data('boundItem', branchElem); + groupElem = null; + return false; + } + }); + + if (groupElem) { + // no existing mapping was found, make the group available for mapping + groupElem.appendTo(groupsCell); + } + }); + // fill in branch groups + $.each(response.branches, function(){ + $('
').click(selectGroupMappingListItem).appendTo(branchesCell) + .text(this.name).attr('id', this.id); + }); + } + }); + } + }); + + // initialise buttons and labels + $('.branchMappingAddButton', gtbDialog).button({ + 'icons' : { + 'primary' : 'ui-icon-seek-next' + }, + 'text' : false + }).click(function(){ + addGroupMapping(); + }); + $('.branchMappingRemoveButton', gtbDialog).button({ + 'icons' : { + 'primary' : 'ui-icon-seek-prev' + }, + 'text' : false + }).click(function(){ + removeGroupMapping(); + }); + } + + gtbDialog.dialog('open'); +}; + +/** + * Make a pair out of selected groups. + */ +function addGroupMapping(){ + var dialog = gtbDialog, + selectedItem = $('.branchMappingFreeItemCell .selected', dialog), + selectedBranch = $('.branchMappingFreeBranchCell .selected', dialog); + + if (selectedItem.length != 1 || selectedBranch.length != 1) { + return; + } + + // original branch stays in its list + selectedBranch = selectedBranch.clone().click(selectGroupMappingListItem); + // add info about the pair for later reference + selectedItem.data('boundItem', selectedBranch); + selectedBranch.data('boundItem', selectedItem); + var itemCell = $('.branchMappingBoundItemCell', dialog), + branchCell = $('.branchMappingBoundBranchCell', dialog); + // clear existing selection + $('.selected', itemCell).removeClass('selected'); + $('.selected', branchCell).removeClass('selected'); + itemCell.append(selectedItem); + branchCell.append(selectedBranch); +} + +function removeGroupMapping() { + var dialog = gtbDialog, + selectedItem = $('.branchMappingBoundItemCell .selected', dialog), + selectedBranch = $('.branchMappingBoundBranchCell .selected', dialog); + + if (selectedItem.length != 1 || selectedBranch.length != 1) { + return; + } + + selectedItem.removeData('boundItem'); + selectedBranch.remove(); + $('.branchMappingFreeItemCell', dialog).append(selectedItem); +} + +/** + * Highlight clicked group + */ +function selectGroupMappingListItem(){ + var item = $(this), + boundItem = item.data('boundItem'); + + item.siblings().removeClass('selected'); + item.addClass('selected'); + + if (boundItem) { + boundItem.siblings().removeClass('selected'); + boundItem.addClass('selected'); + } } \ No newline at end of file Index: lams_central/web/orgGrouping.jsp =================================================================== diff -u -r2ef18e4c87e2e7929950dbeb990c6715ef16c0c2 -refd67298c7f0ea03a8fc9d670329812589db742a --- lams_central/web/orgGrouping.jsp (.../orgGrouping.jsp) (revision 2ef18e4c87e2e7929950dbeb990c6715ef16c0c2) +++ lams_central/web/orgGrouping.jsp (.../orgGrouping.jsp) (revision efd67298c7f0ea03a8fc9d670329812589db742a) @@ -9,8 +9,50 @@ + + @@ -29,7 +71,11 @@ REMOVE_GROUPING_CONFIRM_LABEL : decoderDiv.html('').text(), - USE_GROUPING_CONFIRM_LABEL : decoderDiv.html('').text() + USE_GROUPING_CONFIRM_LABEL : decoderDiv.html('').text(), + + COURSE_GROUPS_TO_BRANCHES_MATCH_DIALOG_TITLE : '', + + OK_BUTTON : '' }; @@ -50,17 +96,12 @@ <%-- In lesson mode do not show groupings with zero groups --%>
- - - - - (${grouping.groupCount}) - + + + (${grouping.groupCount}) + title="" onClick="javascript:removeGrouping(${grouping.groupingId})" />
@@ -71,5 +112,44 @@
+ + + + \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/Group.java =================================================================== diff -u -r51fb2a37254f24bb2a805d4ffd54482c779f43fa -refd67298c7f0ea03a8fc9d670329812589db742a --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/Group.java (.../Group.java) (revision 51fb2a37254f24bb2a805d4ffd54482c779f43fa) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/Group.java (.../Group.java) (revision efd67298c7f0ea03a8fc9d670329812589db742a) @@ -35,7 +35,7 @@ import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.util.Nullable; -public class Group implements Serializable, Nullable, Comparable { +public class Group implements Serializable, Nullable, Comparable { public final static int STAFF_GROUP_ORDER_ID = 1; public final static String NAME_OF_STAFF_GROUP = "Staff Group"; @@ -263,11 +263,10 @@ * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override - public int compareTo(Object o) { - Group castOther = (Group) o; - return new CompareToBuilder().append(this.getOrderId(), castOther.getOrderId()) - .append(this.getGroupId(), castOther.getGroupId()).append(this.getGroupName(), castOther.getGroupName()) - .append(this.getGroupUIID(), castOther.getGroupUIID()).toComparison(); + public int compareTo(Group group) { + return new CompareToBuilder().append(this.getOrderId(), group.getOrderId()) + .append(this.getGroupId(), group.getGroupId()).append(this.getGroupName(), group.getGroupName()) + .append(this.getGroupUIID(), group.getGroupUIID()).toComparison(); } // --------------------------------------------------------------------- Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/OrganisationGroup.java =================================================================== diff -u -r51fb2a37254f24bb2a805d4ffd54482c779f43fa -refd67298c7f0ea03a8fc9d670329812589db742a --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/OrganisationGroup.java (.../OrganisationGroup.java) (revision 51fb2a37254f24bb2a805d4ffd54482c779f43fa) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/OrganisationGroup.java (.../OrganisationGroup.java) (revision efd67298c7f0ea03a8fc9d670329812589db742a) @@ -26,14 +26,13 @@ import java.io.Serializable; import java.util.Set; +import org.apache.commons.lang.builder.CompareToBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; /** * This is a course-level group of learners. - * - * */ -public class OrganisationGroup implements Serializable { +public class OrganisationGroup implements Serializable, Comparable { /** identifier field */ private Long groupId; @@ -127,4 +126,10 @@ } return true; } + + @Override + public int compareTo(OrganisationGroup group) { + return new CompareToBuilder().append(this.getGroupId(), group.getGroupId()) + .append(this.getName(), group.getName()).toComparison(); + } } \ No newline at end of file