001/*
002 *  Copyright 2024 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.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.stream.Collectors;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.commons.lang3.StringUtils;
028
029import org.ametys.cms.repository.comment.AbstractComment;
030import org.ametys.cms.tag.Tag;
031import org.ametys.core.user.UserIdentity;
032import org.ametys.core.util.DateUtils;
033import org.ametys.plugins.explorer.ModifiableExplorerNode;
034import org.ametys.plugins.explorer.resources.ModifiableResource;
035import org.ametys.plugins.explorer.resources.Resource;
036import org.ametys.plugins.explorer.resources.ResourceCollection;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.ModifiableAmetysObject;
039import org.ametys.plugins.repository.tag.TagAwareAmetysObject;
040import org.ametys.plugins.workspaces.WorkspacesHelper;
041import org.ametys.plugins.workspaces.documents.WorkspaceExplorerResourceDAO.ResourceType;
042import org.ametys.plugins.workspaces.project.ProjectManager;
043import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
044import org.ametys.plugins.workspaces.project.objects.Project;
045import org.ametys.plugins.workspaces.util.WorkspaceObjectJSONHelper;
046
047/**
048 * Helper to convert documents to JSON
049 */
050public class DocumentsJSONHelper extends WorkspaceObjectJSONHelper implements Component
051{
052    /** The Avalon role */
053    public static final String ROLE = DocumentsJSONHelper.class.getName();
054
055    /** The project manager */
056    protected ProjectManager _projectManager;
057    
058    private WorkspaceModuleExtensionPoint _moduleEP;
059    private WorkspacesHelper _workspaceHelper;
060    
061    @Override
062    public void service(ServiceManager manager) throws ServiceException
063    {
064        super.service(manager);
065        _moduleEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE);
066        _workspaceHelper = (WorkspacesHelper) manager.lookup(WorkspacesHelper.ROLE);
067        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
068    }
069    
070    /**
071     * return a list of comments in JSON format
072     * @param <T> type of the value to retrieve
073     * @param comments the comments to translate as JSON
074     * @param lang the current language
075     * @param siteName The current site name
076     * @return list of comments
077     */
078    public <T extends AbstractComment> List<Map<String, Object>> commentsToJson(List<T> comments, String lang, String siteName)
079    {
080        List<Map<String, Object>> json = new ArrayList<>();
081
082        for (T comment : comments)
083        {
084            Map<String, Object> commentAsJSON = _commentToJson(comment, lang, siteName, null, true);
085            // As we do not want file comments to be editable or deletable, remove rights
086            commentAsJSON.put("canHandle", false);
087            json.add(commentAsJSON);
088        }
089
090        return json;
091    }
092
093    /**
094     * Internal method to extract the valuable data of a folder
095     * @param folder The folder
096     * @return the valuable folder data
097     */
098    public Map<String, Object> extractCommonFolderData(ResourceCollection folder)
099    {
100        Map<String, Object> data = new HashMap<>();
101        
102        data.put("id", folder.getId());
103        data.put("name", folder.getName());
104        data.put("type", ResourceType.FOLDER.name().toLowerCase());
105        data.put("description", StringUtils.defaultString(folder.getDescription()));
106        
107        AmetysObject parent = folder.getParent();
108        if (parent != null && parent instanceof ResourceCollection)
109        {
110            data.put("location", parent.getName());
111            data.put("parentId", parent.getId());
112        }
113        
114        
115        data.put("modifiable", folder instanceof ModifiableAmetysObject);
116        data.put("canCreateChild", folder instanceof ModifiableExplorerNode);
117        DocumentWorkspaceModule module = _moduleEP.getModule(DocumentWorkspaceModule.DOCUMENT_MODULE_ID);
118        data.put("length", String.valueOf(module.getRessourceSize(folder)));
119
120        data.put("notification", false); // TODO unread notification (not yet supported)
121        
122        return data;
123    }
124
125    /**
126     * Internal method to extract the valuable data of a file
127     * @param file The file
128     * @return the valuable file data
129     */
130    public Map<String, Object> extractCommonFileData(Resource file)
131    {
132        Map<String, Object> data = new HashMap<>();
133        
134        data.put("id", file.getId());
135        data.put("name", file.getName());
136
137        data.put("type", ResourceType.FILE.name().toLowerCase());
138        data.put("fileType", _workspaceHelper.getFileType(file).name().toLowerCase());
139        data.put("fileExtension", StringUtils.substringAfterLast(file.getName(), "."));
140        
141        AmetysObject parent = file.getParent();
142        if (parent != null && parent instanceof ResourceCollection)
143        {
144            data.put("location", parent.getName());
145            data.put("parentId", parent.getId());
146            data.put("parentPath", ((ResourceCollection) parent).getExplorerPath());
147        }
148        
149        data.put("modifiable", file instanceof ModifiableResource);
150        data.put("canCreateChild", file instanceof ModifiableExplorerNode);
151        data.put("tags", tags2json(file));
152        data.put("mimetype", file.getMimeType());
153        data.put("length", String.valueOf(file.getLength()));
154        
155        boolean image = _workspaceHelper.isImage(file);
156        if (image)
157        {
158            data.put("image", true);
159        }
160        
161        UserIdentity creatorIdentity = file.getCreator();
162        data.put("creator", _userHelper.user2json(creatorIdentity));
163        data.put("creationDate", DateUtils.dateToString(file.getCreationDate()));
164        
165        UserIdentity contribIdentity = file.getLastContributor();
166        data.put("author", _userHelper.user2json(contribIdentity));
167        data.put("lastModified", DateUtils.dateToString(file.getLastModified()));
168        
169        return data;
170    }
171
172    /**
173     * Extract resource tags as JSON
174     * @param file the file containing the tags
175     * @return list of tags as JSON
176     */
177    public List<Map<String, Object>> tags2json(Resource file)
178    {
179        Map<String, Object> contextParameters = new HashMap<>();
180
181        Project project = _projectManager.getParentProject(file);
182        // if we can not get project from file, such as when we handle a trashed file, try to get project from request
183        if (project == null)
184        {
185            project = _workspaceHelper.getProjectFromRequest();
186        }
187        if (project != null)
188        {
189            contextParameters.put("projectName", project.getName());
190        }
191        
192        
193        return ((TagAwareAmetysObject) file).getTags()
194            .stream()
195            .filter(tag -> _tagProviderExtensionPoint.hasTag(tag, contextParameters))
196            .map(tag -> _tagProviderExtensionPoint.getTag(tag, contextParameters))
197            .map(this::tag2json)
198            .collect(Collectors.toList());
199    }
200
201    /**
202     * Extract tag as JSON
203     * @param tag the tag to convert
204     * @return tag as JSON
205     */
206    public Map<String, Object> tag2json(Tag tag)
207    {
208        Map<String, Object> tagMap = new HashMap<>();
209        tagMap.put("text", tag.getTitle());
210        tagMap.put("title", tag.getTitle());
211        tagMap.put("name", tag.getName());
212        tagMap.put("color", null); // FIXME tag color is not supported yet
213        
214        return tagMap;
215    }
216    
217}