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