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.documents; 017 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021import java.util.Set; 022 023import org.apache.avalon.framework.context.Context; 024import org.apache.avalon.framework.context.ContextException; 025import org.apache.cocoon.components.ContextHelper; 026import org.apache.cocoon.environment.Request; 027import org.apache.commons.lang.IllegalClassException; 028 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.ObservationConstants; 034import org.ametys.plugins.explorer.resources.ModifiableResourceCollection; 035import org.ametys.plugins.explorer.resources.Resource; 036import org.ametys.plugins.explorer.resources.ResourceCollection; 037import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory; 038import org.ametys.plugins.repository.AmetysObject; 039import org.ametys.plugins.repository.AmetysRepositoryException; 040import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 041import org.ametys.plugins.workspaces.AbstractWorkspaceModule; 042import org.ametys.plugins.workspaces.project.objects.Project; 043import org.ametys.plugins.workspaces.util.StatisticColumn; 044import org.ametys.plugins.workspaces.util.StatisticsColumnType; 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.ZoneItem.ZoneType; 050 051import com.google.common.collect.ImmutableSet; 052 053/** 054 * Helper component for managing documents 055 */ 056public class DocumentWorkspaceModule extends AbstractWorkspaceModule 057{ 058 /** The id of document module */ 059 public static final String DOCUMENT_MODULE_ID = DocumentWorkspaceModule.class.getName(); 060 061 /** Workspaces documents node name */ 062 public static final String WORKSPACES_DOCUMENTS_NODE_NAME = "documents"; 063 064 private static final String __DOCUMENT_NUMBER_HEADER_ID = WORKSPACES_DOCUMENTS_NODE_NAME + "$document_number"; 065 066 @Override 067 public void contextualize(Context context) throws ContextException 068 { 069 _context = context; 070 } 071 072 @Override 073 public String getId() 074 { 075 return DOCUMENT_MODULE_ID; 076 } 077 078 @Override 079 public String getModuleName() 080 { 081 return WORKSPACES_DOCUMENTS_NODE_NAME; 082 } 083 084 public int getOrder() 085 { 086 return ORDER_DOCUMENTS; 087 } 088 089 @Override 090 protected String getModulePageName() 091 { 092 return "documents"; 093 } 094 095 public I18nizableText getModuleTitle() 096 { 097 return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_DOCUMENT_LABEL"); 098 } 099 public I18nizableText getModuleDescription() 100 { 101 return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_SERVICE_MODULE_DOCUMENT_DESCRIPTION"); 102 } 103 @Override 104 protected I18nizableText getModulePageTitle() 105 { 106 return new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_WORKSPACE_PAGE_DOCUMENTS_TITLE"); 107 } 108 109 @Override 110 protected void initializeModulePage(ModifiablePage documentPage) 111 { 112 ModifiableZone defaultZone = documentPage.createZone("default"); 113 114 String serviceId = "org.ametys.plugins.workspaces.module.Document"; 115 ModifiableZoneItem defaultZoneItem = defaultZone.addZoneItem(); 116 defaultZoneItem.setType(ZoneType.SERVICE); 117 defaultZoneItem.setServiceId(serviceId); 118 119 ModifiableModelAwareDataHolder serviceDataHolder = defaultZoneItem.getServiceParameters(); 120 serviceDataHolder.setValue("xslt", _getDefaultXslt(serviceId)); 121 } 122 123 /** 124 * Get the URI of a folder in project'site 125 * @param project The project 126 * @param collectionId The id of collection 127 * @return The thread uri 128 */ 129 public String getFolderUri(Project project, String collectionId) 130 { 131 String moduleUrl = getModuleUrl(project); 132 if (moduleUrl != null) 133 { 134 StringBuilder sb = new StringBuilder(); 135 sb.append(moduleUrl); 136 sb.append("#").append(collectionId); 137 138 return sb.toString(); 139 } 140 141 return null; 142 } 143 144 /** 145 * Retrieves the set of general rights used in the document module for the current user 146 * @return The map of right data. Keys are the rights id, and values indicates whether the current user has the right or not. 147 */ 148 @Callable 149 public Map<String, Object> getModuleBaseRights() 150 { 151 Request request = ContextHelper.getRequest(_context); 152 153 String projectName = (String) request.getAttribute("projectName"); 154 Project project = _projectManager.getProject(projectName); 155 156 ModifiableResourceCollection documentRoot = getModuleRoot(project, false); 157 158 Map<String, Object> rightsData = new HashMap<>(); 159 UserIdentity user = _currentUserProvider.getUser(); 160 161 // Add file / folder 162 rightsData.put("add-file", _rightManager.hasRight(user, "Plugin_Explorer_File_Add", documentRoot) == RightResult.RIGHT_ALLOW); 163 rightsData.put("add-folder", _rightManager.hasRight(user, "Plugin_Explorer_Folder_Add", documentRoot) == RightResult.RIGHT_ALLOW); 164 rightsData.put("add-cmis-folder", _rightManager.hasRight(user, "Plugin_Explorer_CMIS_Add", documentRoot) == RightResult.RIGHT_ALLOW); 165 166 // Tags 167 rightsData.put("add-tag", _projectRightHelper.canAddTag(project)); 168 rightsData.put("remove-tag", _projectRightHelper.canRemoveTag(project)); 169 170 return rightsData; 171 } 172 173 @Override 174 public ModifiableResourceCollection getModuleRoot(Project project, boolean create) 175 { 176 try 177 { 178 ExplorerNode projectRootNode = project.getExplorerRootNode(); 179 180 if (projectRootNode instanceof ModifiableResourceCollection) 181 { 182 ModifiableResourceCollection projectRootNodeRc = (ModifiableResourceCollection) projectRootNode; 183 return _getAmetysObject(projectRootNodeRc, WORKSPACES_DOCUMENTS_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE, create); 184 } 185 else 186 { 187 throw new IllegalClassException(ModifiableResourceCollection.class, projectRootNode.getClass()); 188 } 189 } 190 catch (AmetysRepositoryException e) 191 { 192 throw new AmetysRepositoryException("Error getting the documents root node.", e); 193 } 194 } 195 196 @Override 197 public Set<String> getAllowedEventTypes() 198 { 199 return ImmutableSet.of("resource.created", "resource.updated", "resource.renamed"); 200 } 201 202 @Override 203 public Map<String, Object> _getInternalStatistics(Project project, boolean isActive) 204 { 205 if (isActive) 206 { 207 ModifiableResourceCollection documentRoot = getModuleRoot(project, false); 208 long fileNumber = documentRoot.getChildren() 209 .stream() 210 .mapToLong(child -> _getFileNumber(child)) 211 .sum(); 212 return Map.of(__DOCUMENT_NUMBER_HEADER_ID, fileNumber); 213 } 214 else 215 { 216 return Map.of(__DOCUMENT_NUMBER_HEADER_ID, __SIZE_INACTIVE); 217 } 218 } 219 220 private long _getRessourceSize(AmetysObject document) 221 { 222 if (document instanceof Resource) 223 { 224 Resource file = (Resource) document; 225 return file.getLength(); 226 } 227 else if (document instanceof ResourceCollection) 228 { 229 ResourceCollection folder = (ResourceCollection) document; 230 return folder.getChildren() 231 .stream() 232 .mapToLong(child -> _getRessourceSize(child)) 233 .sum(); 234 } 235 return 0; 236 } 237 238 private long _getFileNumber(AmetysObject document) 239 { 240 if (document instanceof Resource) 241 { 242 return 1; 243 } 244 else if (document instanceof ResourceCollection) 245 { 246 ResourceCollection folder = (ResourceCollection) document; 247 return folder.getChildren() 248 .stream() 249 .mapToLong(child -> _getFileNumber(child)) 250 .sum(); 251 } 252 return 0; 253 } 254 255 @Override 256 public List<StatisticColumn> _getInternalStatisticModel() 257 { 258 259 return List.of(new StatisticColumn(__DOCUMENT_NUMBER_HEADER_ID, new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_STATISTICS_TOOL_COLUMN_FILE_NUMBER")) 260 .withRenderer("Ametys.plugins.workspaces.project.tool.ProjectsGridHelper.renderElements") 261 .withType(StatisticsColumnType.LONG) 262 .withGroup(GROUP_HEADER_ELEMENTS_ID)); 263 } 264 265 @Override 266 protected long _getModuleSize(Project project) 267 { 268 return getModuleRoot(project, false).getChildren() 269 .stream() 270 .mapToLong(child -> _getRessourceSize(child)) 271 .sum(); 272 } 273 274 @Override 275 protected boolean _showModuleSize() 276 { 277 return true; 278 } 279 280 @Override 281 public Set<String> getAllEventTypes() 282 { 283 return Set.of(ObservationConstants.EVENT_RESOURCE_CREATED, 284 ObservationConstants.EVENT_RESOURCE_COMMENTED, 285 ObservationConstants.EVENT_RESOURCE_DELETED, 286 ObservationConstants.EVENT_RESOURCE_MOVED, 287 ObservationConstants.EVENT_RESOURCE_RENAMED, 288 ObservationConstants.EVENT_RESOURCE_UPDATED); 289 } 290}