/********************************************************************************** * Copyright 2008-2009 Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.mailsender.logic.impl; import java.text.Collator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; 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.Role; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.mailsender.logic.ComposeLogic; import org.sakaiproject.mailsender.logic.ExternalLogic; import org.sakaiproject.mailsender.model.EmailRole; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.user.api.UserNotDefinedException; public class ComposeLogicImpl implements ComposeLogic { private static final Log log = LogFactory.getLog(ComposeLogicImpl.class); private static final int NUMBER_ROLES = 15; protected SiteService siteService; protected AuthzGroupService authzGroupService; protected UserDirectoryService userDirectoryService; protected ExternalLogic externalLogic; protected ToolManager toolManager; protected ServerConfigurationService serverConfigurationService; protected HashSet<String> ignoreRoles = new HashSet<String>(); /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.impl.ComposeLogic#getEmailRoles() */ public List<EmailRole> getEmailRoles() throws GroupNotDefinedException { List<EmailRole> theRoles = new ArrayList<EmailRole>(); List<EmailRole> configRoles = getConfigRoles(); String realmId = externalLogic.getSiteRealmID(); AuthzGroup arole = authzGroupService.getAuthzGroup(realmId); for (Iterator<?> i = arole.getRoles().iterator(); i.hasNext();) { Role r = (Role) i.next(); String rolename = r.getId(); if (includeRole(rolename)) { String singular = null; String plural = null; EmailRole configRole = findConfigRole(realmId, rolename, configRoles); // check first for an override from config if (configRole != null) { singular = configRole.getRoleSingular(); plural = configRole.getRolePlural(); } // default case else { singular = rolename; plural = rolename; } // create email role and add to list EmailRole emailrole = null; if (getGroupAwareRole().equals(rolename)) { emailrole = new EmailRole(realmId, rolename, singular, plural, EmailRole.Type.ROLE, true); } else { emailrole = new EmailRole(realmId, rolename, singular, plural, EmailRole.Type.ROLE); } theRoles.add(emailrole); } } Collections.sort(theRoles, new EmailRoleComparator(EmailRoleComparator.SORT_BY.PLURAL)); return theRoles; } /** * Should this role be included in the list which users can send messages to? * @param rolename The role name. * @return <code>true</code> when the role can be shown/selected. */ protected boolean includeRole(String rolename) { // Ignore roles that don't get assigned to users and specifically ignored roles. return ! (rolename.startsWith(".") || ignoreRoles.contains(rolename)); } /** * Get the config roles defined in the tool configuration * * @return */ private List<EmailRole> getConfigRoles() { Properties props = toolManager.getCurrentPlacement().getPlacementConfig(); ArrayList<EmailRole> configRoles = new ArrayList<EmailRole>(); // check for and add in the manual roles from the config file for (int i = 1; i < (NUMBER_ROLES + 1); i++) { String rolerealm = StringUtils.trimToNull(props.getProperty("role" + i + "realmid")); String rolename = StringUtils.trimToNull(props.getProperty("role" + i + "id")); String rolesingular = StringUtils.trimToNull(props.getProperty("role" + i + "singular")); String roleplural = StringUtils.trimToNull(props.getProperty("role" + i + "plural")); // only add role if all data is present if (rolerealm != null && rolename != null && rolesingular != null && roleplural != null) { EmailRole emailrole = null; if (getGroupAwareRole().equals(rolename)) { emailrole = new EmailRole(rolerealm, rolename, rolesingular, roleplural, EmailRole.Type.ROLE, true); } else { emailrole = new EmailRole(rolerealm, rolename, rolesingular, roleplural, EmailRole.Type.ROLE); } configRoles.add(emailrole); } } return configRoles; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.impl.ComposeLogic#getEmailGroups() */ public List<EmailRole> getEmailGroups() throws IdUnusedException { ArrayList<EmailRole> roles = new ArrayList<EmailRole>(); Site currentSite = currentSite(); Collection<Group> groups = currentSite.getGroups(); for (Group group : groups) { if (group.getProperties().getProperty("sections_category") == null) { String groupName = group.getTitle(); String groupId = group.getId(); roles.add(new EmailRole(groupId, groupId, groupName, groupName, EmailRole.Type.GROUP)); } } Collections.sort(roles, new EmailRoleComparator(EmailRoleComparator.SORT_BY.PLURAL)); return roles; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.impl.ComposeLogic#getEmailSections() */ public List<EmailRole> getEmailSections() throws IdUnusedException { ArrayList<EmailRole> roles = new ArrayList<EmailRole>(); Site currentSite = currentSite(); Collection<Group> groups = currentSite.getGroups(); for (Group group : groups) { if (group.getProperties().getProperty("sections_category") != null) { String groupName = group.getTitle(); String groupId = group.getId(); roles.add(new EmailRole(groupId, groupId, groupName, groupName, EmailRole.Type.SECTION)); } } Collections.sort(roles, new EmailRoleComparator(EmailRoleComparator.SORT_BY.PLURAL)); return roles; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.impl.ComposeLogic#getGroupAwareRole() */ public String getGroupAwareRole() { String retval = null; String gar = serverConfigurationService.getString("mailsender.group.aware.role", ""); String[] gartokens = gar.split(","); try { String realmId = externalLogic.getSiteRealmID(); AuthzGroup arole = authzGroupService.getAuthzGroup(realmId); for (Iterator<?> i = arole.getRoles().iterator(); i.hasNext();) { Role r = (Role) i.next(); String rolename = r.getId(); for (int t = 0; t < gartokens.length; t++) { if (gartokens[t].trim().equals(rolename.trim())) { retval = rolename; break; } } if (retval != null) break; } } catch (GroupNotDefinedException e) { log.error(e.getMessage(), e); } if (retval == null) { retval = getGroupAwareRoleDefault(); } return retval; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.impl.ComposeLogic#getGroupAwareRoleDefault() */ public String getGroupAwareRoleDefault() { String siteType = externalLogic.getSiteType(); String defaultRole = ""; if ("course".equals(siteType)) defaultRole = "Student"; if ("project".equals(siteType)) defaultRole = "access"; return defaultRole; } public List<User> getUsers() throws IdUnusedException { ArrayList<User> users = new ArrayList<User>(); Set<String> userIds = getUserIds(); compileUsers(users, userIds); return users; } protected Set<String> getUserIds() throws IdUnusedException { Site currentSite = currentSite(); Set<String> userIds = currentSite.getUsers(); String curUser = externalLogic.getCurrentUserId(); // don't include the current user. this logic is used in other places so it is combined here // to save repeating the logic in the presentation layer. userIds.remove(curUser); return userIds; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.ComposeLogic#getUsersByRole(String) */ public List<User> getUsersByRole(String role) throws IdUnusedException { ArrayList<User> users = new ArrayList<User>(); Set<String> userIds = getUserIdsByRole(role); compileUsers(users, userIds); return users; } protected Set<String> getUserIdsByRole(String role) throws IdUnusedException { Site currentSite = currentSite(); Set<String> userIds = currentSite.getUsersHasRole(role); String curUser = externalLogic.getCurrentUserId(); // don't include the current user. this logic is used in other places so it is combined here // to save repeating the logic in the presentation layer. userIds.remove(curUser); return userIds; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.ComposeLogic#countUsersByRole(java.lang.String) */ public int countUsersByRole(String role) { int count = 0; try { Set<String> userIds = getUserIdsByRole(role); count = userIds.size(); } catch (IdUnusedException e) { // don't care about this } return count; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.ComposeLogic#getUsersByGroup(String) */ public List<User> getUsersByGroup(String groupId) throws IdUnusedException { ArrayList<User> users = new ArrayList<User>(); Set<String> userIds = getUserIdsByGroup(groupId); compileUsers(users, userIds); return users; } protected Set<String> getUserIdsByGroup(String groupId) throws IdUnusedException { Site currentSite = currentSite(); Group group = currentSite.getGroup(groupId); Set<String> userIds = group.getUsers(); String curUser = externalLogic.getCurrentUserId(); // don't include the current user. this logic is used in other places so it is combined here // to save repeating the logic in the presentation layer. userIds.remove(curUser); return userIds; } /** * {@inheritDoc} * * @see org.sakaiproject.mailsender.logic.ComposeLogic#countUsersByGroup(java.lang.String) */ public int countUsersByGroup(String groupId) { int count = 0; try { Set<String> userIds = getUserIdsByGroup(groupId); count = userIds.size(); } catch (IdUnusedException e) { // don't care about this } return count; } /** * Dependency injection method * * @param ss */ public void setSiteService(SiteService ss) { siteService = ss; } /** * Dependency injection method * * @param el */ public void setExternalLogic(ExternalLogic el) { externalLogic = el; } /** * Dependency injection method * * @param tl */ public void setToolManager(ToolManager tl) { toolManager = tl; } /** * Dependency injection method * * @param ags */ public void setAuthzGroupService(AuthzGroupService ags) { authzGroupService = ags; } /** * Dependency injection method * * @param uds */ public void setUserDirectoryService(UserDirectoryService uds) { userDirectoryService = uds; } /** * Dependency injection method * * @param scs */ public void setServerConfigurationService(ServerConfigurationService scs) { serverConfigurationService = scs; } /** * Inject method for setting any roles that should be ignored. * * @param ignoreRoles */ public void setIgnoreRoles(String ignoreRoles) { if (ignoreRoles != null) { this.ignoreRoles.clear(); String[] roles = StringUtils.split(ignoreRoles, ","); for (String role : roles) { this.ignoreRoles.add(role.trim()); } } } /** * Get the current site that the user is acting in. * * @return * @throws IdUnusedException */ protected Site currentSite() throws IdUnusedException { String siteId = externalLogic.getSiteID(); Site currentSite = siteService.getSite(siteId); return currentSite; } /** * Compile a list of users based on user IDs. Does not include the current user. * * @param users * @param userIds */ private void compileUsers(ArrayList<User> users, Set<String> userIds) { for (String userId : userIds) { try { users.add(userDirectoryService.getUser(userId)); } catch (UserNotDefinedException e) { log.warn("Unable to retrieve user: " + userId); } } Collections.sort(users, new UserComparator()); } /** * Look through configRoles to find a role that matches realmId, roleId * * @param realmId * @param roleId * @param configRoles * @return A role that matches realmId, roleId. <code>null</code> if not found. */ private EmailRole findConfigRole(String realmId, String roleId, List<EmailRole> configRoles) { EmailRole retRole = null; for (EmailRole role : configRoles) { if (role.getRealmId().equals(realmId) && role.getRoleId().equals(roleId)) { retRole = role; break; } } return retRole; } /** * Sorts EmailRoles by role name depending on how it is constructed. * * @author <a href="mailto:carl.hall@et.gatech.edu">Carl Hall</a> */ private static class EmailRoleComparator implements Comparator<EmailRole> { public enum SORT_BY { SINGULAR, PLURAL; } Collator collator = Collator.getInstance(); SORT_BY sortBy; public EmailRoleComparator(SORT_BY sortBy) { this.sortBy = sortBy; } public int compare(EmailRole o1, EmailRole o2) { int retval = 0; if (sortBy == SORT_BY.SINGULAR) retval = collator.compare(o1.getRoleSingular(), o2.getRoleSingular()); else if (sortBy == SORT_BY.PLURAL) retval = collator.compare(o1.getRolePlural(), o2.getRolePlural()); return retval; } } /** * Sorts users by last name, first name, display id * * @author <a href="mailto:carl.hall@et.gatech.edu">Carl Hall</a> */ private static class UserComparator implements Comparator<User> { Collator collator = Collator.getInstance(); public int compare(User user1, User user2) { String displayName1 = user1.getLastName() + ", " + user1.getFirstName() + " (" + user1.getDisplayId() + ")"; String displayName2 = user2.getLastName() + ", " + user2.getFirstName() + " (" + user2.getDisplayId() + ")"; return collator.compare(displayName1, displayName2); } } }