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