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