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(ObservationConstants.EVENT_RESOURCE_CREATED, 200 ObservationConstants.EVENT_RESOURCE_COMMENTED, 201 ObservationConstants.EVENT_RESOURCE_RENAMED, 202 ObservationConstants.EVENT_RESOURCE_UPDATED); 203 } 204 205 @Override 206 public Map<String, Object> _getInternalStatistics(Project project, boolean isActive) 207 { 208 if (isActive) 209 { 210 ModifiableResourceCollection documentRoot = getModuleRoot(project, false); 211 long fileNumber = documentRoot.getChildren() 212 .stream() 213 .mapToLong(child -> _getFileNumber(child)) 214 .sum(); 215 return Map.of(__DOCUMENT_NUMBER_HEADER_ID, fileNumber); 216 } 217 else 218 { 219 return Map.of(__DOCUMENT_NUMBER_HEADER_ID, __SIZE_INACTIVE); 220 } 221 } 222 223 private long _getRessourceSize(AmetysObject document) 224 { 225 if (document instanceof Resource) 226 { 227 Resource file = (Resource) document; 228 return file.getLength(); 229 } 230 else if (document instanceof ResourceCollection) 231 { 232 ResourceCollection folder = (ResourceCollection) document; 233 return folder.getChildren() 234 .stream() 235 .mapToLong(child -> _getRessourceSize(child)) 236 .sum(); 237 } 238 return 0; 239 } 240 241 private long _getFileNumber(AmetysObject document) 242 { 243 if (document instanceof Resource) 244 { 245 return 1; 246 } 247 else if (document instanceof ResourceCollection) 248 { 249 ResourceCollection folder = (ResourceCollection) document; 250 return folder.getChildren() 251 .stream() 252 .mapToLong(child -> _getFileNumber(child)) 253 .sum(); 254 } 255 return 0; 256 } 257 258 @Override 259 public List<StatisticColumn> _getInternalStatisticModel() 260 { 261 262 return List.of(new StatisticColumn(__DOCUMENT_NUMBER_HEADER_ID, new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_STATISTICS_TOOL_COLUMN_FILE_NUMBER")) 263 .withRenderer("Ametys.plugins.workspaces.project.tool.ProjectsGridHelper.renderElements") 264 .withType(StatisticsColumnType.LONG) 265 .withGroup(GROUP_HEADER_ELEMENTS_ID)); 266 } 267 268 @Override 269 protected long _getModuleSize(Project project) 270 { 271 return getModuleRoot(project, false).getChildren() 272 .stream() 273 .mapToLong(child -> _getRessourceSize(child)) 274 .sum(); 275 } 276 277 @Override 278 protected boolean _showModuleSize() 279 { 280 return true; 281 } 282 283 @Override 284 public Set<String> getAllEventTypes() 285 { 286 return Set.of(ObservationConstants.EVENT_RESOURCE_CREATED, 287 ObservationConstants.EVENT_RESOURCE_COMMENTED, 288 ObservationConstants.EVENT_RESOURCE_DELETED, 289 ObservationConstants.EVENT_RESOURCE_MOVED, 290 ObservationConstants.EVENT_RESOURCE_RENAMED, 291 ObservationConstants.EVENT_RESOURCE_UPDATED); 292 } 293}