Index: tool/src/java/org/sakaiproject/signup/tool/jsf/organizer/OrganizerSignupMBean.java =================================================================== --- tool/src/java/org/sakaiproject/signup/tool/jsf/organizer/OrganizerSignupMBean.java (revision 14886) +++ tool/src/java/org/sakaiproject/signup/tool/jsf/organizer/OrganizerSignupMBean.java (working copy) @@ -28,8 +28,12 @@ import javax.faces.component.UIData; import javax.faces.component.UIInput; +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; import javax.faces.model.SelectItem; import javax.faces.model.SelectItemGroup; +import javax.servlet.ServletContext; +import javax.faces.event.ActionEvent; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -124,6 +128,7 @@ private boolean collapsedMeetingInfo; private boolean eidInputMode = false; + public String timeslottoGroup; /** * This will initialize all the wrapper objects such as @@ -1257,19 +1262,48 @@ this.collapsedMeetingInfo = collapsedMeetingInfo; } + /** + * This is to retrieve attr from UI Commandbutton + * + * @param timeslottoGroup + * a String value + */ + public void attrListener(ActionEvent event){ + + timeslottoGroup = (String) Utilities.getActionAttribute(event, "timeslottoGroup"); + + } /** + * It's a getter method for UI + * denotes the direction of the synchronize process + * @return a String value timeslottoGroup + */ + public String gettimeslottoGroup() { + return timeslottoGroup; + } + + /** + * This is a setter + * @return a String value + */ + public void setNickname(String timeslottoGroup) { + this.timeslottoGroup = timeslottoGroup; + } + + /** * Synchronise the users in a timeslot with the users in a group. - *

Ensures that both lists have the same users in each, but does NOT remove any users from the group. + * VT customized to allow the user choose the synchronize direction * @return url to the same page which will trigger a reload */ public String synchroniseGroupMembership() { + + TimeslotWrapper timeslotWrapper = (TimeslotWrapper) timeslotWrapperTable.getRowData(); - TimeslotWrapper timeslotWrapper = (TimeslotWrapper) timeslotWrapperTable.getRowData(); - //get groupId for timeslot String groupId = timeslotWrapper.getGroupId(); + SignupMeeting meeting = null; if(StringUtils.isBlank(groupId)){ //TODO. @@ -1282,23 +1316,61 @@ } else { List attendeeUserIds = convertAttendeeWrappersToUuids(timeslotWrapper.getAttendeeWrappers()); - //add timeslot attendees to the group and save - if(!sakaiFacade.addUsersToGroup(attendeeUserIds, currentSiteId(), groupId)) { - Utilities.addErrorMessage(Utilities.rb.getString("error.group_sync_failed")); - return ORGANIZER_MEETING_PAGE_URL; - } + //process to synchronize the time slot attendees to group - //add group members to the timeslot and save - List groupMembers = sakaiFacade.getGroupMembers(currentSiteId(), groupId); + if(timeslottoGroup != null && !timeslottoGroup.trim().isEmpty() && !sakaiFacade.addUsersToGroup(attendeeUserIds, currentSiteId(), groupId, timeslottoGroup)) { + Utilities.addErrorMessage(Utilities.rb.getString("error.group_sync_failed")); + return ORGANIZER_MEETING_PAGE_URL; + } - //remove all of the existing attendees from this list to remove duplicates - groupMembers.removeAll(attendeeUserIds); - + //retrieve all members in group + List groupMembers = sakaiFacade.getGroupMembers(currentSiteId(), groupId); + + //process to synchronize from site group members to time slot + if (timeslottoGroup == null || timeslottoGroup.isEmpty()){ + + //1. first to keep the common members of timeslot and group + + List commonmem = new ArrayList(attendeeUserIds); + commonmem.retainAll(groupMembers); + + //2. only add the group members not existed in timeslot + groupMembers.removeAll(attendeeUserIds); + + //3. remove the time slot attendees that existed only in timeslot + try { + for (String mem: attendeeUserIds){ + if(!commonmem.contains(mem)){ + CancelAttendee remove = new CancelAttendee(signupMeetingService, currentUserId(), currentSiteId(), true); + SignupAttendee removedAttendee = new SignupAttendee(mem, currentSiteId()); + meeting = remove.cancelSignup(getMeetingWrapper().getMeeting(), timeslotWrapper.getTimeSlot(),removedAttendee); + if (sendEmail) { + try { + signupMeetingService.sendEmailToParticipantsByOrganizerAction(remove.getSignupEventTrackingInfo()); + } catch (Exception e) { + logger.error(Utilities.rb.getString("email.exception") + " - " + e.getMessage(), e); + Utilities.addErrorMessage(Utilities.rb.getString("email.exception")); + } + } + } + } + }catch (SignupUserActionException ue) { + Utilities.addErrorMessage(ue.getMessage()); + } catch (Exception e) { + logger.error(Utilities.rb.getString("error.occurred_try_again") + " - " + e.getMessage()); + Utilities.addErrorMessage(Utilities.rb.getString("error.occurred_try_again")); + } + } else{ + //remove all of the existing attendees from this list to remove duplicates + groupMembers.removeAll(attendeeUserIds); + } + //add members and go to return page return addAttendeesToTimeslot(currentSiteId(),timeslotWrapper, groupMembers); } } + /** * Helper to add users to a timeslot and get the return URL * @param userId Index: tool/src/java/org/sakaiproject/signup/tool/util/Utilities.java =================================================================== --- tool/src/java/org/sakaiproject/signup/tool/util/Utilities.java (revision 14886) +++ tool/src/java/org/sakaiproject/signup/tool/util/Utilities.java (working copy) @@ -47,6 +47,7 @@ import org.sakaiproject.signup.tool.jsf.SignupMeetingsBean; import org.sakaiproject.signup.tool.jsf.organizer.UserDefineTimeslotBean; import org.sakaiproject.util.ResourceLoader; +import javax.faces.event.ActionEvent; /** *

@@ -141,6 +142,19 @@ } /** + * This method will retrieve the value from UI CommandButton + * parameter/attribute name + * + * @param attrName + * a string value + * @return a string value + */ + public static String getActionAttribute(ActionEvent event, String name) { + return (String) event.getComponent().getAttributes().get(name); + } + + + /** * Reset the meetings in the SignupMeetingsBean to null so we will fetch all * the up-to-date meeting data again */ Index: tool/src/bundle/messages.properties =================================================================== --- tool/src/bundle/messages.properties (revision 14886) +++ tool/src/bundle/messages.properties (working copy) @@ -1,5 +1,4 @@ -# -events_organizer_instruction=Click 'Add' to create a new meeting, or click a meeting title to modify or copy it. +=Click 'Add' to create a new meeting, or click a meeting title to modify or copy it. events_attendee_instruction=To sign up for a meeting, click the meeting title. add_new_event = Add @@ -189,6 +188,8 @@ cancel_button=Cancel save_button=Save delete_attandee_confirmation=Are you sure you want to remove this participant from the time slot? +synchronisetogroup_confirmation=Are you sure you want to synchronize the participants from the time slot to site group? +synchronisefromgroup_confirmation=Are you sure you want to synchronize the site group membership to the time slot? event_add_attendee= Add Participant event_restore_timeslot_label= Restore event_cancel_timeslot_label= Cancel - delete the timeslot @@ -230,6 +231,8 @@ event_tool_tips_hide_details=Click to hide details. event_tool_tips_collapse_recur_meeting=Collapse recurring Meetings. event_tool_tips_expand_recur_meeting=Expand recurring Meetings. +event_tool_tips_syncTogroup=Click to synchronise the participants to group membership +event_tool_tips_syncFromgroup=Click to synchronise the site group membership to time slot exception.no.such.user=No user was found for user ID:  user.has.no.permission.attend=The user:{0} has no permission to attend this event. @@ -560,7 +563,8 @@ group_description_default = This group ({0}) was automatically created via the Signups tool. Users in timeslots and this group's membership can be synchronised by clicking the 'Synchronise' button for the timeslot in the Signup tool. group_synchronise_heading = Group Membership -group_synchronise_button = Synchronise +group_synchronise_button = SynchroniseToGroup +fromgroup_synchronise_button = SynchroniseFromGroup group_slot_in_group_titlename= slot error.no.change.group.title= Some of the group title have not been synchronized since it's modified via Site Info tool already! @@ -582,4 +586,4 @@ filter_by_category=By category: filter_categories_top=All - \ No newline at end of file + Index: tool/src/webapp/signup/organizer/orgSignupMeeting.jsp =================================================================== --- tool/src/webapp/signup/organizer/orgSignupMeeting.jsp (revision 14886) +++ tool/src/webapp/signup/organizer/orgSignupMeeting.jsp (working copy) @@ -494,7 +494,13 @@ - + + + + + + + Index: impl/src/java/org/sakaiproject/signup/logic/SakaiFacadeImpl.java =================================================================== --- impl/src/java/org/sakaiproject/signup/logic/SakaiFacadeImpl.java (revision 14886) +++ impl/src/java/org/sakaiproject/signup/logic/SakaiFacadeImpl.java (working copy) @@ -30,6 +30,7 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import java.util.HashSet; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -1095,7 +1096,7 @@ /** * {@inheritDoc} */ - public boolean addUsersToGroup(Collection userIds, String siteId, String groupId) { + public boolean addUsersToGroup(Collection userIds, String siteId, String groupId, String timeslottoGroup) { log.debug("addUsersToGroup(userIds=" + Arrays.asList(userIds).toString() + ", siteId=" + siteId + ", groupId=" + groupId); @@ -1114,28 +1115,46 @@ }; enableSecurityAdvisor(securityAdvisor); - Group group = site.getGroup(groupId); + Group group = site.getGroup(groupId); if(group == null) { log.error("No group for id: " + groupId); return false; } + + try { - try { + for(String userId: userIds) { + group = addUserToGroup(userId, group); + } + + //the synchronise is from the time slot to Site group membership + if(timeslottoGroup.equals("toGroup")) { + + List updateusers = getGroupMembers(siteId, groupId); - for(String userId: userIds) { - group = addUserToGroup(userId, group); + //first clone a new group member + Set tmpUsers = new HashSet(); + tmpUsers.addAll(updateusers); + + //retrieve only the difference members from TimeSlot and SiteGroup + tmpUsers.removeAll(userIds); + + //remove the differences from group members + for (String mem: tmpUsers){ + group.removeMember(mem); + } + } - siteService.save(site); + siteService.save(site); - return true; + return true; - } catch (Exception e) { - log.error("addUsersToGroup failed for users: " + Arrays.asList(userIds).toString() + " and group: " + groupId, e); - } finally { - disableSecurityAdvisor(securityAdvisor); - } - + } catch (Exception e) { + log.error("addUsersToGroup failed for users: " + Arrays.asList(userIds).toString() + " and group: " + groupId, e); + } finally { + disableSecurityAdvisor(securityAdvisor); + } return false; } Index: api/src/java/org/sakaiproject/signup/logic/SakaiFacade.java =================================================================== --- api/src/java/org/sakaiproject/signup/logic/SakaiFacade.java (revision 14886) +++ api/src/java/org/sakaiproject/signup/logic/SakaiFacade.java (working copy) @@ -422,7 +422,7 @@ * @param groupId id of the group * @return true if users added, false if not */ - public boolean addUsersToGroup(Collection userIds, String siteId, String groupId); + public boolean addUsersToGroup(Collection userIds, String siteId, String groupId, String timeslottoGroup); /** * Remove the user from the given group in the given site