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 Map<String, Profile> profileMap = _rightProfilesDao.getProfiles().stream().collect(Collectors.toMap(Profile::getId, item -> item)); 150 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 185 Project project = projectName != null ? _projectManager.getProject(projectName) : null; 186 187 // modules 188 Stream<Map<String, Object>> stream = _moduleManagerEP.getExtensionsIds().stream().map(moduleId -> _moduleManagerEP.getExtension(moduleId)).map(module -> _getModuleRightData(project, module)); 189 List<Object> modules = stream.filter(Objects::nonNull).collect(Collectors.toList()); 190 191 Map<String, Object> result = new HashMap<>(); 192 result.put("profiles", profiles); 193 result.put("modules", modules); 194 195 return result; 196 } 197 198 private Map<String, Object> _getProfileRightData(Profile profile) 199 { 200 Map<String, Object> data = new HashMap<>(); 201 data.put("id", profile.getId()); 202 data.put("label", profile.getLabel()); 203 return data; 204 } 205 206 private Map<String, Object> _getModuleRightData(Project project, WorkspaceModule module) 207 { 208 if (project != null && !_projectManager.isModuleActivated(project, module.getId())) 209 { 210 return null; 211 } 212 213 Map<String, Object> data = new HashMap<>(); 214 data.put("id", module.getId()); 215 data.put("label", module.getModuleTitle()); 216 return data; 217 } 218 219 /** 220 * Determines if the current user can view the members of a project 221 * @param project the project 222 * @return true if user can view members 223 */ 224 public boolean canViewMembers(Project project) 225 { 226 return _rightManager.currentUserHasReadAccess(project); 227 } 228 229 /** 230 * Determines if the current user has right to add member on project 231 * @param project the project 232 * @return true if user can add member 233 */ 234 public boolean canAddMember(Project project) 235 { 236 MembersWorkspaceModule module = _moduleManagerEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID); 237 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 238 { 239 AmetysObject moduleRoot = module.getModuleRoot(project, false); 240 return moduleRoot != null && _rightManager.currentUserHasRight(ProjectConstants.RIGHT_PROJECT_ADD_MEMBER, moduleRoot) == RightResult.RIGHT_ALLOW; 241 } 242 243 return false; 244 } 245 246 /** 247 * Determines if the current user has right to edit member on project 248 * @param project the project 249 * @return true if user can edit member 250 */ 251 public boolean canEditMember(Project project) 252 { 253 return canAddMember(project); 254 } 255 256 /** 257 * Determines if the current user has right to add member on project 258 * @param project the project 259 * @return true if user can remove member 260 */ 261 public boolean canRemoveMember(Project project) 262 { 263 return _hasRightOnMembers(project, ProjectConstants.RIGHT_PROJECT_REMOVE_MEMBER); 264 } 265 266 private boolean _hasRightOnMembers(Project project, String rightId) 267 { 268 MembersWorkspaceModule module = _moduleManagerEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID); 269 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 270 { 271 AmetysObject moduleRoot = module.getModuleRoot(project, false); 272 return moduleRoot != null && _rightManager.currentUserHasRight(rightId, moduleRoot) == RightResult.RIGHT_ALLOW; 273 } 274 275 return false; 276 } 277 278 /** 279 * Determines if the current user has right to add tags on project 280 * @param project the project 281 * @return true if user can add tags 282 */ 283 public boolean canAddTag(Project project) 284 { 285 return _hasRightOnTagsOrPlaces(project, ProjectConstants.RIGHT_PROJECT_ADD_TAG); 286 } 287 288 /** 289 * Determines if the current user has right to remove tags on project 290 * @param project the project 291 * @return true if user can remove tags 292 */ 293 public boolean canRemoveTag(Project project) 294 { 295 return _hasRightOnTagsOrPlaces(project, ProjectConstants.RIGHT_PROJECT_DELETE_TAG); 296 } 297 298 private boolean _hasRightOnTagsOrPlaces(Project project, String rightId) 299 { 300 WorkspaceModule module = _moduleManagerEP.getModule(CalendarWorkspaceModule.CALENDAR_MODULE_ID); 301 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 302 { 303 AmetysObject moduleRoot = module.getModuleRoot(project, false); 304 if (moduleRoot != null && _rightManager.currentUserHasRight(rightId, moduleRoot) == RightResult.RIGHT_ALLOW) 305 { 306 return true; 307 } 308 } 309 310 module = _moduleManagerEP.getModule(DocumentWorkspaceModule.DOCUMENT_MODULE_ID); 311 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 312 { 313 AmetysObject moduleRoot = module.getModuleRoot(project, false); 314 if (moduleRoot != null && _rightManager.currentUserHasRight(rightId, moduleRoot) == RightResult.RIGHT_ALLOW) 315 { 316 return true; 317 } 318 } 319 320 return false; 321 } 322 323 /** 324 * Test if the current user has the right on the project 325 * @param rightId The right id 326 * @param project The project 327 * @return true if has right 328 */ 329 public boolean hasRight(String rightId, Project project) 330 { 331 return _rightManager.hasRight(_currentUserProvider.getUser(), rightId, project) == RightResult.RIGHT_ALLOW; 332 } 333 334 /** 335 * Test if the current user has a read access on the project 336 * @param project The project 337 * @return true if has read access 338 */ 339 public boolean hasReadAccess(Project project) 340 { 341 return _rightManager.hasReadAccess(_currentUserProvider.getUser(), project); 342 } 343 344 /** 345 * Test if the current user has the right on an explorer node 346 * @param rightId The right id 347 * @param explorerNode The explorer node 348 * @return true if has right 349 */ 350 public boolean hasRight(String rightId, ExplorerNode explorerNode) 351 { 352 return _rightManager.hasRight(_currentUserProvider.getUser(), rightId, explorerNode) == RightResult.RIGHT_ALLOW; 353 } 354}