001/*
002 *  Copyright 2022 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.workspaces.project.notification;
017
018import java.io.ByteArrayOutputStream;
019import java.io.IOException;
020import java.io.InputStream;
021import java.util.Collection;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025import java.util.stream.Collectors;
026
027import org.apache.cocoon.environment.Request;
028import org.apache.commons.lang.StringUtils;
029import org.apache.excalibur.source.Source;
030import org.apache.excalibur.source.SourceUtil;
031
032import org.ametys.cms.contenttype.ContentTypesHelper;
033import org.ametys.cms.repository.Content;
034import org.ametys.cms.repository.WorkflowAwareContent;
035import org.ametys.core.user.User;
036import org.ametys.core.user.UserIdentity;
037import org.ametys.core.util.mail.SendMailHelper;
038import org.ametys.plugins.workspaces.WorkspacesConstants;
039import org.ametys.plugins.workspaces.project.ProjectManager;
040import org.ametys.plugins.workspaces.project.notification.preferences.NotificationPreferencesHelper;
041import org.ametys.plugins.workspaces.project.notification.preferences.NotificationPreferencesHelper.Frequency;
042import org.ametys.plugins.workspaces.project.objects.Project;
043import org.ametys.runtime.config.Config;
044import org.ametys.web.WebConstants;
045import org.ametys.web.renderingcontext.RenderingContext;
046import org.ametys.web.renderingcontext.RenderingContextHandler;
047import org.ametys.web.repository.content.WebContent;
048import org.ametys.web.repository.site.Site;
049import org.ametys.web.workflow.SendMailFunction;
050
051import com.google.common.collect.Iterables;
052import com.opensymphony.workflow.WorkflowException;
053
054import jakarta.mail.MessagingException;
055
056/**
057 * Function to notify news publication
058 *
059 */
060public class SendNewsPublicationNotificationFunction extends SendMailFunction
061{
062    private RenderingContextHandler _renderingContextHandler;
063    private ContentTypesHelper _contentTypeHelper;
064    private ProjectManager _projectManager;
065    private NotificationPreferencesHelper _notificationPrefHelper;
066
067    @Override
068    public void initialize() throws Exception
069    {
070        super.initialize();
071        _renderingContextHandler = (RenderingContextHandler) _manager.lookup(RenderingContextHandler.ROLE);
072        _contentTypeHelper = (ContentTypesHelper) _manager.lookup(ContentTypesHelper.ROLE);
073        _projectManager = (ProjectManager) _manager.lookup(ProjectManager.ROLE);
074        _notificationPrefHelper = (NotificationPreferencesHelper) _manager.lookup(NotificationPreferencesHelper.ROLE);
075    }
076    
077    @Override
078    protected List<String> getSubjectI18nParams(User user, WorkflowAwareContent content)
079    {
080        List<String> params = super.getSubjectI18nParams(user, content);
081        Project project = _getProject(content);
082        if (project != null)
083        {
084            params.add(project.getTitle());  // {3}
085        }
086        return params;
087    }
088    
089    @Override
090    protected String getMailBody(String bodyI18nKey, User user, WorkflowAwareContent content, Map transientVars)
091    {
092        Request request = _getRequest();
093        
094        Source source = null;
095        RenderingContext currentContext = _renderingContextHandler.getRenderingContext();
096        
097        try
098        {
099            if (content instanceof WebContent && _contentTypeHelper.isInstanceOf(content, WorkspacesConstants.PROJECT_NEWS_CONTENT_TYPE_ID))
100            {
101                // Force rendering context.FRONT to resolve URI
102                _renderingContextHandler.setRenderingContext(RenderingContext.FRONT);
103                request.setAttribute("forceAbsoluteUrl", true);
104                request.setAttribute("lang", content.getLanguage());
105                
106                Site site = ((WebContent) content).getSite();
107                request.setAttribute(WebConstants.REQUEST_ATTR_SITE, site);
108                request.setAttribute(WebConstants.REQUEST_ATTR_SITE_NAME, site.getName());
109                request.setAttribute(WebConstants.REQUEST_ATTR_SKIN_ID, site.getSkinId());
110                request.setAttribute("forceBase64Encoding", true);
111                
112                source = _sourceResolver.resolveURI("cocoon://_plugins/workspaces/notification-mail-news-publication", null, Map.of("content", content, "issuer", user, "project", _getProject(content)));
113                
114                try (InputStream is = source.getInputStream())
115                {
116                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
117                    SourceUtil.copy(is, bos);
118                    return bos.toString("UTF-8");
119                }
120            }
121        }
122        catch (IOException e)
123        {
124            _logger.error("Fail to get mail body for news publication.", e);
125        }
126        finally
127        {
128            request.removeAttribute("forceBase64Encoding");
129            
130            _renderingContextHandler.setRenderingContext(currentContext);
131            if (source != null)
132            {
133                _sourceResolver.release(source);
134            }
135        }
136        
137        return null;
138    }
139    
140    private Project _getProject(Content content)
141    {
142        if (content instanceof WebContent)
143        {
144            Site site = ((WebContent) content).getSite();
145            return Iterables.getFirst(_projectManager.getProjectsForSite(site), null);
146        }
147        return null;
148    }
149    
150    @Override
151    protected void _sendMails(String subject, String body, Set<String> recipients, String from)
152    {
153        if (StringUtils.isNotEmpty(body))
154        {
155            for (String recipient : recipients)
156            {
157                try
158                {
159                    SendMailHelper.newMail()
160                                  .withSubject(subject)
161                                  .withHTMLBody(body)
162                                  .withSender(from)
163                                  .withRecipient(recipient)
164                                  .withAsync(true)
165                                  .withInlineCSS(false)
166                                  .sendMail();
167                }
168                catch (MessagingException | IOException e)
169                {
170                    _logger.warn("Could not send a workflow notification mail to " + recipient, e);
171                }
172            }
173        }
174    }
175    
176    @Override
177    protected Set<UserIdentity> _getUsers(WorkflowAwareContent content, Set<String> rights) throws WorkflowException
178    {
179        boolean returnAll = Config.getInstance().getValue("runtime.mail.massive.sending");
180        Collection<UserIdentity> allowedUsers = _rightManager.getReadAccessAllowedUsers(content).resolveAllowedUsers(returnAll); 
181        
182        return allowedUsers.stream()
183            .filter(userId -> _notificationPrefHelper.askedToBeNotified(userId, _getProject(content).getName(), Frequency.EACH))
184            .collect(Collectors.toSet());
185    }
186}