001/*
002 *  Copyright 2015 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.workspaces.threads;
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.context.Context;
025import org.apache.avalon.framework.context.ContextException;
026import org.apache.avalon.framework.context.Contextualizable;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.components.ContextHelper;
030import org.apache.cocoon.environment.Request;
031import org.apache.commons.io.IOUtils;
032import org.apache.commons.lang.IllegalClassException;
033import org.apache.excalibur.source.Source;
034import org.apache.excalibur.source.SourceResolver;
035
036import org.ametys.core.ui.Callable;
037import org.ametys.plugins.explorer.resources.ModifiableResourceCollection;
038import org.ametys.plugins.explorer.threads.actions.ThreadDAO;
039import org.ametys.plugins.explorer.threads.jcr.JCRPost;
040import org.ametys.plugins.explorer.threads.jcr.JCRThread;
041import org.ametys.plugins.repository.AmetysObject;
042import org.ametys.plugins.repository.AmetysRepositoryException;
043import org.ametys.plugins.workspaces.html.HTMLTransformer;
044import org.ametys.plugins.workspaces.project.ProjectManager;
045import org.ametys.plugins.workspaces.project.modules.WorkspaceModule;
046import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
047import org.ametys.plugins.workspaces.project.objects.Project;
048import org.ametys.runtime.plugin.component.PluginAware;
049
050/**
051 * DAO for manipulating thread of a project
052 *
053 */
054public class WorkspaceThreadDAO extends ThreadDAO implements PluginAware, Contextualizable
055{
056    /** Avalon Role */
057    @SuppressWarnings("hiding")
058    public static final String ROLE = WorkspaceThreadDAO.class.getName();
059    
060    private HTMLTransformer _htmlTransformer;
061    private SourceResolver _sourceResolver;
062    private String _pluginName;
063    private ProjectManager _projectManager;
064
065    private Context _context;
066
067    private WorkspaceModuleExtensionPoint _moduleEP;
068
069    @Override
070    public void service(ServiceManager manager) throws ServiceException
071    {
072        super.service(manager);
073        _htmlTransformer = (HTMLTransformer) manager.lookup(HTMLTransformer.ROLE);
074        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
075        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
076        _moduleEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE);
077    }
078    
079    @Override
080    public void setPluginInfo(String pluginName, String featureName, String id)
081    {
082        _pluginName = pluginName;
083    }
084
085    @Override
086    public void contextualize(Context context) throws ContextException
087    {
088        _context = context;
089    }
090    
091    /**
092     * Get the list of threads of a project
093     * @param includeChildren True to also include threads messages
094     * @return The list of threads
095     */
096    @Callable
097    public Map<String, Object> getThreadsList(boolean includeChildren)
098    {
099        Request request = ContextHelper.getRequest(_context);
100        String projectName = (String) request.getAttribute("projectName");
101        
102        Project project = _projectManager.getProject(projectName);
103        
104        WorkspaceModule module = _moduleEP.getModule(ThreadWorkspaceModule.THREAD_MODULE_ID);
105        ModifiableResourceCollection threadRoot = module.getModuleRoot(project, false);
106        
107        Map<String, Object> result = new HashMap<>();
108        List<Map<String, Object>> threadsList = new ArrayList<>();
109        if (threadRoot != null)
110        {
111            for (AmetysObject ametysObject : threadRoot.getChildren())
112            {
113                AmetysObject threadObject = _resolver.resolveById(ametysObject.getId());
114                
115                if (!(threadObject instanceof JCRThread))
116                {
117                    throw new IllegalClassException(JCRThread.class, threadObject.getClass());
118                }
119                
120                JCRThread thread = (JCRThread) threadObject;
121                threadsList.add(getThreadData(thread, includeChildren));
122            }
123        }
124        
125        result.put("threads", threadsList);
126        return result;
127    }
128    
129    /**
130     * Add a thread
131     * @param name The desired name for the thread
132     * @param description The thread description
133     * @return The result map with id, parentId and name keys
134     * @throws IllegalAccessException If the user has no sufficient rights
135     * @throws AmetysRepositoryException If a repository error occurred
136     */
137    @Callable
138    public Map<String, Object> addThread(String name, String description) throws IllegalAccessException, AmetysRepositoryException
139    {
140        Request request = ContextHelper.getRequest(_context);
141        String projectName = (String) request.getAttribute("projectName");
142        
143        Project project = _projectManager.getProject(projectName);
144        
145        WorkspaceModule module = _moduleEP.getModule(ThreadWorkspaceModule.THREAD_MODULE_ID);
146        ModifiableResourceCollection threadRoot = module.getModuleRoot(project, false);
147        
148        assert threadRoot != null;
149        
150        return addThread(threadRoot.getId(), name, description);
151    }
152    
153    @Override
154    protected void setPostContent(JCRPost post, String content)
155    {
156        try
157        {
158            _htmlTransformer.transform(content, post.getContent());
159        }
160        catch (IOException e)
161        {
162            throw new AmetysRepositoryException("Failed to transform post content into rich text", e);
163        }
164    }
165    
166    @Override
167    protected String getPostContent(JCRPost post) throws AmetysRepositoryException
168    {
169        Source contentSource = null;
170        try
171        {
172            Map<String, Object> parameters = new HashMap<>();
173            parameters.put("source", post.getContent().getInputStream());
174            contentSource = _sourceResolver.resolveURI("cocoon://_plugins/" + _pluginName + "/convert/html2html", null, parameters);
175            return IOUtils.toString(contentSource.getInputStream(), "UTF-8");
176        }
177        catch (IOException e)
178        {
179            throw new AmetysRepositoryException("Failed to transform rich text into string", e);
180        }
181        finally
182        {
183            _sourceResolver.release(contentSource);
184        }
185    }
186    
187    @Override
188    protected String getPostContentForEditing(JCRPost post) throws AmetysRepositoryException
189    {
190        try
191        {
192            StringBuilder sb = new StringBuilder();
193            _htmlTransformer.transformForEditing(post.getContent(), sb);
194            return sb.toString();
195        }
196        catch (IOException e)
197        {
198            throw new AmetysRepositoryException("Failed to transform rich text into string", e);
199        }
200    }
201}