001/*
002 *  Copyright 2016 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.webcontentio;
017
018import java.io.InputStream;
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.context.ContextException;
025import org.apache.avalon.framework.context.Contextualizable;
026import org.apache.avalon.framework.parameters.Parameters;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.Constants;
030import org.apache.cocoon.acting.ServiceableAction;
031import org.apache.cocoon.environment.Context;
032import org.apache.cocoon.environment.ObjectModelHelper;
033import org.apache.cocoon.environment.Redirector;
034import org.apache.cocoon.environment.Request;
035import org.apache.cocoon.environment.SourceResolver;
036import org.apache.cocoon.servlet.multipart.Part;
037import org.apache.commons.lang3.StringUtils;
038
039import org.ametys.core.authentication.token.AuthenticationTokenManager;
040import org.ametys.core.cocoon.ActionResultGenerator;
041import org.ametys.core.right.RightsException;
042import org.ametys.core.user.UserIdentity;
043import org.ametys.plugins.repository.AmetysRepositoryException;
044import org.ametys.web.repository.page.SitemapElement;
045import org.ametys.web.repository.site.Site;
046import org.ametys.web.repository.site.SiteManager;
047import org.ametys.web.repository.sitemap.Sitemap;
048
049/**
050 * Action to import a content from an input stream received through a POST request.
051 */
052public class ImportContentAction extends ServiceableAction implements Contextualizable
053{
054    /** The token context used to valide token when importing contents */
055    public static final String TOKEN_CONTEXT = "WebContentIO-ImportContent";
056    
057    private AuthenticationTokenManager _authenticationManager;
058    private ContentIOManager _contentIOManager;
059    private SiteManager _siteManager;
060
061    private Context _context;
062
063    @Override
064    public void contextualize(org.apache.avalon.framework.context.Context context) throws ContextException
065    {
066        _context = (Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
067    }
068    
069    @Override
070    public void service(ServiceManager smanager) throws ServiceException
071    {
072        super.service(smanager);
073        
074        _authenticationManager = (AuthenticationTokenManager) manager.lookup(AuthenticationTokenManager.ROLE);
075        _contentIOManager = (ContentIOManager) manager.lookup(ContentIOManager.ROLE);
076        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
077    }
078    
079    @Override
080    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
081    {
082        Request request = ObjectModelHelper.getRequest(objectModel);
083        List<String> error = new ArrayList<>();
084        Boolean success = true;
085        
086        if (!"POST".equals(request.getMethod()))
087        {
088            success = false;
089            error.add("Only POST methods are allowed.");
090            getLogger().warn("Only POST methods are allowed.");
091        }
092        
093        Object content = request.get("content");
094        if (content == null)
095        {
096            success = false;
097            error.add("No content provided. The parameter 'content' is mandatory.");
098            getLogger().warn("No content provided. The parameter 'content' is mandatory.");
099        }
100        
101        String authenticationToken = (String) request.get("key");
102        if (authenticationToken == null)
103        {
104            success = false;
105            error.add("No API key provided. The parameter 'key' is mandatory.");
106            getLogger().warn("No API key provided. The parameter 'key' is mandatory.");
107        }
108        
109        UserIdentity user = _authenticationManager.validateToken(authenticationToken, TOKEN_CONTEXT);
110        if (user == null)
111        {
112            success = false;
113            error.add("The API key provided is invalid, please check the value of the parameter 'key'.");
114            getLogger().warn("The API key provided is invalid, please check the value of the parameter 'key'.");
115        }
116        
117        String siteName = parameters.getParameter("site");
118        String sitemapName = parameters.getParameter("sitemap");
119        String path = parameters.getParameter("path");
120        boolean extern = parameters.getParameterAsBoolean("extern", false);
121        
122        SitemapElement rootPage = getPageFromPath(siteName, sitemapName, path);
123        
124        if (rootPage == null)
125        {
126            success = false;
127            error.add("Unable to retrieve the parent page, the specified path was not found.");
128            getLogger().warn("Unable to retrieve the parent page, the specified path was not found.");
129        }
130        
131        if (success && content instanceof Part)
132        {
133            Part part = (Part) content;
134            
135            InputStream is = part.getInputStream();
136            String contentName = part.getUploadName();
137            String mimeType = _context.getMimeType(contentName);
138            
139            try
140            {
141                _contentIOManager.importContent(is, mimeType, contentName, user, rootPage, extern);
142            }
143            catch (RightsException e)
144            {
145                success = false;
146                error.add("Insufficient rights to create a content.");
147                getLogger().warn("Insufficient rights to create a content.");
148            }
149        }
150        
151        Map<String, Object> mapResult = new HashMap<>();
152        mapResult.put("success", success);
153        if (!success)
154        {
155            mapResult.put("error", error);
156        }
157        
158        request.setAttribute(ActionResultGenerator.MAP_REQUEST_ATTR, mapResult);
159        
160        return EMPTY_MAP;
161    }
162    
163    private SitemapElement getPageFromPath(String siteName, String sitemapName, String path)
164    {
165        Site site = null;
166        Sitemap sitemap = null;
167        
168        try
169        {
170            site = _siteManager.getSite(siteName);
171            sitemap = site.getSitemap(sitemapName);
172        }
173        catch (AmetysRepositoryException e)
174        {
175            getLogger().warn("Unable to retrieve the site or sitemap.", e);
176            return null;
177        }
178        
179        if (StringUtils.isEmpty(path) || "/".equals(path))
180        {
181            return sitemap;
182        }
183        
184        String pathCleaned = path;
185        if (pathCleaned.startsWith("/"))
186        {
187            pathCleaned = pathCleaned.substring(1);
188        }
189        if (pathCleaned.endsWith("/"))
190        {
191            pathCleaned = pathCleaned.substring(0, path.length() - 1);
192        }
193
194        String[] pagesName = pathCleaned.split("/");
195        
196        SitemapElement page = sitemap;
197        for (int i = 0; i < pagesName.length; i++)
198        {
199            if (StringUtils.isEmpty(pagesName[i]))
200            {
201                return null;
202            }
203            
204            page = page.getChild(pagesName[i]);
205            
206            if (page == null)
207            {
208                return null;
209            }
210        }
211        
212        return page;
213        
214    }
215}