001/*
002 *  Copyright 2017 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.plugins.bpm.workflowsdef;
017
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Map;
021
022import javax.mail.MessagingException;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.cocoon.components.ContextHelper;
032import org.apache.cocoon.environment.Request;
033import org.apache.commons.lang.StringUtils;
034
035import org.ametys.core.user.CurrentUserProvider;
036import org.ametys.core.user.User;
037import org.ametys.core.user.UserIdentity;
038import org.ametys.core.user.UserManager;
039import org.ametys.core.util.I18nUtils;
040import org.ametys.core.util.JSONUtils;
041import org.ametys.core.util.mail.SendMailHelper;
042import org.ametys.plugins.bpm.BPMWorkflowManager;
043import org.ametys.plugins.bpm.jcr.JCRWorkflowProcess;
044import org.ametys.runtime.config.Config;
045import org.ametys.runtime.i18n.I18nizableText;
046import org.ametys.runtime.plugin.component.AbstractLogEnabled;
047
048import com.opensymphony.module.propertyset.PropertySet;
049import com.opensymphony.workflow.FunctionProvider;
050import com.opensymphony.workflow.WorkflowException;
051/**
052 * Send mail to the users listed in the "users" argument. If the "sendToCreator" argument is present, the mail will also be send to the process creator
053 */
054public class SendProcessMailFunction extends AbstractLogEnabled implements Component, FunctionProvider, Serviceable, Contextualizable
055{
056    /** Actually send the email ? */
057    public static final String SEND_MAIL = "send-request-information-mail";
058    
059    /** The mail subject key. */
060    protected static final String SUBJECT_KEY = "subjectKey";
061    /** The mail body key. */
062    protected static final String BODY_KEY = "bodyKey";
063    
064    private static final String __CONFIG_FROM_MAIL = "smtp.mail.from";
065
066    private JSONUtils _jsonUtils;
067    private UserManager _userManager;
068    private I18nUtils _i18nUtils;
069    private Context _context;
070    private BPMWorkflowManager _bpmWorkflowManager;
071    private CurrentUserProvider _currentUserProvider;
072
073    @Override
074    public void contextualize(Context context) throws ContextException
075    {
076        _context = context;
077    }
078    
079    public void service(ServiceManager manager) throws ServiceException
080    {
081        _bpmWorkflowManager = (BPMWorkflowManager) manager.lookup(BPMWorkflowManager.ROLE);
082        _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE);
083        _userManager = (UserManager) manager.lookup(UserManager.ROLE);
084        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
085        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
086    }
087    
088    @Override
089    public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException
090    {
091        JCRWorkflowProcess process = (JCRWorkflowProcess) transientVars.getOrDefault("process", null);
092        if (process == null)
093        {
094            return;
095        }
096        
097        UserIdentity creator = process.getCreator();
098        User creatorUser = _userManager.getUser(creator);
099        
100        String subjectKey = (String) args.get(SUBJECT_KEY);
101        String bodyKey = (String) args.get(BODY_KEY);
102        String mailSubject = _getSubject(StringUtils.defaultString(subjectKey), process);
103        String mailBody = _getBody(StringUtils.defaultString(bodyKey), process, creatorUser);
104
105        if (mailSubject == null || mailBody == null)
106        {
107            return;
108        }
109
110        List<User> usersList = _getRecipients((String) args.getOrDefault("users", null), (String) args.getOrDefault("sendToCreator", null), creatorUser);
111        
112        String fromMail = Config.getInstance().getValueAsString(__CONFIG_FROM_MAIL);
113        
114        List<String> sentTo = new ArrayList<>();
115        for (User user : usersList)
116        {
117            String recipient = user.getEmail();
118            if (StringUtils.isNotEmpty(recipient) && !sentTo.contains(recipient))
119            {
120                try
121                {
122                    SendMailHelper.sendMail(mailSubject, null, mailBody, recipient, fromMail);
123                    sentTo.add(recipient);
124                }
125                catch (MessagingException e)
126                {
127                    getLogger().warn("Could not send a workflow notification mail to {}", recipient, e);
128                }
129            }
130        }
131        
132    }
133
134    private String _getSubject(String subjectI18nKey, JCRWorkflowProcess process)
135    {
136        List<String> subjectParams = new ArrayList<>();
137        subjectParams.add(process.getTitle());
138        try
139        {
140            String mailSubject = _i18nUtils.translate(new I18nizableText(null, subjectI18nKey, subjectParams), null); // {0}
141            if (mailSubject == null)
142            {
143                getLogger().error("Could not send email for the process workflow, unknown i18n key specified for subject {}", subjectI18nKey);
144            }
145            return mailSubject;
146        }
147        catch (Exception e)
148        {
149            getLogger().error("Could not send email for the process workflow, failed to translate i18n key specified for subject {}", subjectI18nKey, e);
150            return null;
151        }
152    }
153
154    private String _getBody(String bodyI18nKey, JCRWorkflowProcess process, User creatorUser)
155    {
156        List<String> bodyParams = new ArrayList<>();
157        
158        UserIdentity user = _currentUserProvider.getUser();
159        User currentUser = user != null ? _userManager.getUser(user) : null;
160        bodyParams.add(currentUser != null ? currentUser.getFullName() : ""); // {0}
161        bodyParams.add(creatorUser != null ? creatorUser.getFullName() : ""); // {1}
162        bodyParams.add(process.getTitle()); // {2}
163        
164        Request request = ContextHelper.getRequest(_context);
165        String siteName = request.getParameter("site");
166        if (siteName == null)
167        {
168            siteName = (String) request.getAttribute("site");
169        }
170        String lang = request.getParameter("lang");
171        if (lang == null)
172        {
173            lang = (String) request.getAttribute("sitemapLanguage");
174        }
175        
176        bodyParams.add(_bpmWorkflowManager.getProcessPageUrl(process, siteName, lang, true)); // {3}
177        
178        try
179        {
180            String mailBody  = _i18nUtils.translate(new I18nizableText(null, bodyI18nKey, bodyParams), null);
181            if (mailBody == null)
182            {
183                getLogger().error("Could not send email for the process workflow, unknown i18n key specified for body {}", bodyI18nKey);
184            }
185            return mailBody;
186        }
187        catch (Exception e)
188        {
189            getLogger().error("Could not send email for the process workflow, fail to translate i18n key specified for body {}", bodyI18nKey, e);
190            return null;
191        }
192    }
193
194    private List<User> _getRecipients(String users, String sendToCreator, User creatorUser)
195    {
196        List<User> usersList = new ArrayList<>();
197        
198        if (users != null)
199        {
200            for (Object obj : _jsonUtils.convertJsonToList(users))
201            {
202                @SuppressWarnings("unchecked")
203                Map<String, Object> grantedUser = (Map<String, Object>) obj;
204                String login = (String) grantedUser.get("login");
205                String populationId = (String) grantedUser.get("populationId");
206                
207                if (login != null && populationId != null)
208                {
209                    User user = _userManager.getUser(populationId, login);
210                    usersList.add(user);
211                }
212            }
213        }
214        else if ("true".equals(sendToCreator) && creatorUser != null)
215        {
216            usersList.add(creatorUser);
217        }
218        return usersList;
219    }
220}