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.tasks;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.cocoon.components.ContextHelper;
025import org.apache.cocoon.environment.Request;
026import org.apache.commons.lang.IllegalClassException;
027
028import org.ametys.cms.transformation.xslt.ResolveURIComponent;
029import org.ametys.core.right.RightManager.RightResult;
030import org.ametys.core.ui.Callable;
031import org.ametys.core.user.UserIdentity;
032import org.ametys.plugins.explorer.ExplorerNode;
033import org.ametys.plugins.explorer.resources.ModifiableResourceCollection;
034import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory;
035import org.ametys.plugins.explorer.tasks.jcr.JCRTasksDAO;
036import org.ametys.plugins.explorer.tasks.jcr.JCRTasksListFactory;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.AmetysObjectIterable;
039import org.ametys.plugins.repository.AmetysRepositoryException;
040import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
041import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
042import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
043import org.ametys.plugins.workspaces.AbstractWorkspaceModule;
044import org.ametys.plugins.workspaces.project.objects.Project;
045import org.ametys.runtime.i18n.I18nizableText;
046import org.ametys.web.repository.page.ModifiablePage;
047import org.ametys.web.repository.page.ModifiableZone;
048import org.ametys.web.repository.page.ModifiableZoneItem;
049import org.ametys.web.repository.page.Page;
050import org.ametys.web.repository.page.ZoneItem.ZoneType;
051
052import com.google.common.collect.ImmutableSet;
053
054/**
055 * Tasks manager for workspaces
056 */
057public class TasksWorkspaceModule extends AbstractWorkspaceModule
058{
059    /** The id of task module */
060    public static final String TASK_MODULE_ID = TasksWorkspaceModule.class.getName();
061    
062    /** Tag on the main page holding the task module */
063    public static final String TASK_MODULE_TAG = "WORKSPACES_MODULE_TASK";
064    
065    /** Workspaces tasks list node name */
066    private static final String __WORKSPACES_TASKS_NODE_NAME = "tasks";
067    
068    /** Workspaces default tasks list node name */
069    private static final String __WORKSPACES_TASKS_DEFAULT_NODE_NAME = "default";
070
071    /** Module i18n title key */
072    private static final String __MODULE_TITLE_KEY = "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_TASK_LABEL";
073    
074    @Override
075    public String getId()
076    {
077        return TASK_MODULE_ID;
078    }
079    
080    @Override
081    protected String getModulePageName()
082    {
083        return "tasks";
084    }
085    
086    @Override
087    public I18nizableText getModuleTitle()
088    {
089        return new I18nizableText("plugin.workspaces", __MODULE_TITLE_KEY);
090    }
091    
092    @Override
093    protected I18nizableText getModulePageTitle()
094    {
095        return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_WORKSPACE_PAGE_TASKS_TITLE");
096    }
097    
098    @Override
099    protected String getModuleTagName()
100    {
101        return TASK_MODULE_TAG;
102    }
103    
104    @Override
105    protected void initializeModulePage(ModifiablePage taskPage)
106    {
107        ModifiableZone defaultZone = taskPage.createZone("default");
108        
109        String serviceId = "org.ametys.plugins.workspaces.module.Tasks";
110        ModifiableZoneItem defaultZoneItem = defaultZone.addZoneItem();
111        defaultZoneItem.setType(ZoneType.SERVICE);
112        defaultZoneItem.setServiceId(serviceId);
113        
114        ModifiableCompositeMetadata serviceMetadata = defaultZoneItem.getServiceParameters();
115        
116        serviceMetadata.setMetadata("xslt", _getDefaultXslt(serviceId));
117    }
118
119    /**
120     * Retrieves the rights for the current user in the project
121     * @return The project
122     */
123    @Callable
124    public Map<String, Object> getTasksModuleRights()
125    {
126        Map<String, Object> rights = new HashMap<>();
127        
128        Request request = ContextHelper.getRequest(_context);
129        String projectName = (String) request.getAttribute("projectName");
130        Project project = _projectManager.getProject(projectName);
131        ModifiableResourceCollection tasksRoot = getModuleRoot(project, false);
132        
133        UserIdentity currentUser = _currentUserProvider.getUser();
134        rights.put("view", tasksRoot != null && _rightManager.hasRight(currentUser, JCRTasksDAO.RIGHTS_VIEW_TASKS, tasksRoot) == RightResult.RIGHT_ALLOW);
135        rights.put("add", tasksRoot != null && _rightManager.hasRight(currentUser, JCRTasksDAO.RIGHTS_ADD_TASK, tasksRoot) == RightResult.RIGHT_ALLOW);
136        
137        return rights;
138    }
139    
140    /**
141     * Retrieves the rights for the current user in the projects list
142     * @param projectNames The name of projects to checks rights from
143     * @return The rights data
144     */
145    @Callable
146    public Map<String, Object> getTasksServiceRights(List<String> projectNames)
147    {
148        Map<String, Object> rights = new HashMap<>();
149        
150        List<String> rightAdd = new ArrayList<>();
151        
152        UserIdentity currentUser = _currentUserProvider.getUser();
153        for (String projectName : projectNames)
154        {
155            Project project = _projectManager.getProject(projectName);
156            ModifiableResourceCollection tasksRoot = getModuleRoot(project, false);
157            
158            if (tasksRoot != null && _rightManager.hasRight(currentUser, JCRTasksDAO.RIGHTS_ADD_TASK, tasksRoot) == RightResult.RIGHT_ALLOW)
159            {
160                rightAdd.add(projectName);
161            }
162        }
163        
164        rights.put("add", rightAdd);
165        
166        return rights;
167    }
168    
169    /**
170     * Get the URI of a task in project'site
171     * @param project The project
172     * @param taskId The id of the task
173     * @param language The sitemap language
174     * @return The thread uri
175     */
176    public String getTaskUri(Project project, String taskId, String language)
177    {
178        AmetysObjectIterable<Page> pages = getModulePages(project, language);
179        
180        if (pages.getSize() > 0)
181        {
182            Page page = pages.iterator().next();
183            
184            StringBuilder sb = new StringBuilder();
185            sb.append(ResolveURIComponent.resolve("page", page.getId()));
186            sb.append("#").append(taskId);
187            
188            return sb.toString();
189        }
190        
191        return null;
192    }
193    
194    @Override
195    public ModifiableResourceCollection getModuleRoot(Project project, boolean create)
196    {
197        try
198        {
199            ExplorerNode projectRootNode = project.getExplorerRootNode();
200            
201            if (projectRootNode instanceof ModifiableResourceCollection)
202            {
203                ModifiableResourceCollection projectRootNodeRc = (ModifiableResourceCollection) projectRootNode;
204                return _getAmetysObject(projectRootNodeRc, __WORKSPACES_TASKS_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE, create);
205            }
206            else
207            {
208                throw new IllegalClassException(ModifiableResourceCollection.class, projectRootNode.getClass());
209            }
210        }
211        catch (AmetysRepositoryException e)
212        {
213            throw new AmetysRepositoryException("Error getting the documents root node.", e);
214        }
215    }
216    
217    /**
218     * Get the root for tasks
219     * @param project The project
220     * @param create true to create root if not exists
221     * @return The root for tasks
222     */
223    public DefaultTraversableAmetysObject getTasksRoot(Project project, boolean create)
224    {
225        ModifiableResourceCollection moduleRoot = getModuleRoot(project, create);
226        return _getAmetysObject(moduleRoot, __WORKSPACES_TASKS_DEFAULT_NODE_NAME, JCRTasksListFactory.TASKS_LIST_NODETYPE, create);
227    }
228
229    
230    /**
231     * Utility method to get or create an ametys object
232     * @param <A> A sub class of AmetysObject
233     * @param parent The parent object
234     * @param name The ametys object name
235     * @param type The ametys object type
236     * @param create True to create the object if it does not exist
237     * @return ametys object
238     * @throws AmetysRepositoryException if an repository error occurs
239     */
240    protected <A extends AmetysObject> A _getAmetysObject(ModifiableTraversableAmetysObject parent, String name, String type, boolean create) throws AmetysRepositoryException
241    {
242        A object = null;
243        
244        if (parent.hasChild(name))
245        {
246            object = parent.getChild(name);
247        }
248        else if (create)
249        {
250            object = parent.createChild(name, type);
251            parent.saveChanges();
252        }
253        
254        return object;
255    }
256    
257    @Override
258    public Set<String> getAllowedEventTypes()
259    {
260        return ImmutableSet.of("task.created", "task.assigned", "task.status.changed");
261    }
262}