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