001/*
002 *  Copyright 2021 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.joboffer.workflow;
017
018import java.io.IOException;
019import java.io.InputStreamReader;
020import java.io.Reader;
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.components.ContextHelper;
030import org.apache.cocoon.environment.Request;
031import org.apache.commons.io.IOUtils;
032import org.apache.commons.lang3.StringUtils;
033import org.apache.excalibur.source.Source;
034
035import org.ametys.cms.data.ContentValue;
036import org.ametys.cms.repository.Content;
037import org.ametys.cms.repository.WorkflowAwareContent;
038import org.ametys.core.ui.mail.StandardMailBodyHelper;
039import org.ametys.core.ui.mail.StandardMailBodyHelper.MailBodyBuilder;
040import org.ametys.core.user.User;
041import org.ametys.core.user.UserIdentity;
042import org.ametys.core.util.mail.SendMailHelper;
043import org.ametys.plugins.joboffer.JobOfferConstants;
044import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
045import org.ametys.runtime.config.Config;
046import org.ametys.runtime.i18n.I18nizableText;
047import org.ametys.web.WebHelper;
048import org.ametys.web.renderingcontext.RenderingContext;
049import org.ametys.web.renderingcontext.RenderingContextHandler;
050import org.ametys.web.repository.content.WebContent;
051import org.ametys.web.repository.site.Site;
052import org.ametys.web.workflow.SendMailFunction;
053
054import com.opensymphony.workflow.WorkflowException;
055
056import jakarta.mail.MessagingException;
057
058/**
059 * OS workflow function to send mail to person(s) in charge when a new application was submitted.
060 */
061public class SendMailToPersonInChargeFunction extends SendMailFunction
062{
063    private RenderingContextHandler _renderingContextHandler;
064
065    @Override
066    public void service(ServiceManager smanager) throws ServiceException
067    {
068        super.service(smanager);
069        _renderingContextHandler = (RenderingContextHandler) smanager.lookup(RenderingContextHandler.ROLE);
070    }
071    
072    
073    @Override
074    protected Set<UserIdentity> _getUsers(WorkflowAwareContent content, Set<String> rights) throws WorkflowException
075    {
076        if (content.hasDefinition(JobOfferConstants.JOB_APPLICATION_ATTRIBUTE_PATH_PERSON_IN_CHARGE))
077        {
078            UserIdentity[] personIncharge = content.getValue(JobOfferConstants.JOB_APPLICATION_ATTRIBUTE_PATH_PERSON_IN_CHARGE);
079            return personIncharge != null ? Set.of(personIncharge) : Set.of();
080        }
081        
082        return Set.of();
083    }
084    
085   
086    
087    @Override
088    protected String getSender(Map transientVars, WorkflowAwareContent content) throws WorkflowException
089    {
090        if (content instanceof WebContent)
091        {
092            Site site = ((WebContent) content).getSite();
093            return site.getValue("site-mail-from", false, Config.getInstance().getValue("smtp.mail.from"));
094        }
095        else
096        {
097            return Config.getInstance().getValue("smtp.mail.from");
098        }
099    }
100    
101    @Override
102    protected List<String> getSubjectI18nParams(User user, WorkflowAwareContent content)
103    {
104        ContentValue value = content.getValue(JobOfferConstants.JOB_APPLICATION_ATTRIBUTE_PATH_JOB_OFFER);
105        Content jobOffer = value.getContent();
106        
107        List<String> i18nParams = new ArrayList<>();
108        i18nParams.add(jobOffer.getTitle()); // {0}
109        i18nParams.add(jobOffer.getValue(JobOfferConstants.JOB_OFFER_ATTRIBUTE_PATH_REF_ID, false, "")); // {1}
110        
111        return i18nParams;
112    }
113    
114    @Override
115    protected String getMailBody(String subjectI18nKey, String bodyI18nKey, User user, WorkflowAwareContent content, Map transientVars)
116    {
117        Source src = null;
118
119        Request request = _getRequest();
120        String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
121        RenderingContext currentContext = _renderingContextHandler.getRenderingContext();
122        
123        try
124        {
125            // Force default workspace and BACK rendering context to resolve uri (application contents are never published in live)
126            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "default");
127            _renderingContextHandler.setRenderingContext(RenderingContext.PREVIEW);
128            
129            request.setAttribute("_baseServerPath", _getRequestUri());
130            
131            ContentValue jobOffer = content.getValue(JobOfferConstants.JOB_APPLICATION_ATTRIBUTE_PATH_JOB_OFFER);
132            Content jobOfferContent = jobOffer.getContent();
133            
134            Site site = _getSite(content);
135            String jobApplicationUri = _getContentUri(content, null, site);
136            
137            List<String> i18nParams = List.of(jobOfferContent.getTitle(), jobOfferContent.getValue(JobOfferConstants.JOB_OFFER_ATTRIBUTE_PATH_REF_ID, false, StringUtils.EMPTY));
138            
139            MailBodyBuilder bodyBuilder = StandardMailBodyHelper.newHTMLBody()
140                .withTitle(getMailSubject(subjectI18nKey, user, content, transientVars))
141                .addMessage(new I18nizableText("plugin.job-offer", "PLUGINS_JOB_OFFER_WORKFLOW_MAIL_BODY_INTRO", i18nParams))
142                .addMessage(new I18nizableText("plugin.job-offer", "PLUGINS_JOB_OFFER_WORKFLOW_MAIL_BODY_JOB_APPLICATION_LINK", List.of(jobApplicationUri)))
143                .addMessage(new I18nizableText("plugin.job-offer", "PLUGINS_JOB_OFFER_WORKFLOW_MAIL_BODY_TOOL_LINK", List.of(_getToolUri(site))))
144                .withLink(jobApplicationUri, new I18nizableText("plugin.job-offer", "PLUGINS_JOB_OFFER_WORKFLOW_MAIL_BODY_JOB_APPLICATION_LINK_TITLE"));
145            
146            String uri = "cocoon:/apply/mail.html";
147            Map<String, Object> parameters = new HashMap<>();
148            parameters.put("content", content);
149            parameters.put("uriPrefix", _getRequestUri());
150            parameters.put("siteName", _getSite(content).getName());
151
152            src = _sourceResolver.resolveURI(uri, null, parameters);
153            Reader reader = new InputStreamReader(src.getInputStream(), "UTF-8");
154            String details = IOUtils.toString(reader);
155            
156            bodyBuilder.withDetails(new I18nizableText("plugin.job-offer", "PLUGINS_JOB_OFFER_WORKFLOW_MAIL_BODY_JOB_APPLICATION"), details, false);
157            
158            return bodyBuilder.build();
159        }
160        catch (IOException e)
161        {
162            _logger.warn("Failed to get HTML body for mail notification for new application " + content.getId(), e);
163            return null;
164        }
165        finally
166        {
167            _sourceResolver.release(src);
168            
169            _renderingContextHandler.setRenderingContext(currentContext);
170            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWorkspace);
171        }
172    }
173    
174    /**
175     * Get the tool uri
176     * @param site the current site
177     * @return the tool uri
178     */
179    protected String _getToolUri(Site site)
180    {
181        String siteName;
182        if (site != null)
183        {
184            siteName = site.getName();
185        }
186        else
187        {
188            // fallback to the current site if no site is provided
189            siteName = WebHelper.getSiteName(ContextHelper.getRequest(_context));
190        }
191        
192        return _getRequestUri() + "/" + siteName + "/index.html?uitool=uitool-application-search,id:%27search-ui.job-applications%27";
193    }
194    
195    @Override
196    protected void _sendMails(String subject, String body, Set<String> recipients, String from)
197    {
198        if (body != null)
199        {
200            for (String recipient : recipients)
201            {
202                try
203                {
204                    SendMailHelper.newMail()
205                                  .withSubject(subject)
206                                  .withHTMLBody(body)
207                                  .withSender(from)
208                                  .withRecipient(recipient)
209                                  .withAsync(true)
210                                  .sendMail();
211                }
212                catch (MessagingException | IOException e)
213                {
214                    _logger.warn("Could not send a workflow notification mail to " + recipient, e);
215                }
216            }
217        }
218    }
219    
220    @Override
221    public I18nizableText getLabel()
222    {
223        return new I18nizableText("plugin.job-offer", "PLUGINS_JOB_OFFER_SEND_MAIL_TO_PERSON_IN_CHARGE_FUNCTION_LABEL");
224    }
225    
226}