package org.sakaiproject.site.tool.helper.managegroupsectionrole.impl; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import javax.servlet.http.HttpServletRequest; import lombok.Getter; import lombok.Setter; import org.apache.commons.fileupload.FileItem; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.authz.api.AuthzGroup; import org.sakaiproject.authz.api.AuthzGroupService; import org.sakaiproject.authz.api.GroupNotDefinedException; import org.sakaiproject.authz.api.Member; import org.sakaiproject.authz.api.Role; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.event.cover.EventTrackingService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.util.Participant; import org.sakaiproject.site.util.SiteConstants; import org.sakaiproject.site.util.SiteParticipantHelper; import org.sakaiproject.sitemanage.api.SiteHelper; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.util.RequestFilter; import uk.org.ponder.messageutil.TargettedMessage; import uk.org.ponder.messageutil.TargettedMessageList; import uk.org.ponder.rsf.components.UIBranchContainer; import uk.org.ponder.rsf.components.UIOutput; import au.com.bytecode.opencsv.CSVReader; /** * * @author * */ public class SiteManageGroupSectionRoleHandler { private static final String REQ_ATTR_GROUPFILE = "groupfile"; /** Our log (commons). */ private static Log M_log = LogFactory.getLog(SiteManageGroupSectionRoleHandler.class); private List<Member> groupMembers; private GroupComparator groupComparator = new GroupComparator(); public Site site = null; public SiteService siteService = null; public AuthzGroupService authzGroupService = null; public ToolManager toolManager = null; public SessionManager sessionManager = null; public ServerConfigurationService serverConfigurationService; private List<Group> groups = null; private Set unhideables = null; public String memberList = ""; public boolean update = false; public boolean done = false; public String[] selectedGroupMembers = new String[]{}; public String[] selectedSiteMembers = new String[]{}; // selected rosters for autocreate groups public Map<String, Boolean> selectedRosters = new HashMap<String, Boolean>(); // selected roles for autocreate groups public Map<String, Boolean> selectedRoles = new HashMap<String, Boolean>(); private static final int OPTION_ASSIGN_BY_ROLES = 1; private static final int OPTION_ASSIGN_RANDOM = 2; public int optionAssign = OPTION_ASSIGN_BY_ROLES; public boolean groupSplit = true; public String numToSplitGroup = ""; public String numToSplitUser = ""; public String groupTitleGroup = ""; public String groupTitleUser = ""; private String NULL_STRING = ""; private final String TOOL_CFG_FUNCTIONS = "functions.require"; private final String TOOL_CFG_MULTI = "allowMultiple"; private final String SITE_UPD = "site.upd"; private final String HELPER_ID = "sakai.tool.helper.id"; private final String UNHIDEABLES_CFG = "poh.unhideables"; private final String GROUP_ADD = "group.add"; private final String GROUP_DELETE = "group.delete"; private final String GROUP_RENAME = "group.rename"; private final String GROUP_SHOW = "group.show"; private final String GROUP_HIDE = "group.hide"; private final String SITE_REORDER = "group.reorder"; private final String SITE_RESET = "group.reset"; public String joinableSetName = ""; public String joinableSetNameOrig = ""; public String joinableSetNumOfGroups = ""; public String joinableSetNumOfMembers = ""; public boolean allowViewMembership = false; // Tool session attribute name used to schedule a whole page refresh. public static final String ATTR_TOP_REFRESH = "sakai.vppa.top.refresh"; // SAK-23016 - added CSV types from http://filext.com/file-extension/CSV private static final String CSV_FILE_EXTENSION="csv"; private static final String[] CSV_MIME_TYPES = { "application/csv", "application/excel", "application/vnd.ms-excel", "application/vnd.msexcel", "text/anytext", "text/comma-separated-values", "text/csv" }; public TargettedMessageList messages; public void setMessages(TargettedMessageList messages) { this.messages = messages; } private void resetTargettedMessageList() { this.messages = new TargettedMessageList(); } private org.sakaiproject.authz.api.GroupProvider groupProvider = (org.sakaiproject.authz.api.GroupProvider) ComponentManager.get(org.sakaiproject.authz.api.GroupProvider.class); // the group title private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } // group title private String title; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } // group description private String description; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } // for those to be deleted groups public String[] deleteGroupIds; /** * reset the variables */ public void resetParams() { id = ""; title = ""; description =""; deleteGroupIds=new String[]{}; selectedGroupMembers = new String[]{}; selectedSiteMembers = new String[]{}; selectedRosters = new HashMap<String, Boolean>(); selectedRoles = new HashMap<String, Boolean>(); optionAssign=OPTION_ASSIGN_BY_ROLES; groupSplit = true; numToSplitUser = ""; numToSplitGroup = ""; groupTitleUser = ""; groupTitleGroup = ""; importedGroups = null; joinableSetName = ""; joinableSetNameOrig = ""; joinableSetNumOfGroups = ""; joinableSetNumOfMembers = ""; allowViewMembership = false; } /** * Gets the groups for the current site * @return Map of groups (id, group) */ public List<Group> getGroups() { if (site == null) { init(); } if (update) { groups = new Vector<Group>(); if (site != null) { // only show groups created by WSetup tool itself Collection allGroups = (Collection) site.getGroups(); for (Iterator gIterator = allGroups.iterator(); gIterator.hasNext();) { Group gNext = (Group) gIterator.next(); String gProp = gNext.getProperties().getProperty( gNext.GROUP_PROP_WSETUP_CREATED); if (gProp != null && gProp.equals(Boolean.TRUE.toString())) { groups.add(gNext); } } } } Collections.sort(groups, groupComparator); return groups; } /** * Gets the rosters for the current site excluding the group * @return List of roster ids */ public List<String> getSiteRosters(Group group) { if (site == null) { init(); } List<String> providerIds = null; if (update) { providerIds = new Vector<String>(); if (site != null) { // get all provider ids Set pIds = authzGroupService.getProviderIds(siteService.siteReference(site.getId())); providerIds.addAll(pIds); if (group != null) { Set groupPIds = authzGroupService.getProviderIds(siteService.siteGroupReference(site.getId(), group.getId())); providerIds.removeAll(groupPIds); } } } return providerIds; } /** * Gets the rosters for the group * @return List of roster ids */ public List<String> getGroupRosters(Group g) { List<String> providerIds = null; if (update) { providerIds = new Vector<String>(); if (g != null) { // get all provider ids Set pIds = authzGroupService.getProviderIds(siteService.siteGroupReference(site.getId(), g.getId())); providerIds.addAll(pIds); } } return providerIds; } /** * Gets the roles for the current site excluding the group * @return Map of groups (id, group) */ public List<Role> getSiteRoles(Group group) { if (site == null) { init(); } List<Role> roles = null; if (update) { roles = new Vector<Role>(); if (site != null) { // get the authz group String siteReference = siteService.siteReference(site.getId()); try { AuthzGroup siteGroup = authzGroupService.getAuthzGroup(siteReference); roles.addAll(siteGroup.getRoles()); } catch (GroupNotDefinedException e) { M_log.debug(this + ".getRoles: no authzgroup found for " + siteReference); } if (group != null) { String roleProviderId = group.getProperties().getProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID); if (roleProviderId != null) { if (groupProvider != null) { String[] groupProvidedRoles = groupProvider.unpackId(roleProviderId); for(int i=0; i<groupProvidedRoles.length;i++) { roles.remove(group.getRole(groupProvidedRoles[i])); } } } } } } return roles; } /** * Gets the role ids for the current site * @return Map of groups (id, group) */ public List<String> getSiteRoleIds() { List<String> rv = new Vector<String>(); List<Role> roles = getSiteRoles(null); if (roles != null) { for(Role r:roles) { rv.add(r.getId()); } } return rv; } public boolean isUserFromProvider(String userEId, String userId, Group g, List<String> rosterIds, List<String> roleIds) { boolean rv = false; // check roster first if (rosterIds != null) { for (int i = 0; !rv && i < rosterIds.size(); i++) { if (groupProvider != null) { String providerId = rosterIds.get(i); Map userRole = groupProvider.getUserRolesForGroup(providerId); if (userRole.containsKey(userEId)) { rv = true; } } } } // check role next if (!rv && roleIds != null) { for (int i = 0; !rv && i < roleIds.size(); i++) { String roleId = roleIds.get(i); if (g.getUserRole(userId).getId().equals(roleId)) { rv = true; } } } return rv; } /** * Gets the roles for the group * @return Map of groups (id, group) */ public List<String> getGroupProviderRoles(Group g) { List<String> rv = null; if (update) { rv = new Vector<String>(); if (g != null) { // get the authz group String roleProviderId = g.getProperties().getProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID); if (roleProviderId != null) { if (groupProvider != null) { String[] roleStrings = groupProvider.unpackId(roleProviderId); for(String roleString:roleStrings) { rv.add(roleString); } } } } } return rv; } /** * Initialization method, just gets the current site in preperation for other calls * */ public void init() { if (site == null) { String siteId = null; try { siteId = sessionManager.getCurrentToolSession() .getAttribute(HELPER_ID + ".siteId").toString(); } catch (java.lang.NullPointerException npe) { // Site ID wasn't set in the helper call!! } if (siteId == null) { siteId = toolManager.getCurrentPlacement().getContext(); } try { site = siteService.getSite(siteId); // allow update site or group membership update = siteService.allowUpdateSite(site.getId()) || siteService.allowUpdateGroupMembership(site.getId()); } catch (IdUnusedException e) { // The siteId we were given was bogus e.printStackTrace(); } } title = ""; String conf = serverConfigurationService.getString(UNHIDEABLES_CFG); if (conf != null) { unhideables = new HashSet(); String[] toolIds = conf.split(","); for (int i = 0; i < toolIds.length; i++) { unhideables.add(toolIds[i].trim()); } } if (groupMembers == null) { groupMembers = new Vector<Member>(); } } /** * Wrapper around siteService to save a site * @param site * @throws IdUnusedException * @throws PermissionException */ public void saveSite(Site site) throws IdUnusedException, PermissionException { siteService.save(site); } public List<Participant> getSiteParticipant(Group group) { List<Participant> rv = new Vector<Participant>(); if (site != null) { String siteId = site.getId(); String realmId = siteService.siteReference(siteId); List<String> providerCourseList = SiteParticipantHelper.getProviderCourseList(siteId); Collection<Participant> rvCopy = SiteParticipantHelper.prepareParticipants(siteId, providerCourseList); // check with group attendents if (group != null) { // need to remove those inside group already for(Participant p:rvCopy) { if (p.getUniqname() != null && group.getMember(p.getUniqname()) == null) { rv.add(p); } } } else { // if the group is null, add all site members rv.addAll(rvCopy); } } return rv; } public List<Member> getGroupParticipant() { return groupMembers; } /** * Allows the Cancel button to return control to the tool calling this helper * */ public String processCancel() { // reset the warning messages resetTargettedMessageList(); ToolSession session = sessionManager.getCurrentToolSession(); session.setAttribute(ATTR_TOP_REFRESH, Boolean.TRUE); return "done"; } /** * Cancel out of the current action and go back to main view * */ public String processBack() { // reset the warning messages resetTargettedMessageList(); return "cancel"; } public String reset() { try { siteService.save(site); EventTrackingService.post( EventTrackingService.newEvent(SITE_RESET, "/site/" + site.getId(), false)); } catch (IdUnusedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (PermissionException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; } /** * Adds a new group to the current site * @param toolId * @param title * @return the newly added Group */ public String processAddGroup () { // reset the warning message resetTargettedMessageList(); Group group = null; // those added user into group List<String> addedGroupMember = new Vector<String>(); // those deleted user from group List<String> removedGroupMember = new Vector<String>(); id = StringUtils.trimToNull(id); String siteReference = siteService.siteReference(site.getId()); title = StringUtils.trimToNull(title); if (title == null) { messages.addMessage(new TargettedMessage("editgroup.titlemissing",new Object[]{}, TargettedMessage.SEVERITY_ERROR)); return null; } else if (title != null && title.length() > SiteConstants.SITE_GROUP_TITLE_LIMIT) { messages.addMessage(new TargettedMessage("site_group_title_length_limit",new Object[] { String.valueOf(SiteConstants.SITE_GROUP_TITLE_LIMIT) }, TargettedMessage.SEVERITY_ERROR)); return null; } else if (id == null) { Collection siteGroups = site.getGroups(); if (siteGroups != null && siteGroups.size() > 0) { // when adding a group, check whether the group title has // been used already boolean titleExist = false; for (Iterator iGroups = siteGroups.iterator(); !titleExist && iGroups.hasNext();) { Group iGroup = (Group) iGroups.next(); if (title.equals(iGroup.getTitle())) { // found same title titleExist = true; } } if (titleExist) { messages.addMessage(new TargettedMessage("group.title.same", null, TargettedMessage.SEVERITY_ERROR)); return null; } } } int joinableSetNumOfMembersInt = -1; if(joinableSetName != null && !"".equals(joinableSetName.trim())){ if(joinableSetNumOfMembers == null || "".equals(joinableSetNumOfMembers)){ messages.addMessage(new TargettedMessage("maxMembers.empty.alert","num-groups")); return null; }else{ try{ joinableSetNumOfMembersInt = Integer.parseInt(joinableSetNumOfMembers); if(joinableSetNumOfMembersInt <= 0){ messages.addMessage(new TargettedMessage("maxMembers.zero.alert","num-max-members")); return null; } }catch (Exception e) { messages.addMessage(new TargettedMessage("maxMembers.empty.alert","num-max-members")); return null; } } } if (id != null) { // editing existing group group = site.getGroup(id); } else { // adding a new group group= site.addGroup(); group.getProperties().addProperty(group.GROUP_PROP_WSETUP_CREATED, Boolean.TRUE.toString()); } if (group != null) { group.setTitle(title); group.setDescription(description); if(joinableSetName != null && !"".equals(joinableSetName.trim())){ group.getProperties().addProperty(group.GROUP_PROP_JOINABLE_SET, joinableSetName); group.getProperties().addProperty(group.GROUP_PROP_JOINABLE_SET_MAX, joinableSetNumOfMembers); group.getProperties().addProperty(group.GROUP_PROP_JOINABLE_SET_PREVIEW,Boolean.toString(allowViewMembership)); }else{ group.getProperties().removeProperty(group.GROUP_PROP_JOINABLE_SET); group.getProperties().removeProperty(group.GROUP_PROP_JOINABLE_SET_MAX); group.getProperties().removeProperty(group.GROUP_PROP_JOINABLE_SET_PREVIEW); } boolean found = false; // remove those no longer included in the group Set members = group.getMembers(); String[] membersSelected = (memberList != null && memberList.length() > 0) ? memberList.split("##"):new String[0]; for (Iterator iMembers = members.iterator(); iMembers .hasNext();) { found = false; String mId = ((Member) iMembers.next()).getUserId(); for (int i = 0; !found && i < membersSelected.length; i++) { if (mId.equals(membersSelected[i])) { found = true; } } if (!found) { group.removeMember(mId); removedGroupMember.add("uid=" + mId + ";groupId=" + group.getId()); } } // add those selected members List<String> siteRosters = getSiteRosters(null); List<String> siteRoles = getSiteRoleIds(); List<String> selectedRosters = new Vector<String>(); List<String> selectedRoles = new Vector<String>(); for (int i = 0; i < membersSelected.length; i++) { String memberId = membersSelected[i]; if (siteRosters.contains(memberId)) { // this is a roster selectedRosters.add(memberId); // TODO: log event for each individual user? } else if (siteRoles.contains(memberId)) { // this is a role Set roleUsers = site.getUsersHasRole(memberId); for (Iterator iRoleUsers = roleUsers.iterator(); iRoleUsers.hasNext();) { String roleUserId = (String) iRoleUsers.next(); Member member = site.getMember(roleUserId); group.addMember(roleUserId, memberId, member.isActive(), false); addedGroupMember.add("uid=" + roleUserId + ";role=" + member.getRole().getId() + ";active=" + member.isActive() + ";provided=false;groupId=" + group.getId()); } selectedRoles.add(memberId); } else { // normal user id memberId = StringUtils.trimToNull(memberId); if (memberId != null && group.getUserRole(memberId) == null) { Role r = site.getUserRole(memberId); Member m = site.getMember(memberId); Role memberRole = m != null ? m.getRole() : null; // for every member added through the "Manage // Groups" interface, he should be defined as // non-provided // get role first from site definition. // However, if the user is inactive, getUserRole would return null; then use member role instead String roleString = r != null ? r.getId(): memberRole != null? memberRole.getId() : ""; boolean active = m != null ? m.isActive() : true; group.addMember(memberId, roleString, active,false); addedGroupMember.add("uid=" + memberId + ";role=" + roleString + ";active=" + active + ";provided=false;groupId=" + group.getId()); } } } if (!selectedRosters.isEmpty()) { //since RSF doesn't like "."s, they have been escaped. Now unescape them for(String s : selectedRoles){ s = s.replaceAll("-_p_-", "."); } // set provider id group.setProviderGroupId(getProviderString(selectedRosters)); } else { // clear the provider id group.setProviderGroupId(null); } if (!selectedRoles.isEmpty()) { // pack the role provider id and add to property group.getProperties().addProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID, getProviderString(selectedRoles)); } else { // clear the role provider id group.getProperties().removeProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID); } // save the changes try { siteService.save(site); // post event about the participant update EventTrackingService.post(EventTrackingService.newEvent(SiteService.SECURE_UPDATE_GROUP_MEMBERSHIP, group.getId(),true)); if (serverConfigurationService.getBoolean(SiteHelper.WSETUP_TRACK_USER_MEMBERSHIP_CHANGE, false)) { // added members for(String addedMemberString : addedGroupMember) { // an event for each individual member add EventTrackingService.post(EventTrackingService.newEvent(SiteService.EVENT_USER_GROUP_MEMBERSHIP_ADD, addedMemberString, true/*update event*/)); } // removed members for(String removedMemberString : removedGroupMember) { // an event for each individual member remove EventTrackingService.post(EventTrackingService.newEvent(SiteService.EVENT_USER_GROUP_MEMBERSHIP_REMOVE, removedMemberString, true/*update event*/)); } } // reset the form params resetParams(); } catch (IdUnusedException e) { M_log.warn(this + ".processAddGroup: cannot find site " + site.getId(), e); return null; } catch (PermissionException e) { M_log.warn(this + ".processAddGroup: cannot find site " + site.getId(), e); return null; } } return "success"; } public String processConfirmGroupDelete() { // reset the warning messages resetTargettedMessageList(); if (deleteGroupIds == null || deleteGroupIds.length == 0) { // no group chosen to be deleted M_log.debug(this + ".processConfirmGroupDelete: no group chosen to be deleted."); messages.addMessage(new TargettedMessage("delete_group_nogroup","no group chosen")); return null; } else { List<Group> groups = new Vector<Group>(); for (int i = 0; i < deleteGroupIds.length; i ++) { String groupId = deleteGroupIds[i]; // try { Group g = site.getGroup(groupId); groups.add(g); } catch (Exception e) { } } return "confirm"; } } public String processDeleteGroups() { // reset the warning messages resetTargettedMessageList(); if (site != null) { for (int i = 0; i < deleteGroupIds.length; i ++) { String groupId = deleteGroupIds[i]; Group g = site.getGroup(groupId); if (g != null) { site.removeGroup(g); } } try { siteService.save(site); } catch (IdUnusedException e) { messages.addMessage(new TargettedMessage("editgroup.site.notfound.alert","cannot find site")); M_log.warn(this + ".processDeleteGroups: Problem of saving site after group removal: site id =" + site.getId(), e); } catch (PermissionException e) { messages.addMessage(new TargettedMessage("editgroup.site.permission.alert","not allowed to find site")); M_log.warn(this + ".processDeleteGroups: Permission problem of saving site after group removal: site id=" + site.getId(), e); } } return "success"; } public String processCancelDelete() { // reset the warning messages resetTargettedMessageList(); return "cancel"; } /** * atuo create group(s) based on selected roster(s) or role(s) * */ public String processAutoCreateGroup() { // reset the warning messages resetTargettedMessageList(); //check if fields are correct: int intToSplit=-1; if(OPTION_ASSIGN_RANDOM == optionAssign){ String numToSplit = groupSplit ? numToSplitGroup : numToSplitUser; String groupTitle = groupSplit ? groupTitleGroup : groupTitleUser; if(numToSplit == null){ if(groupSplit){ messages.addMessage(new TargettedMessage("numToSplit.group.empty.alert","numToSplit")); }else{ messages.addMessage(new TargettedMessage("numToSplit.user.empty.alert","numToSplit")); } return null; }else{ try { intToSplit = Integer.parseInt(numToSplit); if(intToSplit <= 0){ if(groupSplit){ messages.addMessage(new TargettedMessage("numToSplit.group.notanumber.alert","numToSplit")); }else{ messages.addMessage(new TargettedMessage("numToSplit.user.notanumber.alert","numToSplit")); } return null; } } catch (Exception e) { if(groupSplit){ messages.addMessage(new TargettedMessage("numToSplit.group.notanumber.alert","numToSplit")); }else{ messages.addMessage(new TargettedMessage("numToSplit.user.notanumber.alert","numToSplit")); } return null; } } if(groupTitle == null || "".equals(groupTitle)){ messages.addMessage(new TargettedMessage("groupTitle.empty.alert","groupTitle")); return null; } } List<String> rosterList = new Vector<String>(); if (!selectedRosters.isEmpty()) { for (Iterator<String> iterRosters= selectedRosters.keySet().iterator(); iterRosters.hasNext(); ) { String roster = iterRosters.next(); if (Boolean.TRUE.equals(selectedRosters.get(roster))) { // selected roster rosterList.add(roster); } } } List<String> roleList = new Vector<String>(); if (!selectedRoles.isEmpty()) { for (Iterator<String> iterRoles = selectedRoles.keySet().iterator(); iterRoles.hasNext(); ) { String role = iterRoles.next(); if (Boolean.TRUE.equals(selectedRoles.get(role))) { // selected role roleList.add(role); } } } if (rosterList.isEmpty() && roleList.isEmpty()) { // nothing selected, generate alert messages.addMessage(new TargettedMessage("group.autocreate.selectrosterorrole","Please select at lease one roster or role.")); } else { // go and create the new group if (!rosterList.isEmpty()) { for (String roster:rosterList) { Group group = site.addGroup(); group.getProperties().addProperty(group.GROUP_PROP_WSETUP_CREATED, Boolean.TRUE.toString()); // roster provider string //rsf doesn't like "."'s, so these have been escaped. Now unescape them roster = roster.replaceAll("-_p_-", "."); group.setProviderGroupId(roster); String title = truncateGroupTitle(roster); group.setTitle(title); } } // role based if (!roleList.isEmpty()) { if(OPTION_ASSIGN_BY_ROLES == optionAssign){ for(String role:roleList) { Group group = site.addGroup(); // make the provider id as of SITEID_ROLEID //group.setProviderGroupId(site.getId() + "_" + role); group.getProperties().addProperty(group.GROUP_PROP_WSETUP_CREATED, Boolean.TRUE.toString()); group.getProperties().addProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID, role); String title = truncateGroupTitle(role); group.setTitle(title); // get the authz group String siteReference = siteService.siteReference(site.getId()); try { AuthzGroup siteGroup = authzGroupService.getAuthzGroup(siteReference); Set<String> usersHasRole = siteGroup.getUsersHasRole(role); if (usersHasRole != null) { for (Iterator<String> uIterator = usersHasRole.iterator(); uIterator.hasNext();) { String userId = uIterator.next(); Member member = site.getMember(userId); group.addMember(userId, role, member.isActive(), false); } } } catch (GroupNotDefinedException e) { M_log.debug(this + ".processAutoCreateGroup: no authzgroup found for " + siteReference); } } }else{ createRandomGroups(roleList, intToSplit); } } // save the changes try { siteService.save(site); // reset the form params resetParams(); } catch (IdUnusedException e) { M_log.warn(this + ".processAutoCreateGroup: cannot find site " + site.getId(), e); return null; } catch (PermissionException e) { M_log.warn(this + ".processAutoCreateGroup: cannot find site " + site.getId(), e); return null; } } return "done"; } private void createRandomGroups(List<String> roleList, int unit){ String groupTitle = groupSplit ? groupTitleGroup : groupTitleUser; if(groupTitle != null && !"".equals(groupTitle)){ //get list of all users: List<String> usersList = new ArrayList<String>(); for(String role:roleList) { // get the authz group String siteReference = siteService.siteReference(site.getId()); try { AuthzGroup siteGroup = authzGroupService.getAuthzGroup(siteReference); Set<String> usersHasRole = siteGroup.getUsersHasRole(role); if (usersHasRole != null) { for (Iterator<String> uIterator = usersHasRole.iterator(); uIterator.hasNext();) { String userId = uIterator.next(); if(!usersList.contains(userId)){ usersList.add(userId); } } } } catch (GroupNotDefinedException e) { M_log.debug(this + ".processAutoCreateGroup: no authzgroup found for " + siteReference); } } //split users into random groups: int numOfGroups=-1; int numOfUsersPerGroup=-1; if(groupSplit){ numOfGroups = (unit > usersList.size()) ? usersList.size() : unit; if(numOfGroups > 0){ numOfUsersPerGroup = usersList.size()/numOfGroups; } }else{ numOfUsersPerGroup = (unit > usersList.size()) ? usersList.size() : unit; if(numOfUsersPerGroup > 0){ numOfGroups = usersList.size()/numOfUsersPerGroup; } } int groupCount = 0; List<Group> gList = new ArrayList<Group>(); while(groupCount < numOfGroups){ Group group = site.addGroup(); group.getProperties().addProperty(group.GROUP_PROP_WSETUP_CREATED, Boolean.TRUE.toString()); //Title StringBuffer title = new StringBuffer(); title.append(groupTitle); title.append("-"); title.append(groupCount+1); group.setTitle(title.toString()); int userCount = 0; while(userCount < numOfUsersPerGroup && usersList.size() > 0){ int index = (int)(Math.random() * (usersList.size() - 1)); String userId = usersList.get(index); Member member = site.getMember(userId); group.addMember(userId, member.getRole().getId(), member.isActive(), false); //remove this user now: usersList.remove(index); userCount++; } groupCount++; // add the group object to list gList.add(group); } // all the groups has been created, but there are some users still left to be assigned while (usersList.size() > 0) { // pick a random user int index = (int)(Math.random() * (usersList.size() - 1)); String userId = usersList.get(index); // pick a random group int gIndex = (int)(Math.random() * (gList.size() - 1)); Group group = gList.get(gIndex); // add user to group Member member = site.getMember(userId); group.addMember(userId, member.getRole().getId(), member.isActive(), false); //remove this user now: usersList.remove(index); } } } /** * check whether the title string is within length limit, truncate it if necessary * @param oTitle * @return */ private String truncateGroupTitle(String oTitle) { String title = oTitle; if (title.length() > SiteConstants.SITE_GROUP_TITLE_LIMIT) { title = title.substring(0, SiteConstants.SITE_GROUP_TITLE_LIMIT); } return title.trim(); } /** * Return a single string representing the provider id list * @param idsList */ private String getProviderString(List<String> idsList) { String[] sArray = new String[idsList.size()]; sArray = (String[]) idsList.toArray(sArray); if (groupProvider != null) { return groupProvider.packId(sArray); } else { // simply concat strings StringBuffer rv = new StringBuffer(); for(String sArrayString:sArray) { rv.append(" ").append(sArrayString); } return rv.toString(); } } /** * Removes a group from the site * * @param groupId * @return title of page removed * @throws IdUnusedException * @throws PermissionException */ public String removeGroup(String groupId) throws IdUnusedException, PermissionException { Group group = site.getGroup(groupId); site.removeGroup(group); saveSite(site); EventTrackingService.post( EventTrackingService.newEvent(GROUP_DELETE, "/site/" + site.getId() + "/group/" + group.getId(), false)); return group.getTitle(); } public String[] getDeleteGroupIds() { return deleteGroupIds; } public List<Group> getSelectedGroups() { List<Group> rv = new Vector<Group>(); if (deleteGroupIds != null && deleteGroupIds.length > 0 && site != null) { for (int i = 0; i<deleteGroupIds.length; i++) { String groupId = deleteGroupIds[i]; try { Group g = site.getGroup(groupId); rv.add(g); } catch (Exception e) { M_log.debug(this + ":getSelectedGroups: cannot get group with id " + groupId); } } } return rv; } public void setDeleteGroupIds(String[] deleteGroupIds) { this.deleteGroupIds = deleteGroupIds; } /** * Gets the current tool * @return Tool */ public Tool getCurrentTool() { return toolManager.getCurrentTool(); } /** * check whether there is already a group within the site containing the roster id * @param rosterId * @return */ public boolean existRosterGroup(String rosterId) { boolean rv = false; Collection<Group> groups = site.getGroups(); for(Group group:groups) { // check if there is one group with this roster id already String groupWSetupCreated = group.getProperties().getProperty(group.GROUP_PROP_WSETUP_CREATED); if (groupWSetupCreated != null && groupWSetupCreated.equalsIgnoreCase(Boolean.TRUE.toString())) { if (group.getProviderGroupId() != null && group.getProviderGroupId().equals(rosterId)) { rv = true; break; } } } return rv; } /** * check whether there is already a group within the site containing the role id * @param roleId * @return */ public boolean existRoleGroup(String roleId) { boolean rv = false; Collection<Group> groups = site.getGroups(); for(Group group:groups) { // check if there is one group with this roster id already String groupWSetupCreated = group.getProperties().getProperty(group.GROUP_PROP_WSETUP_CREATED); if (groupWSetupCreated != null && groupWSetupCreated.equalsIgnoreCase(Boolean.TRUE.toString())) { String groupRole = group.getProperties().getProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID); if (groupRole != null && groupRole.equals(roleId)) { rv = true; break; } } } return rv; } /** ** Comparator for sorting Group objects **/ private class GroupComparator implements Comparator { public int compare(Object o1, Object o2) { return ((Group)o1).getTitle().compareToIgnoreCase( ((Group)o2).getTitle() ); } } /** * Grabs the uploaded file from the groupfile request attribute and extracts the group details * from it, adding them to the importedGroups list as it goes. Expects at least three columns, * the first three being first name, last name and email respectively. */ public String processUploadAndCheck() { String uploadsDone = (String) httpServletRequest.getAttribute(RequestFilter.ATTR_UPLOADS_DONE); FileItem usersFileItem; if (uploadsDone != null && uploadsDone.equals(RequestFilter.ATTR_UPLOADS_DONE)) { try { usersFileItem = (FileItem) httpServletRequest.getAttribute(REQ_ATTR_GROUPFILE); if(usersFileItem != null && usersFileItem.getSize() > 0) { String mimetype = usersFileItem.getContentType(); String filename = usersFileItem.getName(); if (ArrayUtils.contains(CSV_MIME_TYPES, mimetype) || StringUtils.endsWith(filename, "csv")) { if (processCsvFile(usersFileItem)) { return "success"; // SHORT CIRCUIT } } else { M_log.error("Invalid file type: " + mimetype); return "error"; // SHORT CIRCUIT } } } catch (Exception e){ M_log.error(e.getClass() + " : " + e.getMessage()); return "error"; // SHORT CIRCUIT } finally { // clear the groupfile attribute so the tool does not have to be reset httpServletRequest.removeAttribute(REQ_ATTR_GROUPFILE); } } return "error"; } /** * Helper to process the uploaded CSV file * * @param fileItem * @return */ private boolean processCsvFile(FileItem fileItem){ M_log.debug("CSV file uploaded"); importedGroups = new ArrayList<ImportedGroup>(); CSVReader reader; try { reader = new CSVReader(new InputStreamReader(fileItem.getInputStream())); List<String[]> lines = reader.readAll(); //maintain a map of the groups and their titles in case the CSV file is unordered //this way we can still lookup the group and add members to it Map<String, ImportedGroup> groupMap = new HashMap<String, ImportedGroup>(); for(String[] line: lines){ String groupTitle = StringUtils.trim(line[0]); String userId = StringUtils.trim(line[1]); //if we already have an occurrence of this group, get the group and update the user list within it if(groupMap.containsKey(groupTitle)){ ImportedGroup group = groupMap.get(groupTitle); group.addUser(userId); } else { ImportedGroup group = new ImportedGroup(groupTitle, userId); groupMap.put(groupTitle, group); } } //extract all of the imported groups from the map importedGroups.addAll(groupMap.values()); } catch (IOException ioe) { M_log.error(ioe.getClass() + " : " + ioe.getMessage()); return false; } catch (ArrayIndexOutOfBoundsException ae){ M_log.error(ae.getClass() + " : " + ae.getMessage()); return false; } return true; } /** * Helper to check for a valid user in a site, given an eid * @param eid eid of user,v eg jsmith26 * @return */ public boolean isValidSiteUser(String eid) { try { User u = userDirectoryService.getUserByEid(eid); if(u != null){ Member m = site.getMember(u.getId()); if(m != null) { return true; } } } catch (UserNotDefinedException e) { //not a valid user return false; } return false; } /** * Helper to get a userId given an eid * @param eid eid of user,v eg jsmith26 * @return */ public String getUserId(String eid) { try { return userDirectoryService.getUserId(eid); } catch (UserNotDefinedException e) { M_log.error("The eid: " + eid + "is invalid."); return null; } } /** * Does the actual import of the groups into the site. * @return */ public String processImportedGroups() { //get current groups in this site List<Group> existingGroups = getGroups(); //for each imported group... for(ImportedGroup importedGroup: importedGroups) { Group group = null; //check if the groups already exists for(Group g : existingGroups) { if(StringUtils.equals(g.getTitle(), importedGroup.getGroupTitle())) { //use existing group group = g; } } if(group == null){ //create new group group= site.addGroup(); group.getProperties().addProperty(group.GROUP_PROP_WSETUP_CREATED, Boolean.TRUE.toString()); group.setTitle(importedGroup.getGroupTitle()); } //add all of the imported members to the group for(String eid: importedGroup.getUserIds()){ this.addUserToGroup(eid, group); } try { siteService.save(site); // post event about the participant update EventTrackingService.post(EventTrackingService.newEvent(SiteService.SECURE_UPDATE_GROUP_MEMBERSHIP, group.getId(),true)); } catch (Exception e) { M_log.error("processImportedGroups failed for site: " + site.getId(), e); return "error"; } } return "success"; } /** * Helper to get a list of user eids in a group * @param g the group * @return */ public List<String> getGroupUserIds(Group g) { List<String> userIds = new ArrayList<String>(); if(g == null) { return userIds; } Set<Member> members= g.getMembers(); for(Member m: members) { userIds.add(m.getUserEid()); } return userIds; } /** * Helper to add a user to a group. Takes care of the role selection. * @param eid eid of the user eg jsmith26 * @param g the group */ private void addUserToGroup(String eid, Group g) { //is this a valid site user? if(!isValidSiteUser(eid)){ return; } //get userId String userId = getUserId(eid); if(StringUtils.isBlank(userId)) { return; } //is user already in the group? if(g.getUserRole(userId) != null) { return; } //add user to group with correct role. This is the same logic as above Role r = site.getUserRole(userId); Member m = site.getMember(userId); Role memberRole = m != null ? m.getRole() : null; g.addMember(userId, r != null ? r.getId() : memberRole != null? memberRole.getId() : "", m != null ? m.isActive() : true, false); } @Setter private UserDirectoryService userDirectoryService; /** * We need this to get the uploaded file as snaffled by the request filter. */ @Setter private HttpServletRequest httpServletRequest; /** * As we import groups we store the details here for use in further stages * of the import sequence. */ @Getter private List<ImportedGroup> importedGroups; public String processCreateJoinableSet() { // reset the warning messages resetTargettedMessageList(); String returnVal = processCreateJoinableSetHelper(); if(returnVal == null){ return null; }else{ resetParams(); return returnVal; } } private String processCreateJoinableSetHelper(){ if(joinableSetName == null || "".equals(joinableSetName.trim())){ messages.addMessage(new TargettedMessage("groupTitle.empty.alert","groupTitle-group")); return null; } int joinableSetNumOfGroupsInt = -1; if(joinableSetNumOfGroups == null || "".equals(joinableSetNumOfGroups)){ messages.addMessage(new TargettedMessage("numGroups.empty.alert","num-groups")); return null; }else{ try{ joinableSetNumOfGroupsInt = Integer.parseInt(joinableSetNumOfGroups); if(joinableSetNumOfGroupsInt > 1000){ messages.addMessage(new TargettedMessage("maxGroups.alert","num-groups")); return null; } if(joinableSetNumOfGroupsInt <= 0){ messages.addMessage(new TargettedMessage("numGroups.zero.alert","num-groups")); } }catch (Exception e) { messages.addMessage(new TargettedMessage("numGroups.empty.alert","num-groups")); return null; } } int joinableSetNumOfMembersInt = -1; if(joinableSetNumOfMembers == null || "".equals(joinableSetNumOfMembers)){ messages.addMessage(new TargettedMessage("maxMembers.empty.alert","num-groups")); return null; }else{ try{ joinableSetNumOfMembersInt = Integer.parseInt(joinableSetNumOfMembers); if(joinableSetNumOfMembersInt <= 0){ messages.addMessage(new TargettedMessage("maxMembers.zero.alert","num-max-members")); return null; } }catch (Exception e) { messages.addMessage(new TargettedMessage("maxMembers.empty.alert","num-max-members")); return null; } } int groupsCreated = 0; Collection siteGroups = site.getGroups(); Set<String> groupTitles = new HashSet<String>(); if (siteGroups != null && siteGroups.size() > 0) { for (Iterator iGroups = siteGroups.iterator(); iGroups.hasNext();) { Group iGroup = (Group) iGroups.next(); groupTitles.add(iGroup.getTitle()); } } for(int i = 1; groupsCreated < joinableSetNumOfGroupsInt && i < 1000; i++){ String groupTitle = joinableSetName + " " + i; if(!groupTitles.contains(groupTitle)){ Group g = site.addGroup(); g.getProperties().addProperty(g.GROUP_PROP_WSETUP_CREATED, Boolean.TRUE.toString()); g.getProperties().addProperty(g.GROUP_PROP_JOINABLE_SET, joinableSetName); g.getProperties().addProperty(g.GROUP_PROP_JOINABLE_SET_MAX, joinableSetNumOfMembers); g.getProperties().addProperty(g.GROUP_PROP_JOINABLE_SET_PREVIEW,Boolean.toString(allowViewMembership)); g.setTitle(joinableSetName + " " + i); try{ siteService.save(site); groupsCreated++; }catch (Exception e) { } } } return "success"; } public String processDeleteJoinableSet(){ // reset the warning messages resetTargettedMessageList(); boolean updated = false; for(Group group : site.getGroups()){ String joinableSet = group.getProperties().getProperty(group.GROUP_PROP_JOINABLE_SET); if(joinableSet != null && joinableSet.equals(joinableSetNameOrig)){ group.getProperties().removeProperty(group.GROUP_PROP_JOINABLE_SET); group.getProperties().removeProperty(group.GROUP_PROP_JOINABLE_SET_MAX); group.getProperties().removeProperty(group.GROUP_PROP_JOINABLE_SET_PREVIEW); updated = true; } } if(updated){ try{ siteService.save(site); }catch (Exception e) { } } resetParams(); return "success"; } public String processChangeJoinableSetName(){ // reset the warning messages resetTargettedMessageList(); String returnVal = processChangeJoinableSetNameHelper(); if(returnVal == null){ return null; }else{ resetParams(); return returnVal; } } private String processChangeJoinableSetNameHelper(){ if(joinableSetName == null || "".equals(joinableSetName.trim())){ messages.addMessage(new TargettedMessage("groupTitle.empty.alert","groupTitle-group")); return null; } if(!joinableSetName.equals(joinableSetNameOrig)){ boolean updated = false; for(Group group : site.getGroups()){ String joinableSet = group.getProperties().getProperty(group.GROUP_PROP_JOINABLE_SET); if(joinableSet != null && joinableSet.equals(joinableSetNameOrig)){ group.getProperties().addProperty(group.GROUP_PROP_JOINABLE_SET, joinableSetName); updated = true; } } if(updated){ try{ siteService.save(site); }catch (Exception e) { } } } return "success"; } public String processGenerateJoinableSet(){ // reset the warning messages resetTargettedMessageList(); //first generate the new groups since it will check all the required fields String returnVal = processCreateJoinableSetHelper(); if(returnVal != null && "success".equals(returnVal)){ returnVal = processChangeJoinableSetNameHelper(); if(returnVal == null){ return null; }else{ resetParams(); return returnVal; } } return null; } }