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}