001/*
002 *  Copyright 2020 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;
017
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Map;
021import java.util.Objects;
022import java.util.Optional;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.cocoon.Constants;
032import org.apache.cocoon.components.ContextHelper;
033import org.apache.cocoon.environment.Request;
034import org.apache.commons.lang3.StringUtils;
035
036import org.ametys.cms.content.indexing.solr.SolrResourceGroupedMimeTypes;
037import org.ametys.core.right.RightManager;
038import org.ametys.core.right.RightManager.RightResult;
039import org.ametys.core.user.CurrentUserProvider;
040import org.ametys.core.user.UserIdentity;
041import org.ametys.core.util.URIUtils;
042import org.ametys.plugins.explorer.resources.Resource;
043import org.ametys.plugins.repository.TraversableAmetysObject;
044import org.ametys.plugins.repository.tag.TaggableAmetysObject;
045import org.ametys.plugins.workspaces.project.ProjectConstants;
046import org.ametys.plugins.workspaces.project.ProjectManager;
047import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
048import org.ametys.plugins.workspaces.project.objects.Project;
049import org.ametys.plugins.workspaces.tags.ProjectTagsDAO;
050import org.ametys.runtime.authentication.AccessDeniedException;
051import org.ametys.runtime.plugin.component.AbstractLogEnabled;
052import org.ametys.web.URIPrefixHandler;
053import org.ametys.web.WebHelper;
054import org.ametys.web.repository.site.Site;
055import org.ametys.web.repository.site.SiteManager;
056import org.ametys.web.repository.sitemap.Sitemap;
057
058/**
059 * Utility classes for workspaces
060 *
061 */
062public class WorkspacesHelper extends AbstractLogEnabled implements Component, Serviceable, Contextualizable
063{
064    /** Avalon role */
065    public static final String ROLE = WorkspacesHelper.class.getName();
066
067    /** The right manager */
068    protected RightManager _rightManager;
069    
070    /** The workspace module extension point */
071    protected WorkspaceModuleExtensionPoint _workspaceModuleEP;
072
073    /** The current user provider. */
074    protected CurrentUserProvider _currentUserProvider;
075    
076    /**
077     * Enumeration for file type
078     */
079    public enum FileType
080    {
081        /** Text document */
082        TEXT,
083        /** PDF document */
084        PDF,
085        /** Spreadsheet */
086        SPREADSHEET,
087        /** Presentation */
088        PRES,
089        /** Image */
090        IMAGE,
091        /** Video */
092        VIDEO,
093        /** Audio */
094        AUDIO,
095        /** Archive */
096        ARCHIVE,
097        /** Unknown type */
098        UNKNOWN
099    }
100
101    private Context _context;
102    private org.apache.cocoon.environment.Context _cocoonContext;
103    private URIPrefixHandler _prefixHandler;
104    private ProjectTagsDAO _projectTagsDAO;
105    private SiteManager _siteManager;
106    private ProjectManager _projectManager;
107    
108    public void contextualize(Context context) throws ContextException
109    {
110        _context = context;
111        _cocoonContext = (org.apache.cocoon.environment.Context) _context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
112    }
113    
114    public void service(ServiceManager smanager) throws ServiceException
115    {
116        _prefixHandler = (URIPrefixHandler) smanager.lookup(URIPrefixHandler.ROLE);
117        _projectTagsDAO = (ProjectTagsDAO) smanager.lookup(ProjectTagsDAO.ROLE);
118        _projectManager = (ProjectManager) smanager.lookup(ProjectManager.ROLE);
119        _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE);
120
121        _rightManager = (RightManager) smanager.lookup(RightManager.ROLE);
122        _workspaceModuleEP = (WorkspaceModuleExtensionPoint) smanager.lookup(WorkspaceModuleExtensionPoint.ROLE);
123        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
124    }
125    
126    /**
127     * Determines if the resource file is an image
128     * @param file the resource
129     * @return true if the resource file is an image
130     */
131    public boolean isImage(Resource file)
132    {
133        return SolrResourceGroupedMimeTypes.getGroup(file.getMimeType())
134            .map(groupMimeType -> FileType.IMAGE == FileType.valueOf(groupMimeType.toUpperCase()))
135            .orElse(false);
136    }
137    
138    /**
139     * Get the file type of a resource file
140     * @param file the resource
141     * @return the {@link FileType}
142     */
143    public FileType getFileType(Resource file)
144    {
145        Optional<String> group = SolrResourceGroupedMimeTypes.getGroup(file.getMimeType());
146        
147        return group
148                .map(groupMimeType -> FileType.valueOf(groupMimeType.toUpperCase()))
149                .orElse(FileType.UNKNOWN);
150    }
151    
152    /**
153     * Get the file type of a resource from its name
154     * @param filename the resource's name
155     * @return the {@link FileType}
156     */
157    public FileType getFileType(String filename)
158    {
159        String mimeType = _cocoonContext.getMimeType(filename);
160        Optional<String> group = SolrResourceGroupedMimeTypes.getGroup(mimeType);
161        
162        return group
163                .map(groupMimeType -> FileType.valueOf(groupMimeType.toUpperCase()))
164                .orElse(FileType.UNKNOWN);
165    }
166
167    /**
168     * Get user avatar
169     * @param userIdentity the user identity
170     * @param lang the lang for user's content
171     * @param size the size in pixel of image
172     * @return the avatar url
173     */
174    public String getAvatar(UserIdentity userIdentity, String lang, int size)
175    {
176        StringBuilder sb = new StringBuilder();
177        
178        String siteName = WebHelper.getSiteName(_getRequest());
179        sb.append(_prefixHandler.getUriPrefix(siteName))
180            .append("/_plugins/user-directory/user/")
181            .append(userIdentity.getPopulationId())
182            .append("/")
183            .append(URIUtils.encodePath(userIdentity.getLogin()))
184            .append("/image_")
185            .append(size)
186            .append("?lang=")
187            .append(lang);
188        
189        return sb.toString();
190    }
191    
192    private Request _getRequest()
193    {
194        return ContextHelper.getRequest(_context);
195    }
196    
197    /**
198     * Get current project from request
199     * @return the current project or null if not found.
200     */
201    public Project getProjectFromRequest()
202    {
203        Request request = _getRequest();
204        String projectName = (String) request.getAttribute(WorkspacesConstants.REQUEST_ATTR_PROJECT_NAME);
205        
206        if (StringUtils.isNotEmpty(projectName))
207        {
208            return _projectManager.getProject(projectName);
209        }
210        
211        String siteName = WebHelper.getSiteName(request);
212        if (StringUtils.isNotEmpty(siteName) && _siteManager.hasSite(siteName))
213        {
214            Site site = _siteManager.getSite(siteName);
215            List<Project> projects = _projectManager.getProjectsForSite(site);
216            if (!projects.isEmpty())
217            {
218                return projects.get(0);
219            }
220        }
221        
222        return null;
223    }
224    
225    /**
226     * Handle tags for the edition of a TaggableAmetysObject
227     * @param taggableAmetysObject the object to edit
228     * @param tags the tags
229     * @param moduleRoot the module root, used to check tag creation rights if needed
230     * @return the created tags
231     */
232    public List<Map<String, Object>> handleTags(TaggableAmetysObject taggableAmetysObject, List<Object> tags, TraversableAmetysObject moduleRoot)
233    {
234        List<String> createdTags = new ArrayList<>();
235        List<Map<String, Object>> createdTagsJson = new ArrayList<>();
236        // Tag new tags
237        for (Object tag : tags)
238        {
239            // Tag doesn't exist so create the tag
240            if (tag instanceof Map)
241            {
242                if (_rightManager.currentUserHasRight(ProjectConstants.RIGHT_PROJECT_ADD_TAG, moduleRoot) != RightResult.RIGHT_ALLOW)
243                {
244                    throw new AccessDeniedException("User '" + _currentUserProvider.getUser() + "' tried to handle tags without convenient right.");
245                }
246                @SuppressWarnings("unchecked")
247                String tagText = (String) ((Map<String, Object>) tag).get("text");
248                List<Map<String, Object>> newTags = _projectTagsDAO.addTags(new String[] {tagText});
249                String newTag = (String) newTags.get(0).get("name");
250                taggableAmetysObject.tag(newTag);
251                createdTags.add(newTag);
252                createdTagsJson.addAll(newTags);
253            }
254            else
255            {
256                taggableAmetysObject.tag((String) tag);
257            }
258        }
259        // Untag unused tags
260        for (String tag : taggableAmetysObject.getTags())
261        {
262            if (!tags.contains(tag) && !createdTags.contains(tag))
263            {
264                taggableAmetysObject.untag(tag);
265            }
266        }
267        return createdTagsJson;
268    }
269
270    /**
271     * Get the lang for this project, or en if none found
272     * @param project the project to check
273     * @return a lang in this project
274     */
275    public String getLang(Project project)
276    {
277        /*
278         * get the site, then the sitemaps (transformed back to a stream of sitemap)
279         * then get the name
280         * return the 1st one, or "en" by default if none is available, or if the site could not be found
281         */
282        
283        Site site = project.getSite();
284        
285        if (site != null)
286        {
287            return site.getSitemaps()
288                       .stream()
289                       .filter(Objects::nonNull)
290                       .map(Sitemap::getName)
291                       .findFirst()
292                       .orElse("en");
293        }
294        else
295        {
296            return "en";
297        }
298    }
299}