001/*
002 *  Copyright 2018 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.actions;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.parameters.Parameters;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.cocoon.acting.ServiceableAction;
028import org.apache.cocoon.environment.ObjectModelHelper;
029import org.apache.cocoon.environment.Redirector;
030import org.apache.cocoon.environment.Request;
031import org.apache.cocoon.environment.SourceResolver;
032import org.apache.commons.lang.StringUtils;
033
034import org.ametys.cms.content.ContentHelper;
035import org.ametys.cms.contenttype.ContentType;
036import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
037import org.ametys.cms.contenttype.ContentTypesHelper;
038import org.ametys.cms.repository.Content;
039import org.ametys.cms.repository.WorkflowAwareContent;
040import org.ametys.core.captcha.CaptchaHelper;
041import org.ametys.core.cocoon.ActionResultGenerator;
042import org.ametys.core.ui.mail.StandardMailBodyHelper;
043import org.ametys.core.ui.mail.StandardMailBodyHelper.MailBodyBuilder;
044import org.ametys.core.user.CurrentUserProvider;
045import org.ametys.core.user.User;
046import org.ametys.core.user.UserIdentity;
047import org.ametys.core.user.UserManager;
048import org.ametys.core.util.I18nUtils;
049import org.ametys.core.util.JSONUtils;
050import org.ametys.core.util.mail.SendMailHelper;
051import org.ametys.plugins.repository.AmetysObjectResolver;
052import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder;
053import org.ametys.plugins.ugc.UGCConstants;
054import org.ametys.runtime.i18n.I18nizableText;
055import org.ametys.web.cache.PageHelper;
056import org.ametys.web.content.FOContentCreationHelper;
057import org.ametys.web.repository.content.WebContent;
058import org.ametys.web.repository.page.Page;
059import org.ametys.web.repository.page.ZoneItem;
060import org.ametys.web.repository.site.Site;
061
062import com.google.common.collect.ArrayListMultimap;
063import com.google.common.collect.Multimap;
064
065import jakarta.mail.MessagingException;
066
067/**
068 * Create content action
069 */
070public class ProposeContentAction extends ServiceableAction
071{  
072    private static final int _INITIAL_ACTION_ID = 1111;
073    
074    /** Ametys object resolver. */
075    protected AmetysObjectResolver _resolver;
076    
077    /** The content type extension point */
078    protected ContentTypeExtensionPoint _cTypeEP;
079    
080    /** The content type helper */
081    protected ContentTypesHelper _contentTypeHelper;
082    
083    /** The JSON Utils */
084    protected JSONUtils _jsonUtils;
085    
086    /** The current user provider */
087    protected CurrentUserProvider _currentUserProvider;
088    
089    /** The I18n utils */
090    protected I18nUtils _i18nUtils;
091
092    /** The user manager */
093    protected UserManager _userManager;
094
095    /** Helper for FO content creation */
096    protected FOContentCreationHelper _foContentCreationHelper;
097    
098    /** The page helper */
099    protected PageHelper _pageHelper;
100
101    /** The content helper */
102    protected ContentHelper _contentHelper;
103    
104    @Override
105    public void service(ServiceManager serviceManager) throws ServiceException
106    {
107        super.service(serviceManager);
108        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
109        _cTypeEP = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE);
110        _contentTypeHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE);
111        _jsonUtils = (JSONUtils) serviceManager.lookup(JSONUtils.ROLE);
112        _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE);
113        _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE);
114        _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE);
115        _foContentCreationHelper = (FOContentCreationHelper) serviceManager.lookup(FOContentCreationHelper.ROLE);
116        _pageHelper = (PageHelper) serviceManager.lookup(PageHelper.ROLE);
117        _contentHelper = (ContentHelper) serviceManager.lookup(ContentHelper.ROLE);
118    }
119    
120    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
121    {
122        Map<String, Object> result = new HashMap<>();
123        
124        Multimap<String, I18nizableText> errors = ArrayListMultimap.create();
125
126        Request request = ObjectModelHelper.getRequest(objectModel);
127        
128        String zoneId = request.getParameter("zoneId");
129        ZoneItem zoneItem = _resolver.resolveById(zoneId);
130        Page page = zoneItem.getParent().getParent().getParent().getParent();
131        
132        ModelAwareDataHolder serviceParameters = zoneItem.getServiceParameters();
133        String workflowName = serviceParameters.getValue("workflow");
134        String contentTypeId = serviceParameters.getValue("content-type");
135        UserIdentity[] adminUsers = serviceParameters.getValue("users");
136        
137        String siteName = request.getParameter("site");
138        String language = request.getParameter("lang");
139        
140        ContentType ugcMixin = _cTypeEP.getExtension(UGCConstants.UGC_MIXIN_TYPE);
141        
142        ContentType contentType = _cTypeEP.getExtension(contentTypeId);
143        Map<String, Object> values = _foContentCreationHelper.getAndValidateFormValues(request, contentType, "main", errors);
144        values.putAll(_foContentCreationHelper.getAndValidateFormValues(request, ugcMixin, "main", errors));
145        
146        // Check captcha if needed
147        if (_pageHelper.isCaptchaRequired(page))
148        {   
149            String captchaValue = request.getParameter("captcha");
150            String captchaKey = request.getParameter("captcha-key");
151
152            // Validate the input
153            if (!CaptchaHelper.checkAndInvalidate(captchaKey, captchaValue))
154            {
155                errors.put("captcha", new I18nizableText("plugin.ugc", "PLUGINS_UGC_SERVICE_FORM_ERROR_INVALID_CAPTCHA"));
156            }
157        }
158        
159        // If there are no errors
160        if (errors.isEmpty())
161        {            
162            String title = request.getParameter("title");
163            
164            // we add a prefix to the title for the content name to prevent issue with numeric title
165            String prefix = StringUtils.substringAfterLast(contentTypeId, ".");
166            
167            result = _foContentCreationHelper.createAndEditContent(_INITIAL_ACTION_ID, new String[] {contentTypeId}, new String[] {UGCConstants.UGC_MIXIN_TYPE}, siteName, prefix + "-" + title, title, language, values, workflowName, null, new HashMap<>());
168            
169            if (result.containsKey(Content.class.getName()))
170            {
171                result.put("success", true);
172
173                // Send mail
174                WorkflowAwareContent content = (WorkflowAwareContent) result.get(Content.class.getName());
175                _sendMail(adminUsers, content);
176            }
177            else
178            {
179                result.put("success", false);
180            }
181        }
182        else
183        {
184            result.put("success", false);
185            result.put("errors", _jsonUtils.convertObjectToJson(errors.asMap()));
186        }
187        
188        request.setAttribute(ActionResultGenerator.MAP_REQUEST_ATTR, result);
189        return EMPTY_MAP;
190    }
191
192    /**
193     * Send mail to inform that a content is created
194     * @param adminUsers the admin users
195     * @param content the created content
196     */
197    protected void _sendMail(UserIdentity[] adminUsers, WorkflowAwareContent content)
198    {
199        if (adminUsers != null)
200        {
201            String creatorFullName = null;
202            UserIdentity creatorIdentity = _currentUserProvider.getUser();
203            if (creatorIdentity != null)
204            {
205                User creator = _userManager.getUser(creatorIdentity);
206                creatorFullName = creator.getFullName();
207            }
208            else
209            {
210                creatorFullName = content.getValue(UGCConstants.ATTRIBUTE_PATH_UGC_AUTHOR);
211            }
212            
213            Site site = _getSite(content);
214            
215            try
216            {
217                String htmlBody = _getI18nBody(content, creatorFullName, site);
218                
219                I18nizableText i18nSubject = _getI18nSubject(site);
220                String subject = _i18nUtils.translate(i18nSubject);
221                
222                for (UserIdentity adminUser : adminUsers)
223                {
224                    User user = _userManager.getUser(adminUser);
225                    if (user == null)
226                    {
227                        getLogger().error("Can not send an e-mail for the content creation to the unexisting user " + adminUser);
228                    }
229                    else
230                    {
231                        String email = user.getEmail();
232                        try
233                        {
234                            SendMailHelper.newMail()
235                                          .withSubject(subject)
236                                          .withHTMLBody(htmlBody)
237                                          .withRecipient(email)
238                                          .sendMail();
239                        }
240                        catch (MessagingException | IOException e)
241                        {
242                            getLogger().warn("Could not send an e-mail for the content creation to " + email, e);
243                        }
244                    }
245                }
246            }
247            catch (IOException e)
248            {
249                getLogger().warn("Fail to build HTML body for the content creation", e);
250            }
251        }
252    }
253
254    /**
255     * Get the i18n body
256     * @param content the content
257     * @param creatorFullName the creator full name
258     * @param site the site
259     * @return The i18n body
260     * @throws IOException if failed to build html body
261     */
262    protected String _getI18nBody(WorkflowAwareContent content, String creatorFullName, Site site) throws IOException
263    {
264        List<String> parametersBody = new ArrayList<>();
265        parametersBody.add(content.getTitle());
266        parametersBody.add(creatorFullName);
267        
268        MailBodyBuilder bodyBuilder = StandardMailBodyHelper.newHTMLBody()
269            .withTitle(_getI18nSubject(site));
270            
271        if (site != null)
272        {
273            parametersBody.add(_getContentUri(content));
274            parametersBody.add(site.getTitle());
275            parametersBody.add(site.getUrl());
276            
277            bodyBuilder.withMessage(new I18nizableText("plugin.ugc", "PLUGINS_UGC_SERVICE_FORM_CREATED_CONTENT_MAIL_BODY", parametersBody))
278                .withLink(_getContentUri(content), new I18nizableText("plugin.ugc", "PLUGINS_UGC_SERVICE_FORM_CREATED_CONTENT_MAIL_BODY_CONTENT_LINK"));
279        }
280        else
281        {
282            bodyBuilder.withMessage(new I18nizableText("plugin.ugc", "PLUGINS_UGC_SERVICE_FORM_CREATED_CONTENT_MAIL_BODY_NO_SITE", parametersBody));
283        }
284        return bodyBuilder.build();
285    }
286
287    /**
288     * Get the i18n subject
289     * @param site the site
290     * @return The i18n subject
291     */
292    protected I18nizableText _getI18nSubject(Site site)
293    {
294        I18nizableText i18nSubject = null;
295        if (site != null)
296        {
297            List<String> parametersSubject = new ArrayList<>();
298            parametersSubject.add(site.getTitle());
299            i18nSubject = new I18nizableText("plugin.ugc", "PLUGINS_UGC_SERVICE_FORM_CREATED_CONTENT_MAIL_SUBJECT", parametersSubject);
300        }
301        else
302        {
303            i18nSubject = new I18nizableText("plugin.ugc", "PLUGINS_UGC_SERVICE_FORM_CREATED_CONTENT_MAIL_SUBJECT_NO_SITE");
304        }
305        return i18nSubject;
306    }
307    
308    /**
309     * Get the site name
310     * @param content The content
311     * @return the site name
312     */
313    protected Site _getSite(WorkflowAwareContent content)
314    {
315        if (content instanceof WebContent)
316        {
317            return ((WebContent) content).getSite();
318        }
319        
320        return null;
321    }
322    
323    
324    /**
325     * Get the content uri
326     * @param content the content
327     * @return the content uri
328     */
329    protected String _getContentUri(WorkflowAwareContent content)
330    {
331        return _contentHelper.getContentBOUrl(content, Map.of());
332    }
333}