001/*
002 *  Copyright 2019 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.ugc.observation;
017
018import java.io.IOException;
019import java.time.ZoneId;
020import java.time.ZonedDateTime;
021import java.time.format.FormatStyle;
022import java.util.Collection;
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.avalon.framework.configuration.Configurable;
027import org.apache.avalon.framework.configuration.Configuration;
028import org.apache.avalon.framework.configuration.ConfigurationException;
029import org.apache.avalon.framework.logger.AbstractLogEnabled;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.commons.lang.StringUtils;
034
035import org.ametys.cms.contenttype.ContentTypesHelper;
036import org.ametys.cms.repository.Content;
037import org.ametys.core.observation.Observer;
038import org.ametys.core.user.User;
039import org.ametys.core.user.UserIdentity;
040import org.ametys.core.user.UserManager;
041import org.ametys.core.user.population.UserPopulationDAO;
042import org.ametys.core.util.I18nUtils;
043import org.ametys.core.util.mail.SendMailHelper;
044import org.ametys.plugins.ugc.UGCConstants;
045import org.ametys.runtime.config.Config;
046import org.ametys.runtime.i18n.I18nizableDateTime;
047import org.ametys.runtime.i18n.I18nizableText;
048import org.ametys.runtime.i18n.I18nizableTextParameter;
049import org.ametys.web.repository.content.WebContent;
050import org.ametys.web.repository.page.Page;
051import org.ametys.web.repository.site.Site;
052
053import jakarta.mail.MessagingException;
054
055/**
056 * Abstract observer to send mail to UGC author on UGC content event
057 *
058 */
059public abstract class AbstractUGCContentObserver extends AbstractLogEnabled implements Observer, Serviceable, Configurable
060{
061    /** The content type helper */
062    protected ContentTypesHelper _cTypeHelper;
063    /** The i18n utils */
064    protected I18nUtils _i18nUtils;
065    /** The user manager */
066    protected UserManager _userManager;
067    
068    /** The i18n key for mail subject */
069    protected String _subjectI18nKey;
070    /** The i18n key for mail body */
071    protected String _bodyI18nKey;
072    
073    @Override
074    public void service(ServiceManager smanager) throws ServiceException
075    {
076        _cTypeHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE);
077        _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE);
078        _userManager = (UserManager) smanager.lookup(UserManager.ROLE);
079    }
080    
081    public void configure(Configuration configuration) throws ConfigurationException
082    {
083        _subjectI18nKey = configuration.getChild("mailSubjectKey").getValue(null);
084        _bodyI18nKey = configuration.getChild("mailBodyKey").getValue(null);
085    }
086    
087    @Override
088    public int getPriority()
089    {
090        return MIN_PRIORITY;
091    }
092    
093    /**
094     * Send mail to the UGC author
095     * @param ugcContent The UGC content
096     * @param comment The comment. Can be null.
097     */
098    protected void sendMailToUGCAuthor(Content ugcContent, String comment)
099    {
100        String recipient = ugcContent.getValue(UGCConstants.ATTRIBUTE_PATH_UGC_MAIL, false, null);
101        if (StringUtils.isNotBlank(recipient))
102        {
103            String language = getMailLanguage(ugcContent);
104            String sender = Config.getInstance().getValue("smtp.mail.from");
105            if (ugcContent instanceof WebContent)
106            {
107                Site site = ((WebContent) ugcContent).getSite();
108                sender = site.getValue("site-mail-from", false, Config.getInstance().getValue("smtp.mail.from"));
109            }
110            
111            String subject = getMailSubject(ugcContent, language);
112            String body = getMailBody(ugcContent, comment, language);
113            
114            try
115            {
116                SendMailHelper.newMail()
117                              .withSubject(subject)
118                              .withTextBody(body)
119                              .withSender(sender)
120                              .withRecipient(recipient)
121                              .withAsync(true)
122                              .sendMail();
123            }
124            catch (MessagingException | IOException e)
125            {
126                getLogger().warn("Fail to send UGC content notification mail to " + recipient, e);
127            }
128        }
129    }
130    
131    /**
132     * Get the mail language
133     * @param ugcContent The UGC content
134     * @return the language to use in the mail or null if none was found
135     */
136    protected String getMailLanguage(Content ugcContent)
137    {
138        String language = null;
139        UserIdentity userIdentity = ugcContent.getCreator();
140        if (userIdentity != null && !UserPopulationDAO.SYSTEM_USER_IDENTITY.equals(userIdentity))
141        {
142            User user = _userManager.getUser(userIdentity);
143            if (user != null)
144            {
145                language = user.getLanguage();
146            }
147        }
148        
149        // ugc content language can also be null
150        return StringUtils.defaultIfEmpty(language, ugcContent.getLanguage());
151    }
152    
153    /**
154     * Get the mail subject
155     * @param ugcContent The UGC content
156     * @param language The language to use
157     * @return the mail text subject
158     */
159    protected String getMailSubject (Content ugcContent, String language)
160    {
161        I18nizableText subjectKey = new I18nizableText(null, _subjectI18nKey, getSubjectI18nParams(ugcContent));
162        return _i18nUtils.translate(subjectKey, language);
163    }
164    
165    /**
166     * Get the mail body
167     * @param ugcContent The UGC content
168     * @param comment The comment. Can be null.
169     * @param language The language to use
170     * @return the mail text body
171     */
172    protected String getMailBody (Content ugcContent, String comment, String language)
173    {
174        I18nizableText bodyKey = new I18nizableText(null, _bodyI18nKey, getBodyI18nParams(ugcContent, comment));
175        return _i18nUtils.translate(bodyKey, language);
176    }
177    
178    /**
179     * Get the i18n parameters for mail subject
180     * @param ugcContent The UGC content
181     * @return the i18n parameters for mail subject
182     */
183    protected Map<String, I18nizableTextParameter> getSubjectI18nParams(Content ugcContent)
184    {
185        Map<String, I18nizableTextParameter> params = new HashMap<>();
186        
187        params.put("contentTitle", new I18nizableText(ugcContent.getTitle()));
188        if (ugcContent instanceof WebContent)
189        {
190            Site site = ((WebContent) ugcContent).getSite();
191            params.put("siteTitle", new I18nizableText(site.getTitle()));
192        }
193        
194        return params;
195    }
196    
197    /**
198     * Get the i18n parameters for mail body
199     * @param ugcContent The UGC content
200     * @param comment The comment. Can be null.
201     * @return the i18n parameters for mail body
202     */
203    protected Map<String, I18nizableTextParameter> getBodyI18nParams(Content ugcContent, String comment)
204    {
205        Map<String, I18nizableTextParameter> params = new HashMap<>();
206        
207        String authorFullName = ugcContent.getValue(UGCConstants.ATTRIBUTE_PATH_UGC_AUTHOR, false, null);
208        params.put("authorFullName", new I18nizableText(authorFullName));
209        
210        params.put("contentTitle", new I18nizableText(ugcContent.getTitle()));
211        
212        if (ugcContent instanceof WebContent)
213        {
214            Site site = ((WebContent) ugcContent).getSite();
215            params.put("siteTitle", new I18nizableText(site.getTitle()));
216            params.put("siteUrl", new I18nizableText(site.getUrl()));
217            
218            Collection<Page> pages = ((WebContent) ugcContent).getReferencingPages();
219            if (!pages.isEmpty())
220            {
221                Page page = pages.iterator().next();
222                String uri = site.getUrl() + "/" + page.getSitemapName() + "/" + page.getPathInSitemap() + ".html";
223                params.put("uri", new I18nizableText(uri));
224            }
225        }
226        
227        ZonedDateTime creationDate = ugcContent.getCreationDate();
228        params.put("creationDate", new I18nizableDateTime(creationDate, ZoneId.from(creationDate), FormatStyle.LONG));
229        
230        if (StringUtils.isNotBlank(comment))
231        {
232            params.put("comment", new I18nizableText(comment));
233        }
234        
235        return params;
236    }
237}