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.project.rights; 017 018import java.util.Arrays; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Objects; 023import java.util.Set; 024import java.util.stream.Collectors; 025import java.util.stream.Stream; 026 027import org.apache.avalon.framework.component.Component; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.commons.lang3.StringUtils; 032import org.apache.http.annotation.Obsolete; 033 034import org.ametys.core.right.Profile; 035import org.ametys.core.right.RightManager; 036import org.ametys.core.right.RightManager.RightResult; 037import org.ametys.core.right.RightProfilesDAO; 038import org.ametys.core.ui.Callable; 039import org.ametys.core.user.CurrentUserProvider; 040import org.ametys.plugins.explorer.ExplorerNode; 041import org.ametys.plugins.repository.AmetysObject; 042import org.ametys.plugins.repository.AmetysObjectResolver; 043import org.ametys.plugins.workspaces.WorkspacesConstants; 044import org.ametys.plugins.workspaces.about.AboutWorkspaceModule; 045import org.ametys.plugins.workspaces.alert.AlertWorkspaceModule; 046import org.ametys.plugins.workspaces.calendars.CalendarWorkspaceModule; 047import org.ametys.plugins.workspaces.documents.DocumentWorkspaceModule; 048import org.ametys.plugins.workspaces.members.MembersWorkspaceModule; 049import org.ametys.plugins.workspaces.minisite.MiniSiteWorkspaceModule; 050import org.ametys.plugins.workspaces.news.NewsWorkspaceModule; 051import org.ametys.plugins.workspaces.project.ProjectConstants; 052import org.ametys.plugins.workspaces.project.ProjectManager; 053import org.ametys.plugins.workspaces.project.modules.WorkspaceModule; 054import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 055import org.ametys.plugins.workspaces.project.objects.Project; 056import org.ametys.plugins.workspaces.wall.WallContentModule; 057import org.ametys.runtime.config.Config; 058import org.ametys.runtime.plugin.component.AbstractLogEnabled; 059 060/** 061 * Helper related to rights management for projects. 062 */ 063public class ProjectRightHelper extends AbstractLogEnabled implements Serviceable, Component 064{ 065 /** Avalon Role */ 066 public static final String ROLE = ProjectRightHelper.class.getName(); 067 068 @Obsolete // For v1 project only 069 private static final String __PROJECT_RIGHT_PROFILE = "PROJECT"; 070 071 /** Ametys object resolver */ 072 protected AmetysObjectResolver _resolver; 073 074 /** Project manager */ 075 protected ProjectManager _projectManager; 076 077 /** Right manager */ 078 protected RightManager _rightManager; 079 080 /** Right profiles manager */ 081 protected RightProfilesDAO _rightProfilesDao; 082 083 /** Current user provider */ 084 protected CurrentUserProvider _currentUserProvider; 085 086 /** Workspace Module ExtensionPoint */ 087 protected WorkspaceModuleExtensionPoint _workspaceModuleEP; 088 089 /** Association ContentTypeId, Module */ 090 protected Map<String, WorkspaceModule> _contentTypesToModule; 091 092 /** Module managers EP */ 093 protected WorkspaceModuleExtensionPoint _moduleManagerEP; 094 095 private Set<String> _profileIds; 096 097 098 @Override 099 public void service(ServiceManager manager) throws ServiceException 100 { 101 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 102 _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE); 103 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 104 _rightProfilesDao = (RightProfilesDAO) manager.lookup(RightProfilesDAO.ROLE); 105 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 106 _moduleManagerEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE); 107 108 _workspaceModuleEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE); 109 _contentTypesToModule = Map.of( 110 WorkspacesConstants.WALL_CONTENT_CONTENT_TYPE_ID, _workspaceModuleEP.getModule(WallContentModule.WALLCONTENT_MODULE_ID), 111 WorkspacesConstants.PROJECT_NEWS_CONTENT_TYPE_ID, _workspaceModuleEP.getModule(NewsWorkspaceModule.NEWS_MODULE_ID), 112 WorkspacesConstants.PROJECT_ALERT_CONTENT_TYPE_ID, _workspaceModuleEP.getModule(AlertWorkspaceModule.ALERT_MODULE_ID), 113 WorkspacesConstants.PROJECT_ARTICLE_CONTENT_TYPE, _workspaceModuleEP.getModule(MiniSiteWorkspaceModule.MINISITE_MODULE_ID), 114 WorkspacesConstants.ABOUT_CONTENT_TYPE, _workspaceModuleEP.getModule(AboutWorkspaceModule.ABOUT_MODULE_ID) 115 ); 116 } 117 118 /** 119 * The association of all project content types and associated modules 120 * @return The association 121 */ 122 public Map<String, WorkspaceModule> getProjectContentTypesAndModules() 123 { 124 return _contentTypesToModule; 125 } 126 127 /** 128 * Retrieves all project profiles ids given the "profile list" configuration parameter 129 * Profile order is guaranteed to be the same as in the configuration parameter. 130 * @return the projects 131 */ 132 public synchronized Set<String> getProfilesIds() 133 { 134 if (_profileIds == null) 135 { 136 String rawProjectProfileIds = StringUtils.defaultString(Config.getInstance().getValue("workspaces.profile.list")); 137 _profileIds = Arrays.stream(StringUtils.split(rawProjectProfileIds, ',')).collect(Collectors.toSet()); 138 } 139 return _profileIds; 140 } 141 142 /** 143 * Retrieves all project profile given the "profile list" configuration parameter 144 * Profile order is guaranteed to be the same as in the configuration parameter. 145 * @return the projects 146 */ 147 public Set<Profile> getProfiles() 148 { 149 // getProfiles(null) to get only shared profile 150 Map<String, Profile> profileMap = _rightProfilesDao.getProfiles(null).stream().collect(Collectors.toMap(Profile::getId, item -> item)); 151 152 // Collect project profiles (unexisting entries are filtered out). 153 return getProfilesIds().stream() 154 .map(id -> 155 { 156 Profile p = profileMap.get(id); 157 158 // log null entries 159 if (p == null) 160 { 161 getLogger().warn("Could not find profile with id '{}'.", id); 162 } 163 164 return p; 165 }) 166 .filter(Objects::nonNull) 167 .collect(Collectors.toSet()); 168 } 169 170 /** 171 * Get the list of profiles and the list of modules available for rights affectation in the project. 172 * @param projectName The project to check if the modules are activated. Can be null to ignore 173 * @return the project rights data 174 */ 175 @Callable 176 public Map<String, Object> getProjectRightsData(String projectName) 177 { 178 // profiles 179 List<Object> profiles = getProfiles() 180 .stream() 181 .map(this::_getProfileRightData) 182 .collect(Collectors.toList()); 183 184 Project project = projectName != null ? _projectManager.getProject(projectName) : null; 185 186 // modules 187 Stream<Map<String, Object>> stream = _moduleManagerEP.getExtensionsIds().stream().map(moduleId -> _moduleManagerEP.getExtension(moduleId)).map(module -> _getModuleRightData(project, module)); 188 List<Object> modules = stream.filter(Objects::nonNull).collect(Collectors.toList()); 189 190 Map<String, Object> result = new HashMap<>(); 191 result.put("profiles", profiles); 192 result.put("modules", modules); 193 194 return result; 195 } 196 197 private Map<String, Object> _getProfileRightData(Profile profile) 198 { 199 Map<String, Object> data = new HashMap<>(); 200 data.put("id", profile.getId()); 201 data.put("label", profile.getLabel()); 202 return data; 203 } 204 205 private Map<String, Object> _getModuleRightData(Project project, WorkspaceModule module) 206 { 207 if (project != null && !_projectManager.isModuleActivated(project, module.getId())) 208 { 209 return null; 210 } 211 212 Map<String, Object> data = new HashMap<>(); 213 data.put("id", module.getId()); 214 data.put("label", module.getModuleTitle()); 215 return data; 216 } 217 218 /** 219 * Determines if the current user can view the members of a project 220 * @param project the project 221 * @return true if user can view members 222 */ 223 public boolean canViewMembers(Project project) 224 { 225 return _rightManager.currentUserHasReadAccess(project); 226 } 227 228 /** 229 * Determines if the current user has right to add member on project 230 * @param project the project 231 * @return true if user can add member 232 */ 233 public boolean canAddMember(Project project) 234 { 235 MembersWorkspaceModule module = _moduleManagerEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID); 236 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 237 { 238 AmetysObject moduleRoot = module.getModuleRoot(project, false); 239 return moduleRoot != null && _rightManager.currentUserHasRight(ProjectConstants.RIGHT_PROJECT_ADD_MEMBER, moduleRoot) == RightResult.RIGHT_ALLOW; 240 } 241 242 return false; 243 } 244 245 /** 246 * Determines if the current user has right to edit member on project 247 * @param project the project 248 * @return true if user can edit member 249 */ 250 public boolean canEditMember(Project project) 251 { 252 return canAddMember(project); 253 } 254 255 /** 256 * Determines if the current user has right to add member on project 257 * @param project the project 258 * @return true if user can remove member 259 */ 260 public boolean canRemoveMember(Project project) 261 { 262 return _hasRightOnMembers(project, ProjectConstants.RIGHT_PROJECT_REMOVE_MEMBER); 263 } 264 265 private boolean _hasRightOnMembers(Project project, String rightId) 266 { 267 MembersWorkspaceModule module = _moduleManagerEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID); 268 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 269 { 270 AmetysObject moduleRoot = module.getModuleRoot(project, false); 271 return moduleRoot != null && _rightManager.currentUserHasRight(rightId, moduleRoot) == RightResult.RIGHT_ALLOW; 272 } 273 274 return false; 275 } 276 277 /** 278 * Determines if the current user has right to add tags on project 279 * @param project the project 280 * @return true if user can add tags 281 */ 282 public boolean canAddTag(Project project) 283 { 284 return _hasRightOnTagsOrPlaces(project, ProjectConstants.RIGHT_PROJECT_ADD_TAG); 285 } 286 287 /** 288 * Determines if the current user has right to remove tags on project 289 * @param project the project 290 * @return true if user can remove tags 291 */ 292 public boolean canRemoveTag(Project project) 293 { 294 return _hasRightOnTagsOrPlaces(project, ProjectConstants.RIGHT_PROJECT_DELETE_TAG); 295 } 296 297 private boolean _hasRightOnTagsOrPlaces(Project project, String rightId) 298 { 299 WorkspaceModule module = _moduleManagerEP.getModule(CalendarWorkspaceModule.CALENDAR_MODULE_ID); 300 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 301 { 302 AmetysObject moduleRoot = module.getModuleRoot(project, false); 303 if (moduleRoot != null && _rightManager.currentUserHasRight(rightId, moduleRoot) == RightResult.RIGHT_ALLOW) 304 { 305 return true; 306 } 307 } 308 309 module = _moduleManagerEP.getModule(DocumentWorkspaceModule.DOCUMENT_MODULE_ID); 310 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 311 { 312 AmetysObject moduleRoot = module.getModuleRoot(project, false); 313 if (moduleRoot != null && _rightManager.currentUserHasRight(rightId, moduleRoot) == RightResult.RIGHT_ALLOW) 314 { 315 return true; 316 } 317 } 318 319 return false; 320 } 321 322 /** 323 * Test if the current user has the right on the project 324 * @param rightId The right id 325 * @param project The project 326 * @return true if has right 327 */ 328 public boolean hasRight(String rightId, Project project) 329 { 330 return _rightManager.hasRight(_currentUserProvider.getUser(), rightId, project) == RightResult.RIGHT_ALLOW; 331 } 332 333 /** 334 * Test if the current user has a read access on the project 335 * @param project The project 336 * @return true if has read access 337 */ 338 public boolean hasReadAccess(Project project) 339 { 340 return _rightManager.hasReadAccess(_currentUserProvider.getUser(), project); 341 } 342 343 /** 344 * Test if the current user has the right on an explorer node 345 * @param rightId The right id 346 * @param explorerNode The explorer node 347 * @return true if has right 348 */ 349 public boolean hasRight(String rightId, ExplorerNode explorerNode) 350 { 351 return _rightManager.hasRight(_currentUserProvider.getUser(), rightId, explorerNode) == RightResult.RIGHT_ALLOW; 352 } 353}