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}