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.workspaces.threads;
017
018import java.util.HashMap;
019import java.util.Map;
020import java.util.Set;
021
022import org.apache.cocoon.components.ContextHelper;
023import org.apache.cocoon.environment.Request;
024import org.apache.commons.lang.IllegalClassException;
025
026import org.ametys.cms.transformation.xslt.ResolveURIComponent;
027import org.ametys.core.right.RightManager.RightResult;
028import org.ametys.core.ui.Callable;
029import org.ametys.plugins.explorer.ExplorerNode;
030import org.ametys.plugins.explorer.resources.ModifiableResourceCollection;
031import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory;
032import org.ametys.plugins.explorer.threads.actions.ThreadDAO;
033import org.ametys.plugins.repository.AmetysObject;
034import org.ametys.plugins.repository.AmetysObjectIterable;
035import org.ametys.plugins.repository.AmetysRepositoryException;
036import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
037import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
038import org.ametys.plugins.workspaces.AbstractWorkspaceModule;
039import org.ametys.plugins.workspaces.project.objects.Project;
040import org.ametys.runtime.i18n.I18nizableText;
041import org.ametys.web.repository.page.ModifiablePage;
042import org.ametys.web.repository.page.ModifiableZone;
043import org.ametys.web.repository.page.ModifiableZoneItem;
044import org.ametys.web.repository.page.Page;
045import org.ametys.web.repository.page.ZoneItem.ZoneType;
046
047import com.google.common.collect.ImmutableSet;
048
049/**
050 * ThreadDAO to interact with projects aware threads
051 */
052public class ThreadWorkspaceModule extends AbstractWorkspaceModule
053{
054    /** The id of thread module */
055    public static final String THREAD_MODULE_ID = ThreadWorkspaceModule.class.getName();
056    
057    /** Tag on the main page holding the thread module */
058    private static final String __THREAD_MODULE_TAG = "WORKSPACES_MODULE_THREAD";
059    
060    /** Workspaces threads node name */
061    private static final String __WORKSPACES_THREADS_NODE_NAME = "threads";
062    
063    /** Module i18n title key */
064    private static final String __MODULE_TITLE_KEY = "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_THREAD_LABEL";   
065    
066    @Override
067    public String getId()
068    {
069        return THREAD_MODULE_ID;
070    }
071    
072    @Override
073    protected String getModulePageName()
074    {
075        return "forum";
076    }
077    
078    @Override
079    public I18nizableText getModuleTitle()
080    {
081        return new I18nizableText("plugin." + _pluginName, __MODULE_TITLE_KEY);
082    }
083    
084    @Override
085    protected I18nizableText getModulePageTitle()
086    {
087        return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_WORKSPACE_PAGE_FORUM_TITLE");
088    }
089    
090    @Override
091    protected String getModuleTagName()
092    {
093        return __THREAD_MODULE_TAG;
094    }
095    
096    @Override
097    protected void initializeModulePage(ModifiablePage forumPage)
098    {
099        ModifiableZone defaultZone = forumPage.createZone("default");
100        
101        String serviceId = "org.ametys.plugins.workspaces.module.Thread";
102        ModifiableZoneItem defaultZoneItem = defaultZone.addZoneItem();
103        defaultZoneItem.setType(ZoneType.SERVICE);
104        defaultZoneItem.setServiceId(serviceId);
105        
106        ModifiableCompositeMetadata serviceMetadata = defaultZoneItem.getServiceParameters();
107        
108        serviceMetadata.setMetadata("xslt", _getDefaultXslt(serviceId));
109    }
110    
111    /**
112     * Get the URI of a thread in project'site
113     * @param project The project
114     * @param threadId The id of thread
115     * @param language The sitemap language
116     * @return The thread uri
117     */
118    public String getThreadUri(Project project, String threadId, String language)
119    {
120        AmetysObjectIterable<Page> pages = getModulePages(project, language);
121        
122        if (pages.getSize() > 0)
123        {
124            Page page = pages.iterator().next();
125            
126            StringBuilder sb = new StringBuilder();
127            sb.append(ResolveURIComponent.resolve("page", page.getId()));
128            sb.append("#").append(threadId);
129            
130            return sb.toString();
131        }
132        
133        return null;
134    }
135    
136    /**
137     * Retrieve the current user rights on the thread module
138     * @return The map of rights
139     */
140    @Callable
141    public Map<String, Object> getThreadModuleRights()
142    {
143        Map<String, Object> rights = new HashMap<>();
144        
145        Request request = ContextHelper.getRequest(_context);
146        String projectName = (String) request.getAttribute("projectName");
147        Project project = _projectManager.getProject(projectName);
148        ModifiableResourceCollection threadRoot = getModuleRoot(project, false);
149        
150        rights.put("threadAdd", threadRoot != null && _rightManager.hasRight(_currentUserProvider.getUser(), ThreadDAO.__RIGHTS_THREAD_ADD, threadRoot) == RightResult.RIGHT_ALLOW);
151        
152        return rights;
153    }
154    
155    @Override
156    public ModifiableResourceCollection getModuleRoot(Project project, boolean create)
157    {
158        try
159        {
160            ExplorerNode projectRootNode = project.getExplorerRootNode();
161            
162            if (projectRootNode instanceof ModifiableResourceCollection)
163            {
164                ModifiableResourceCollection projectRootNodeRc = (ModifiableResourceCollection) projectRootNode;
165                return _getAmetysObject(projectRootNodeRc, __WORKSPACES_THREADS_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE, create);
166            }
167            else
168            {
169                throw new IllegalClassException(ModifiableResourceCollection.class, projectRootNode.getClass());
170            }
171        }
172        catch (AmetysRepositoryException e)
173        {
174            throw new AmetysRepositoryException("Error getting the documents root node.", e);
175        }
176    }
177
178    
179    /**
180     * Utility method to get or create an ametys object
181     * @param <A> A sub class of AmetysObject
182     * @param parent The parent object
183     * @param name The ametys object name
184     * @param type The ametys object type
185     * @param create True to create the object if it does not exist
186     * @return ametys object
187     * @throws AmetysRepositoryException if an repository error occurs
188     */
189    protected <A extends AmetysObject> A _getAmetysObject(ModifiableTraversableAmetysObject parent, String name, String type, boolean create) throws AmetysRepositoryException
190    {
191        A object = null;
192        
193        if (parent.hasChild(name))
194        {
195            object = parent.getChild(name);
196        }
197        else if (create)
198        {
199            object = parent.createChild(name, type);
200            parent.saveChanges();
201        }
202        
203        return object;
204    }
205
206    @Override
207    public Set<String> getAllowedEventTypes()
208    {
209        return ImmutableSet.of("thread.created", "thread.post.created");
210    }
211}