/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/polls/tags/polls-1.4.3/impl/src/java/org/sakaiproject/poll/logic/impl/ExternalLogicImpl.java $ * $Id: ExternalLogicImpl.java 96681 2011-08-09 16:03:21Z arwhyte@umich.edu $ *********************************************************************************** * * Copyright (c) 2006, 2007 The 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.osedu.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.poll.logic.impl; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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.AuthzPermissionException; import org.sakaiproject.authz.api.FunctionManager; import org.sakaiproject.authz.api.GroupNotDefinedException; import org.sakaiproject.authz.api.Role; import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.email.api.EmailService; import org.sakaiproject.emailtemplateservice.model.EmailTemplate; import org.sakaiproject.emailtemplateservice.model.RenderedTemplate; import org.sakaiproject.emailtemplateservice.service.EmailTemplateService; import org.sakaiproject.entity.api.EntityManager; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entitybroker.DeveloperHelperService; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.poll.logic.ExternalLogic; import org.sakaiproject.poll.logic.PollListManager; import org.sakaiproject.poll.model.PollRolePerms; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.time.api.TimeService; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.SessionManager; 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.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class ExternalLogicImpl implements ExternalLogic { private static Log log = LogFactory.getLog(ExternalLogicImpl.class); private static final String /* Email template constants */ EMAIL_TEMPLATE_NOTIFY_DELETED_OPTION = "polls.notifyDeletedOption", FILE_NOTIFY_DELETED_OPTION_TEMPLATE = "notifyDeletedOption.xml", /* Other constants */ USER_ADMIN_ID = "admin", USER_ADMIN_EID = "admin"; private static final String USER_ENTITY_PREFIX = "/user/"; /** * Injected services */ private DeveloperHelperService developerHelperService; public void setDeveloperHelperService( DeveloperHelperService developerHelperService) { this.developerHelperService = developerHelperService; } private AuthzGroupService authzGroupService; public void setAuthzGroupService(AuthzGroupService authzGroupService) { this.authzGroupService = authzGroupService; } private EntityManager entityManager; public void setEntityManager(EntityManager em) { entityManager = em; } private EmailService emailService; public void setEmailService(EmailService emailService) { this.emailService = emailService; } private EmailTemplateService emailTemplateService; public void setEmailTemplateService(EmailTemplateService emailTemplateService) { this.emailTemplateService = emailTemplateService; } private EventTrackingService eventTrackingService; public void setEventTrackingService(EventTrackingService ets) { eventTrackingService = ets; } private FunctionManager functionManager; public void setFunctionManager(FunctionManager fm) { functionManager = fm; } private TimeService timeService; public void setTimeService(TimeService ts) { timeService = ts; } private SiteService siteService; public void setSiteService(SiteService siteService) { this.siteService = siteService; } private SecurityService securityService; public void setSecurityService(SecurityService securityService) { this.securityService = securityService; } private ServerConfigurationService serverConfigurationService; public void setServerConfigurationService( ServerConfigurationService serverConfigurationService) { this.serverConfigurationService = serverConfigurationService; } private SessionManager sessionManager; public void setSessionManager(SessionManager sessionManager) { this.sessionManager = sessionManager; } private UserDirectoryService userDirectoryService; public void setUserDirectoryService(UserDirectoryService userDirectoryService) { this.userDirectoryService = userDirectoryService; } private String fromEmailAddress; public void setFromEmailAddress(String fromEmailAddress) { this.fromEmailAddress = fromEmailAddress; } private String replyToEmailAddress; public void setReplyToEmailAddress(String replyToEmailAddress) { this.replyToEmailAddress = replyToEmailAddress; } /** * Methods */ public String getCurrentLocationId() { return developerHelperService.getCurrentLocationId(); } public boolean isUserAdmin(String userId) { return developerHelperService.isUserAdmin(USER_ENTITY_PREFIX + userId); } public boolean isUserAdmin() { return isUserAdmin(getCurrentUserId()); } public String getCurrentUserId() { return developerHelperService.getCurrentUserId(); } public String getCurrentuserReference() { return developerHelperService.getCurrentUserReference(); } public String getUserEidFromId(String userId) { try { return userDirectoryService.getUserEid(userId); } catch (UserNotDefinedException e) { log.debug("Looked up non-existant user id: "+userId, e); } return null; } public String getCurrentLocationReference() { log.debug("getCurrentLocationReference"); return developerHelperService.getCurrentLocationReference(); } public boolean isAllowedInLocation(String permission, String locationReference, String userReference) { log.debug("isAllowed in location( " + permission + " , " + locationReference + " , " + userReference); return developerHelperService.isUserAllowedInEntityReference(userReference, permission, locationReference); } public boolean isAllowedInLocation(String permission, String locationReference) { log.debug("isAllowed in location( " + permission + " , " + locationReference); return isAllowedInLocation(permission, locationReference, developerHelperService.getCurrentUserReference()); } private static final String SAKAI_SITE_TYPE = SiteService.SITE_SUBTYPE; public void init() { log.info("init()"); try { //Load the "notify deleted option" template loadMailTemplate(EMAIL_TEMPLATE_NOTIFY_DELETED_OPTION, FILE_NOTIFY_DELETED_OPTION_TEMPLATE); } catch (ParserConfigurationException e) { throw new RuntimeException("Could not load an XML parser.", e); } catch (IOException e) { throw new RuntimeException("Could not read from XML template."); } catch (InvalidEmailTemplateException e) { throw new RuntimeException("Could not parse email template: "+e.getKey()+" from "+e.getFileName(), e); } } public List<String> getSitesForUser(String userId, String permission) { log.debug("userId: " + userId + ", permission: " + permission); List<String> l = new ArrayList<String>(); // get the groups from Sakai Set<String> authzGroupIds = authzGroupService.getAuthzGroupsIsAllowed(userId, permission, null); Iterator<String> it = authzGroupIds.iterator(); while (it.hasNext()) { String authzGroupId = it.next(); Reference r = entityManager.newReference(authzGroupId); if (r.isKnownType()) { // check if this is a Sakai Site or Group if (r.getType().equals(SiteService.APPLICATION_ID)) { String type = r.getSubType(); if (SAKAI_SITE_TYPE.equals(type)) { // this is a Site String siteId = r.getId(); l.add(siteId); } } } } if (l.isEmpty()) log.info("Empty list of siteIds for user:" + userId + ", permission: " + permission); return l; } public void postEvent(String eventId, String reference, boolean modify) { eventTrackingService.post(eventTrackingService.newEvent(eventId, reference, modify)); } public void registerFunction(String function) { functionManager.registerFunction(function); } public TimeZone getLocalTimeZone() { return timeService.getLocalTimeZone(); } public List<String> getRoleIdsInRealm(String realmId) { AuthzGroup group; try { group = authzGroupService.getAuthzGroup(realmId); List<String> ret = new ArrayList<String>(); Set<Role> roles = group.getRoles(); Iterator<Role> i = roles.iterator(); while (i.hasNext()) { Role role = (Role)i.next(); ret.add(role.getId()); } return ret; } catch (GroupNotDefinedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public boolean isRoleAllowedInRealm(String roleId, String realmId, String permission) { try { AuthzGroup group = authzGroupService.getAuthzGroup(realmId); Role role = group.getRole(roleId); return role.isAllowed(permission); } catch (GroupNotDefinedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } public String getSiteTile(String siteId) { Site site; try { site = siteService.getSite(siteId); return site.getTitle(); } catch (IdUnusedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public void setToolPermissions(Map<String, PollRolePerms> permMap, String locationReference) throws SecurityException, IllegalArgumentException { AuthzGroup authz = null; try { authz = authzGroupService.getAuthzGroup(locationReference); } catch (GroupNotDefinedException e) { throw new IllegalArgumentException(e); } Set<Entry<String, PollRolePerms>> entrySet = permMap.entrySet(); for (Iterator<Entry<String, PollRolePerms>> i = entrySet.iterator(); i.hasNext();) { Entry<String, PollRolePerms> entry = i.next(); String key = entry.getKey(); Role role = authz.getRole(key); //try { PollRolePerms rp = (PollRolePerms) entry.getValue(); if (rp.add != null ) setFunc(role,PollListManager.PERMISSION_ADD,rp.add); if (rp.deleteAny != null ) setFunc(role,PollListManager.PERMISSION_DELETE_ANY, rp.deleteAny); if (rp.deleteOwn != null ) setFunc(role,PollListManager.PERMISSION_DELETE_OWN,rp.deleteOwn); if (rp.editAny != null ) setFunc(role,PollListManager.PERMISSION_EDIT_ANY,rp.editAny); if (rp.editOwn != null ) setFunc(role,PollListManager.PERMISSION_EDIT_OWN,rp.editOwn); if (rp.vote != null ) setFunc(role,PollListManager.PERMISSION_VOTE,rp.vote); log.info(" Key: " + key + " Vote: " + rp.vote + " New: " + rp.add ); /*} catch(Exception e) { log.error(" ClassCast Ex PermKey: " + key); e.printStackTrace(); return "error"; }*/ } try { authzGroupService.save(authz); } catch (GroupNotDefinedException e) { throw new IllegalArgumentException(e); } catch (AuthzPermissionException e) { throw new SecurityException(e); } } public Map<String, PollRolePerms> getRoles(String locationReference) { log.debug("Getting permRoles"); Map<String, PollRolePerms> perms = new HashMap<String, PollRolePerms>(); try { AuthzGroup group = authzGroupService.getAuthzGroup(locationReference); Set<Role> roles = group.getRoles(); Iterator<Role> i = roles.iterator(); while (i.hasNext()) { Role role = (Role)i.next(); String name = role.getId(); log.debug("Adding element for " + name); perms.put(name, new PollRolePerms(name, role.isAllowed(PollListManager.PERMISSION_VOTE), role.isAllowed(PollListManager.PERMISSION_ADD), role.isAllowed(PollListManager.PERMISSION_DELETE_OWN), role.isAllowed(PollListManager.PERMISSION_DELETE_ANY), role.isAllowed(PollListManager.PERMISSION_EDIT_OWN), role.isAllowed(PollListManager.PERMISSION_EDIT_ANY) )); } } catch (Exception e) { e.printStackTrace(); } return perms; } private void setFunc(Role role, String function, Boolean allow) { //m_log.debug("Setting " + function + " to " + allow.toString() + " for " + rolename + " in /site/" + ToolManager.getCurrentPlacement().getContext()); if (allow.booleanValue()) role.allowFunction(function); else role.disallowFunction(function); } public String getSiteRefFromId(String siteId) { return siteService.siteReference(siteId); } public boolean userIsViewingAsRole() { String effectiveRole = securityService.getUserEffectiveRole(developerHelperService.getCurrentLocationReference()); if (effectiveRole != null) return true; return false; } public void notifyDeletedOption(List<String> userEids, String siteTitle, String pollQuestion) { if (siteTitle == null) throw new IllegalArgumentException("Site title cannot be null"); else if (pollQuestion == null) throw new IllegalArgumentException("Poll Question cannot be null"); Map<String, String> replacementValues = new HashMap<String, String>(); String from = (fromEmailAddress == null || fromEmailAddress.equals("")) ? serverConfigurationService.getString("smtpFrom@org.sakaiproject.email.api.EmailService") : fromEmailAddress; for (String userEid : userEids) { User user = null; try { user = userDirectoryService.getUserByEid(userEid); replacementValues.put("localSakaiName", developerHelperService.getConfigurationSetting("ui.service", "Sakai")); replacementValues.put("recipientFirstName",user.getFirstName()); replacementValues.put("pollQuestion", pollQuestion); replacementValues.put("siteTitle", siteTitle); RenderedTemplate template = emailTemplateService.getRenderedTemplateForUser(EMAIL_TEMPLATE_NOTIFY_DELETED_OPTION, user.getReference(), replacementValues); if (template == null) return; String content = template.getRenderedMessage(), subject = template.getRenderedSubject(); emailService.send(from, user.getEmail(), subject, content, user.getEmail(), from, null); } catch (UserNotDefinedException e) { log.warn("Attempted to send email to unknown user (eid): '"+userEid+"'", e); } } } /** * Load the mail template described by the XML in file 'fileName' into the emailTemplateService, * identified by 'key' * * @param key * The key that identifies the template * @param fileName * The filename that holds the template information * @throws ParserConfigurationException * @throws IOException * @throws InvalidEmailTemplateException * Thrown if the email template is not a valid format. */ private void loadMailTemplate(String key, String fileName) throws ParserConfigurationException, IOException, InvalidEmailTemplateException { Session session = null; try { session = sessionManager.getCurrentSession(); session.setUserId(USER_ADMIN_ID); session.setUserEid(USER_ADMIN_EID); try { NodeList templates = getEmailTemplates(FILE_NOTIFY_DELETED_OPTION_TEMPLATE); int n = templates.getLength(); for (int i = 0; i < n; i++) { xmlToTemplate((Element)templates.item(i), key); } } catch (SAXException e) { throw new InvalidEmailTemplateException(key, fileName, e); } catch (InvalidEmailTemplateException e) { //'e' doesn't have all the information to throw here. throw new InvalidEmailTemplateException(key, fileName); } } finally { if (session != null) { session.setUserId(null); session.setUserEid(null); } } } /** * Given the XML template node, load it into the Email Template Service as a template * identified by 'key' * * @param xmlTemplate * The valid XML template to load * @param key * The key that should identify the template */ private void xmlToTemplate(Element xmlTemplate, String key) { String subject = getTagValue(xmlTemplate, "subject", ""), body = getTagValue(xmlTemplate, "message", ""), locale = getTagValue(xmlTemplate, "locale", ""), versionString = getTagValue(xmlTemplate, "version", ""); if (!emailTemplateService.templateExists(key, new Locale(locale))) { EmailTemplate template = new EmailTemplate(); template.setSubject(subject); template.setMessage(body); template.setLocale(locale); template.setKey(key); template.setVersion(Integer.valueOf(1)); template.setOwner(USER_ADMIN_ID); template.setLastModified(new Date()); this.emailTemplateService.saveTemplate(template); log.debug("Added email template: '"+key+"'"); } else { EmailTemplate existingTemplate = this.emailTemplateService.getEmailTemplate(key, new Locale(locale)); String oVersionString = existingTemplate.getVersion() != null ? existingTemplate.getVersion().toString():null; if ((oVersionString == null && versionString != null) || (oVersionString != null && versionString != null && !oVersionString.equals(versionString))) { Integer version = (versionString != null && !versionString.equals("")) ? Integer.valueOf(versionString) : Integer.valueOf(0); existingTemplate.setSubject(subject); existingTemplate.setMessage(body); existingTemplate.setLocale(locale); existingTemplate.setKey(key); existingTemplate.setVersion(version); existingTemplate.setOwner(USER_ADMIN_ID); existingTemplate.setLastModified(new Date()); this.emailTemplateService.updateTemplate(existingTemplate); log.debug("Updated email template: '"+key+"' to version "+version); } } } /** * Load a list of all the XML DOM elements that represent 'emailTemplate's. * * @param file * The file to parse * @return * A list of nodes (NodeList) that represent all the email templates within the file * @throws SAXException * @throws IOException * @throws ParserConfigurationException * @throws InvalidEmailTemplateException * Thrown if the XML template is not a valid email template definition * * TODO: Validate the XML email templates against a DTD to validate correctness */ private NodeList getEmailTemplates(String file) throws SAXException, IOException, ParserConfigurationException, InvalidEmailTemplateException { InputStream in = getClass().getClassLoader().getResourceAsStream(file); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(in); Element emailTemplates = doc.getDocumentElement(); if ("emailTemplates".equals(emailTemplates.getNodeName())) { return emailTemplates.getElementsByTagName("emailTemplate"); } else { throw new InvalidEmailTemplateException(null, file); } } /** * Convenience method to get the value of a particular tag within an XML element. * @param e * @param tagName * @return */ private String getTagValue(Element e, String tagName, String failover) { String value = failover; NodeList l = e.getElementsByTagName(tagName); if (l != null && l.getLength() > 0) { Element tag = (Element) l.item(0); if (tag != null) { Node n = tag.getFirstChild(); if (n != null) { value = n.getNodeValue(); } } } return value; } public ToolSession getCurrentToolSession() { return sessionManager.getCurrentToolSession(); } public boolean isMobileBrowser() { Session session = sessionManager.getCurrentSession(); if (session.getAttribute("is_wireless_device") != null && ((Boolean) session.getAttribute("is_wireless_device")).booleanValue()) { return true; } return false; } }