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.avalon.framework.context.Context; 029import org.apache.avalon.framework.context.ContextException; 030import org.apache.avalon.framework.context.Contextualizable; 031import org.apache.cocoon.components.ContextHelper; 032import org.apache.cocoon.environment.Request; 033import org.apache.commons.lang.StringUtils; 034import org.apache.excalibur.source.SourceResolver; 035 036import org.ametys.cms.repository.WorkflowAwareContent; 037import org.ametys.core.right.RightManager; 038import org.ametys.core.user.CurrentUserProvider; 039import org.ametys.core.user.User; 040import org.ametys.core.user.UserIdentity; 041import org.ametys.core.user.UserManager; 042import org.ametys.core.util.I18nUtils; 043import org.ametys.core.util.mail.SendMailHelper; 044import org.ametys.plugins.workflow.support.WorkflowProvider; 045import org.ametys.runtime.config.Config; 046import org.ametys.runtime.i18n.I18nizableText; 047import org.ametys.runtime.plugin.component.PluginAware; 048 049import com.opensymphony.module.propertyset.PropertySet; 050import com.opensymphony.workflow.FunctionProvider; 051import com.opensymphony.workflow.WorkflowException; 052 053/** 054 * OS workflow function to send mail after an action is triggered. 055 */ 056public class SendMailFunction extends AbstractContentWorkflowComponent implements FunctionProvider, Initializable, PluginAware, Contextualizable 057{ 058 /** 059 * Provide "false" to prevent the function sending the mail. 060 * Useful when making large automatic workflow operations (for instance, when bulk importing and proposing in one action). 061 */ 062 public static final String SEND_MAIL = "send-mail"; 063 064 /** The rights key. */ 065 protected static final String RIGHTS_KEY = "rights"; 066 /** The mail subject key. */ 067 protected static final String SUBJECT_KEY = "subjectKey"; 068 /** The mail body key. */ 069 protected static final String BODY_KEY = "bodyKey"; 070 071 /** The current user provider. */ 072 protected CurrentUserProvider _currentUserProvider; 073 074 /** The rights manager. */ 075 protected RightManager _rightManager; 076 077 /** The users manager. */ 078 protected UserManager _userManager; 079 080 /** The source resolver. */ 081 protected SourceResolver _sourceResolver; 082 083 /** The workflow. */ 084 protected WorkflowProvider _workflowProvider; 085 086 /** The Avalon context. */ 087 protected Context _context; 088 089 /** The plugin name. */ 090 protected String _pluginName; 091 092 /** I18nUtils */ 093 protected I18nUtils _i18nUtils; 094 095 @Override 096 public void initialize() throws Exception 097 { 098 _currentUserProvider = (CurrentUserProvider) _manager.lookup(CurrentUserProvider.ROLE); 099 _rightManager = (RightManager) _manager.lookup(RightManager.ROLE); 100 _userManager = (UserManager) _manager.lookup(UserManager.ROLE); 101 _sourceResolver = (SourceResolver) _manager.lookup(SourceResolver.ROLE); 102 _workflowProvider = (WorkflowProvider) _manager.lookup(WorkflowProvider.ROLE); 103 _i18nUtils = (I18nUtils) _manager.lookup(I18nUtils.ROLE); 104 } 105 106 public void contextualize(Context context) throws ContextException 107 { 108 _context = context; 109 } 110 111 @Override 112 public void setPluginInfo(String pluginName, String featureName, String id) 113 { 114 _pluginName = pluginName; 115 } 116 117 @Override 118 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 119 { 120 String rightsParam = StringUtils.defaultString((String) args.get(RIGHTS_KEY)); 121 String subjectI18nKey = StringUtils.defaultString((String) args.get(SUBJECT_KEY)); 122 String bodyI18nKey = StringUtils.defaultString((String) args.get(BODY_KEY)); 123 124 Set<String> rights = new HashSet<>(); 125 for (String right : rightsParam.split(",")) 126 { 127 if (StringUtils.isNotBlank(right)) 128 { 129 rights.add(right.trim()); 130 } 131 } 132 133 // If "send-mail" is set to true or is not present in the vars, send the mail. 134 boolean dontSendMail = "false".equals(transientVars.get(SEND_MAIL)); 135 136 if (dontSendMail) 137 { 138 return; 139 } 140 141 try 142 { 143 WorkflowAwareContent content = getContent(transientVars); 144 UserIdentity userIdentity = getUser(transientVars); 145 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 146 147 Set<UserIdentity> users = _getUsers(content, rights); 148 149 if (users.size() > 0) 150 { 151 String mailSubject = getMailSubject(subjectI18nKey, user, content); 152 String mailBody = getMailBody(bodyI18nKey, user, content, transientVars); 153 154 _sendMails(mailSubject, mailBody, users, user.getEmail()); 155 } 156 } 157 catch (Exception e) 158 { 159 _logger.error("An error occurred: unable to send mail to notify workflow change.", e); 160 } 161 } 162 163 /** 164 * Get the subject of mail 165 * @param subjectI18nKey the i18n key to use for subject 166 * @param user the caller 167 * @param content the content 168 * @return the subject 169 */ 170 protected String getMailSubject (String subjectI18nKey, User user, WorkflowAwareContent content) 171 { 172 I18nizableText subjectKey = new I18nizableText(null, subjectI18nKey, getSubjectI18nParams(user, content)); 173 return _i18nUtils.translate(subjectKey, null); // FIXME Use user preference language 174 } 175 176 /** 177 * Get the text body of mail 178 * @param bodyI18nKey the i18n key to use for body 179 * @param user the caller 180 * @param content the content 181 * @param transientVars the transient variables 182 * @return the text body 183 */ 184 protected String getMailBody (String bodyI18nKey, User user, WorkflowAwareContent content, Map transientVars) 185 { 186 I18nizableText bodyKey = new I18nizableText(null, bodyI18nKey, getBodyI18nParams(user, content)); 187 String mailBody = _i18nUtils.translate(bodyKey, null); // FIXME Use user preference language 188 189 // Get the workflow comment 190 String comment = (String) transientVars.get("comment"); 191 if (StringUtils.isNotEmpty(comment)) 192 { 193 List<String> params = new ArrayList<>(); 194 params.add(comment); 195 196 I18nizableText commentKey = new I18nizableText("plugin.cms", "WORKFLOW_MAIL_BODY_USER_COMMENT", params); 197 String commentTxt = _i18nUtils.translate(commentKey, null); // FIXME Use user preference language 198 199 mailBody += "\n\n" + commentTxt; 200 } 201 202 return mailBody; 203 } 204 205 /** 206 * Send the notification emails. 207 * @param subject the e-mail subject. 208 * @param body the e-mail body. 209 * @param users users to send the mail to. 210 * @param from the address sending the e-mail. 211 */ 212 protected void _sendMails(String subject, String body, Set<UserIdentity> users, String from) 213 { 214 for (UserIdentity userIdentity : users) 215 { 216 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 217 if (user != null && StringUtils.isNotBlank(user.getEmail())) 218 { 219 String mail = user.getEmail(); 220 221 try 222 { 223 SendMailHelper.sendMail(subject, null, body, mail, from, true); 224 } 225 catch (MessagingException e) 226 { 227 _logger.warn("Could not send a workflow notification mail to " + mail, e); 228 } 229 } 230 } 231 } 232 233 /** 234 * Get the i18n parameters of mail subject 235 * @param user the caller 236 * @param content the content 237 * @return the i18n parameters 238 */ 239 protected List<String> getSubjectI18nParams (User user, WorkflowAwareContent content) 240 { 241 List<String> params = new ArrayList<>(); 242 params.add(_contentHelper.getTitle(content)); 243 return params; 244 } 245 246 /** 247 * Get the i18n parameters of mail body text 248 * @param user the caller 249 * @param content the content 250 * @return the i18n parameters 251 */ 252 protected List<String> getBodyI18nParams (User user, WorkflowAwareContent content) 253 { 254 List<String> params = new ArrayList<>(); 255 256 params.add(user.getFullName()); // {0} 257 params.add(content.getTitle()); // {1} 258 params.add(_getContentUri(content)); // {2} 259 260 return params; 261 } 262 263 /** 264 * Get the content uri 265 * @param content the content 266 * @return the content uri 267 */ 268 protected String _getContentUri(WorkflowAwareContent content) 269 { 270 String requestUri = _getRequestUri(); 271 return requestUri + "/index.html?uitool=uitool-content,id:%27" + content.getId() + "%27"; 272 } 273 274 /** 275 * Get the request URI. 276 * @return the full request URI. 277 */ 278 protected String _getRequestUri() 279 { 280 return StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/"); 281 } 282 283 /** 284 * Retrieve the request from which this component is called. 285 * @return the request or <code>null</code>. 286 */ 287 public Request _getRequest() 288 { 289 try 290 { 291 return (Request) _context.get(ContextHelper.CONTEXT_REQUEST_OBJECT); 292 } 293 catch (ContextException ce) 294 { 295 _logger.info("Unable to get the request", ce); 296 return null; 297 } 298 } 299 300 /** 301 * Get the user logins. 302 * @param content the content. 303 * @param rights the set of rights to check. 304 * @return the users. 305 * @throws WorkflowException If an error occurred 306 */ 307 protected Set<UserIdentity> _getUsers(WorkflowAwareContent content, Set<String> rights) throws WorkflowException 308 { 309 Set<UserIdentity> users = new HashSet<>(); 310 311 Iterator<String> rightIt = rights.iterator(); 312 313 // First right : add all the granted users. 314 if (rightIt.hasNext()) 315 { 316 users.addAll(_rightManager.getAllowedUsers(rightIt.next(), content).resolveAllowedUsers(Config.getInstance().getValueAsBoolean("runtime.mail.massive.sending"))); 317 } 318 319 // Next rights : retain all the granted users. 320 while (rightIt.hasNext()) 321 { 322 users.retainAll(_rightManager.getAllowedUsers(rightIt.next(), content).resolveAllowedUsers(Config.getInstance().getValueAsBoolean("runtime.mail.massive.sending"))); 323 } 324 325 return users; 326 } 327}