001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.workflow; 017 018import java.util.ArrayList; 019import java.util.HashSet; 020import java.util.Iterator; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import javax.mail.MessagingException; 026 027import org.apache.avalon.framework.activity.Initializable; 028import org.apache.commons.lang.StringUtils; 029import org.apache.excalibur.source.SourceResolver; 030 031import org.ametys.cms.repository.WorkflowAwareContent; 032import org.ametys.core.right.RightManager; 033import org.ametys.core.user.CurrentUserProvider; 034import org.ametys.core.user.User; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.core.user.UserManager; 037import org.ametys.core.util.I18nUtils; 038import org.ametys.core.util.mail.SendMailHelper; 039import org.ametys.plugins.workflow.support.WorkflowProvider; 040import org.ametys.runtime.config.Config; 041import org.ametys.runtime.i18n.I18nizableText; 042import org.ametys.runtime.plugin.component.PluginAware; 043 044import com.opensymphony.module.propertyset.PropertySet; 045import com.opensymphony.workflow.FunctionProvider; 046import com.opensymphony.workflow.WorkflowException; 047 048/** 049 * OS workflow function to send mail after an action is triggered. 050 */ 051public class SendMailFunction extends AbstractContentWorkflowComponent implements FunctionProvider, Initializable, PluginAware 052{ 053 /** 054 * Provide "false" to prevent the function sending the mail. 055 * Useful when making large automatic workflow operations (for instance, when bulk importing and proposing in one action). 056 */ 057 public static final String SEND_MAIL = "send-mail"; 058 059 /** The rights key. */ 060 protected static final String RIGHTS_KEY = "rights"; 061 /** The mail subject key. */ 062 protected static final String SUBJECT_KEY = "subjectKey"; 063 /** The mail body key. */ 064 protected static final String BODY_KEY = "bodyKey"; 065 066 /** The current user provider. */ 067 protected CurrentUserProvider _currentUserProvider; 068 069 /** The rights manager. */ 070 protected RightManager _rightManager; 071 072 /** The users manager. */ 073 protected UserManager _userManager; 074 075 /** The source resolver. */ 076 protected SourceResolver _sourceResolver; 077 078 /** The workflow. */ 079 protected WorkflowProvider _workflowProvider; 080 081 /** The plugin name. */ 082 protected String _pluginName; 083 084 /** I18nUtils */ 085 protected I18nUtils _i18nUtils; 086 087 @Override 088 public void initialize() throws Exception 089 { 090 _currentUserProvider = (CurrentUserProvider) _manager.lookup(CurrentUserProvider.ROLE); 091 _rightManager = (RightManager) _manager.lookup(RightManager.ROLE); 092 _userManager = (UserManager) _manager.lookup(UserManager.ROLE); 093 _sourceResolver = (SourceResolver) _manager.lookup(SourceResolver.ROLE); 094 _workflowProvider = (WorkflowProvider) _manager.lookup(WorkflowProvider.ROLE); 095 _i18nUtils = (I18nUtils) _manager.lookup(I18nUtils.ROLE); 096 } 097 098 @Override 099 public void setPluginInfo(String pluginName, String featureName, String id) 100 { 101 _pluginName = pluginName; 102 } 103 104 @Override 105 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 106 { 107 String rightsParam = StringUtils.defaultString((String) args.get(RIGHTS_KEY)); 108 String subjectI18nKey = StringUtils.defaultString((String) args.get(SUBJECT_KEY)); 109 String bodyI18nKey = StringUtils.defaultString((String) args.get(BODY_KEY)); 110 111 Set<String> rights = new HashSet<>(); 112 for (String right : rightsParam.split(",")) 113 { 114 if (StringUtils.isNotBlank(right)) 115 { 116 rights.add(right.trim()); 117 } 118 } 119 120 // If "send-mail" is set to true or is not present in the vars, send the mail. 121 boolean dontSendMail = "false".equals(transientVars.get(SEND_MAIL)); 122 123 if (dontSendMail) 124 { 125 return; 126 } 127 128 try 129 { 130 WorkflowAwareContent content = getContent(transientVars); 131 UserIdentity userIdentity = getUser(transientVars); 132 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 133 134 Set<UserIdentity> users = _getUsers(content, rights); 135 136 String mailSubject = getMailSubject(subjectI18nKey, user, content); 137 String mailBody = getMailBody(bodyI18nKey, user, content, transientVars); 138 139 _sendMails(mailSubject, mailBody, users, user.getEmail()); 140 } 141 catch (Exception e) 142 { 143 _logger.error("An error occurred: unable to send mail to notify workflow change.", e); 144 } 145 } 146 147 /** 148 * Get the subject of mail 149 * @param subjectI18nKey the i18n key to use for subject 150 * @param user the caller 151 * @param content the content 152 * @return the subject 153 */ 154 protected String getMailSubject (String subjectI18nKey, User user, WorkflowAwareContent content) 155 { 156 I18nizableText subjectKey = new I18nizableText(null, subjectI18nKey, getSubjectI18nParams(user, content)); 157 return _i18nUtils.translate(subjectKey, null); // FIXME Use user preference language 158 } 159 160 /** 161 * Get the text body of mail 162 * @param bodyI18nKey the i18n key to use for body 163 * @param user the caller 164 * @param content the content 165 * @param transientVars the transient variables 166 * @return the text body 167 */ 168 protected String getMailBody (String bodyI18nKey, User user, WorkflowAwareContent content, Map transientVars) 169 { 170 I18nizableText bodyKey = new I18nizableText(null, bodyI18nKey, getBodyI18nParams(user, content)); 171 String mailBody = _i18nUtils.translate(bodyKey, null); // FIXME Use user preference language 172 173 // Get the workflow comment 174 String comment = (String) transientVars.get("comment"); 175 if (StringUtils.isNotEmpty(comment)) 176 { 177 List<String> params = new ArrayList<>(); 178 params.add(comment); 179 180 I18nizableText commentKey = new I18nizableText("plugin.cms", "WORKFLOW_MAIL_BODY_USER_COMMENT", params); 181 String commentTxt = _i18nUtils.translate(commentKey, null); // FIXME Use user preference language 182 183 mailBody += "\n\n" + commentTxt; 184 } 185 186 return mailBody; 187 } 188 189 /** 190 * Send the notification emails. 191 * @param subject the e-mail subject. 192 * @param body the e-mail body. 193 * @param users users to send the mail to. 194 * @param from the address sending the e-mail. 195 */ 196 protected void _sendMails(String subject, String body, Set<UserIdentity> users, String from) 197 { 198 for (UserIdentity userIdentity : users) 199 { 200 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 201 if (user != null && StringUtils.isNotBlank(user.getEmail())) 202 { 203 String mail = user.getEmail(); 204 205 try 206 { 207 SendMailHelper.sendMail(subject, null, body, mail, from); 208 } 209 catch (MessagingException e) 210 { 211 _logger.warn("Could not send a workflow notification mail to " + mail, e); 212 } 213 } 214 } 215 } 216 217 /** 218 * Get the i18n parameters of mail subject 219 * @param user the caller 220 * @param content the content 221 * @return the i18n parameters 222 */ 223 protected List<String> getSubjectI18nParams (User user, WorkflowAwareContent content) 224 { 225 List<String> params = new ArrayList<>(); 226 params.add(content.getTitle()); 227 return params; 228 } 229 230 /** 231 * Get the i18n parameters of mail body text 232 * @param user the caller 233 * @param content the content 234 * @return the i18n parameters 235 */ 236 protected List<String> getBodyI18nParams (User user, WorkflowAwareContent content) 237 { 238 List<String> params = new ArrayList<>(); 239 240 params.add(user.getFullName()); // {0} 241 params.add(content.getTitle()); // {1} 242 243 String requestUri = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/"); 244 params.add(requestUri + "/index.html?uitool=uitool-content,id:%27" + content.getId() + "%27"); // {2} 245 246 return params; 247 } 248 249 /** 250 * Get the user logins. 251 * @param content the content. 252 * @param rights the set of rights to check. 253 * @return the users. 254 * @throws WorkflowException If an error occurred 255 */ 256 protected Set<UserIdentity> _getUsers(WorkflowAwareContent content, Set<String> rights) throws WorkflowException 257 { 258 Set<UserIdentity> users = new HashSet<>(); 259 260 Iterator<String> rightIt = rights.iterator(); 261 262 // First right : add all the granted users. 263 if (rightIt.hasNext()) 264 { 265 users.addAll(_rightManager.getAllowedUsers(rightIt.next(), content).resolveAllowedUsers(Config.getInstance().getValueAsBoolean("runtime.mail.massive.sending"))); 266 } 267 268 // Next rights : retain all the granted users. 269 while (rightIt.hasNext()) 270 { 271 users.retainAll(_rightManager.getAllowedUsers(rightIt.next(), content).resolveAllowedUsers(Config.getInstance().getValueAsBoolean("runtime.mail.massive.sending"))); 272 } 273 274 return users; 275 } 276}