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}