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