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.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.components.ContextHelper; 028import org.apache.cocoon.environment.Request; 029 030import org.ametys.cms.data.Binary; 031import org.ametys.core.right.RightManager.RightResult; 032import org.ametys.core.ui.Callable; 033import org.ametys.core.user.UserIdentity; 034import org.ametys.plugins.explorer.resources.ModifiableResourceCollection; 035import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory; 036import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 037import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; 038import org.ametys.plugins.workspaces.AbstractWorkspaceModule; 039import org.ametys.plugins.workspaces.ObservationConstants; 040import org.ametys.plugins.workspaces.project.objects.Project; 041import org.ametys.plugins.workspaces.util.StatisticColumn; 042import org.ametys.plugins.workspaces.util.StatisticsColumnType; 043import org.ametys.runtime.i18n.I18nizableText; 044import org.ametys.web.repository.page.ModifiablePage; 045import org.ametys.web.repository.page.ModifiableZone; 046import org.ametys.web.repository.page.ModifiableZoneItem; 047import org.ametys.web.repository.page.ZoneItem.ZoneType; 048 049import com.google.common.collect.ImmutableSet; 050 051/** 052 * Tasks manager for workspaces 053 */ 054public class TasksWorkspaceModule extends AbstractWorkspaceModule 055{ 056 /** The id of task module */ 057 public static final String TASK_MODULE_ID = TasksWorkspaceModule.class.getName(); 058 059 /** Workspaces tasks list node name */ 060 private static final String __WORKSPACES_TASKS_NODE_NAME = "tasks"; 061 062 /** Workspaces root tasks node name */ 063 private static final String __WORKSPACES_TASKS_ROOT_NODE_NAME = "tasks-root"; 064 065 /** Workspaces root tasks lists node name */ 066 private static final String __WORKSPACES_TASKS_LIST_ROOT_NODE_NAME = "tasks-list-root"; 067 068 private static final String __TASK_NUMBER_HEADER_ID = __WORKSPACES_TASKS_NODE_NAME + "$task_number"; 069 070 /** The tasks module DAO */ 071 private WorkspaceTaskDAO _workspaceTaskDAO; 072 073 @Override 074 public void service(ServiceManager serviceManager) throws ServiceException 075 { 076 super.service(serviceManager); 077 _workspaceTaskDAO = (WorkspaceTaskDAO) serviceManager.lookup(WorkspaceTaskDAO.ROLE); 078 } 079 080 @Override 081 public String getId() 082 { 083 return TASK_MODULE_ID; 084 } 085 086 @Override 087 public String getModuleName() 088 { 089 return __WORKSPACES_TASKS_NODE_NAME; 090 } 091 092 public int getOrder() 093 { 094 return ORDER_TASKS; 095 } 096 097 @Override 098 protected String getModulePageName() 099 { 100 return "tasks"; 101 } 102 103 public I18nizableText getModuleTitle() 104 { 105 return new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_TASK_LABEL"); 106 } 107 public I18nizableText getModuleDescription() 108 { 109 return new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_TASK_DESCRIPTION"); 110 } 111 @Override 112 protected I18nizableText getModulePageTitle() 113 { 114 return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_WORKSPACE_PAGE_TASKS_TITLE"); 115 } 116 117 @Override 118 protected void initializeModulePage(ModifiablePage taskPage) 119 { 120 ModifiableZone defaultZone = taskPage.createZone("default"); 121 122 String serviceId = "org.ametys.plugins.workspaces.module.Tasks"; 123 ModifiableZoneItem defaultZoneItem = defaultZone.addZoneItem(); 124 defaultZoneItem.setType(ZoneType.SERVICE); 125 defaultZoneItem.setServiceId(serviceId); 126 127 ModifiableModelAwareDataHolder serviceDataHolder = defaultZoneItem.getServiceParameters(); 128 serviceDataHolder.setValue("xslt", _getDefaultXslt(serviceId)); 129 } 130 131 /** 132 * Retrieves the rights for the current user in the project 133 * @return The project 134 */ 135 @Callable 136 public Map<String, Object> getTasksModuleRights() 137 { 138 Map<String, Object> rights = new HashMap<>(); 139 140 141 Request request = ContextHelper.getRequest(_context); 142 String projectName = (String) request.getAttribute("projectName"); 143 Project project = _projectManager.getProject(projectName); 144 ModifiableResourceCollection tasksRoot = getModuleRoot(project, false); 145 146 UserIdentity currentUser = _currentUserProvider.getUser(); 147 rights.put("view", tasksRoot != null && _rightManager.hasRight(currentUser, AbstractWorkspaceTaskDAO.RIGHTS_HANDLE_TASK, tasksRoot) == RightResult.RIGHT_ALLOW); 148 rights.put("add", tasksRoot != null && _rightManager.hasRight(currentUser, AbstractWorkspaceTaskDAO.RIGHTS_HANDLE_TASK, tasksRoot) == RightResult.RIGHT_ALLOW); 149 150 return rights; 151 } 152 153 /** 154 * Retrieves the rights for the current user in the projects list 155 * @param projectNames The name of projects to checks rights from 156 * @return The rights data 157 */ 158 @Callable 159 public Map<String, Object> getTasksServiceRights(List<String> projectNames) 160 { 161 Map<String, Object> rights = new HashMap<>(); 162 163 List<String> rightAdd = new ArrayList<>(); 164 165 UserIdentity currentUser = _currentUserProvider.getUser(); 166 for (String projectName : projectNames) 167 { 168 Project project = _projectManager.getProject(projectName); 169 ModifiableResourceCollection tasksRoot = getModuleRoot(project, false); 170 171 if (tasksRoot != null && _rightManager.hasRight(currentUser, AbstractWorkspaceTaskDAO.RIGHTS_HANDLE_TASK, tasksRoot) == RightResult.RIGHT_ALLOW) 172 { 173 rightAdd.add(projectName); 174 } 175 } 176 177 rights.put("add", rightAdd); 178 179 return rights; 180 } 181 182 /** 183 * Get the URI of a task in project'site 184 * @param project The project 185 * @param taskId The id of the task 186 * @return The task uri 187 */ 188 public String getTaskUri(Project project, String taskId) 189 { 190 String moduleUrl = getModuleUrl(project); 191 if (moduleUrl != null) 192 { 193 StringBuilder sb = new StringBuilder(); 194 sb.append(moduleUrl); 195 sb.append("#task-").append(taskId); 196 197 return sb.toString(); 198 } 199 200 return null; 201 } 202 203 /** 204 * Get the root for tasks 205 * @param project The project 206 * @param create true to create root if not exists 207 * @return The root for tasks 208 */ 209 public DefaultTraversableAmetysObject getTasksRoot(Project project, boolean create) 210 { 211 ModifiableResourceCollection moduleRoot = getModuleRoot(project, create); 212 return _getAmetysObject(moduleRoot, __WORKSPACES_TASKS_ROOT_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE, create); 213 } 214 215 /** 216 * Get the root for tasks lists 217 * @param project The project 218 * @param create true to create root if not exists 219 * @return The root for tasks lists 220 */ 221 public DefaultTraversableAmetysObject getTasksListsRoot(Project project, boolean create) 222 { 223 ModifiableResourceCollection moduleRoot = getModuleRoot(project, create); 224 return _getAmetysObject(moduleRoot, __WORKSPACES_TASKS_LIST_ROOT_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE, create); 225 } 226 227 228 @Override 229 public Set<String> getAllowedEventTypes() 230 { 231 return ImmutableSet.of(ObservationConstants.EVENT_TASK_CREATED, ObservationConstants.EVENT_TASK_ASSIGNED, ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED, ObservationConstants.EVENT_TASK_DELETING); 232 } 233 234 @Override 235 public Map<String, Object> _getInternalStatistics(Project project, boolean isActive) 236 { 237 if (isActive) 238 { 239 return Map.of(__TASK_NUMBER_HEADER_ID, _workspaceTaskDAO.getTasksCount(project)); 240 } 241 else 242 { 243 return Map.of(__TASK_NUMBER_HEADER_ID, __SIZE_INACTIVE); 244 } 245 } 246 247 @Override 248 protected long _getModuleSize(Project project) 249 { 250 return _workspaceTaskDAO.getProjectTasks(project) 251 .stream() 252 .map(Task::getAttachments) 253 .flatMap(Collection::stream) 254 .mapToLong(Binary::getLength) 255 .sum(); 256 } 257 258 @Override 259 public List<StatisticColumn> _getInternalStatisticModel() 260 { 261 return List.of(new StatisticColumn(__TASK_NUMBER_HEADER_ID, new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_PROJECT_STATISTICS_TOOL_COLUMN_TASK_NUMBER")) 262 .withRenderer("Ametys.plugins.workspaces.project.tool.ProjectsGridHelper.renderElements") 263 .withType(StatisticsColumnType.LONG) 264 .withGroup(GROUP_HEADER_ELEMENTS_ID)); 265 } 266 267 @Override 268 protected boolean _showModuleSize() 269 { 270 return true; 271 } 272}