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.stream.Collectors;
024import java.util.stream.Stream;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.commons.lang3.StringUtils;
031
032import org.ametys.core.right.Profile;
033import org.ametys.core.right.RightManager;
034import org.ametys.core.right.RightManager.RightResult;
035import org.ametys.core.right.RightProfilesDAO;
036import org.ametys.core.ui.Callable;
037import org.ametys.core.user.CurrentUserProvider;
038import org.ametys.plugins.explorer.ExplorerNode;
039import org.ametys.plugins.explorer.resources.Resource;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041import org.ametys.plugins.repository.UnknownAmetysObjectException;
042import org.ametys.plugins.workspaces.project.ProjectManager;
043import org.ametys.plugins.workspaces.project.modules.WorkspaceModule;
044import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
045import org.ametys.plugins.workspaces.project.objects.Project;
046import org.ametys.runtime.config.Config;
047import org.ametys.runtime.i18n.I18nizableText;
048import org.ametys.runtime.plugin.component.AbstractLogEnabled;
049import org.ametys.runtime.plugin.component.PluginAware;
050
051/**
052 * Helper related to rights management for projects.
053 */
054public class ProjectRightHelper extends AbstractLogEnabled implements Serviceable, Component, PluginAware
055{
056    /** Avalon Role */
057    public static final String ROLE = ProjectRightHelper.class.getName();
058    
059    private static final String __PROJECT_RIGHT_PROFILE = "PROJECT";
060    
061    /** Ametys object resolver */
062    protected AmetysObjectResolver _resolver;
063    
064    /** Project manager */
065    protected ProjectManager _projectManager;
066    
067    /** Right manager */
068    protected RightManager _rightManager;
069    
070    /** Right profiles manager */
071    protected RightProfilesDAO _rightProfilesDao;
072    
073    /** Current user provider */
074    protected CurrentUserProvider _currentUserProvider;
075    
076    /** Module managers EP */
077    protected WorkspaceModuleExtensionPoint _moduleManagerEP;
078
079    private String _pluginName;
080    
081    @Override
082    public void service(ServiceManager manager) throws ServiceException
083    {
084        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
085        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
086        _rightManager = (RightManager) manager.lookup(RightManager.ROLE);
087        _rightProfilesDao = (RightProfilesDAO) manager.lookup(RightProfilesDAO.ROLE);
088        _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
089        _moduleManagerEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE);
090    }
091    
092    public void setPluginInfo(String pluginName, String featureName, String id)
093    {
094        _pluginName = pluginName;
095    }
096    /**
097     * Retrieves all project profile given the "profile list" configuration parameter
098     * Profile order is guaranteed to be the same as in the configuration parameter.
099     * @return the projects
100     */
101    public List<Profile> getProfileList()
102    {
103        Map<String, Profile> profileMap = _rightProfilesDao.getProfiles().stream().collect(Collectors.toMap(Profile::getId, item -> item));
104        String rawProjectProfileIds = StringUtils.defaultString(Config.getInstance().getValueAsString("workspaces.profile.list"));
105        
106        // Collect project profiles (unexisting entries are filtered out).
107        return Arrays.stream(StringUtils.split(rawProjectProfileIds, ','))
108            .map(id -> 
109            {
110                Profile p = profileMap.get(id);
111                
112                // log null entries
113                if (p == null)
114                {
115                    getLogger().warn("Could not find profile with id '{}'.", id);
116                }
117                return p;
118            })
119            .filter(Objects::nonNull)
120            .collect(Collectors.toList());
121    }
122    
123    /**
124     * Get the list of profiles and the list of modules available for rights affectation in the project.
125     * @param projectName The project to check if the modules are activated. Can be null to ignore
126     * @param includeAllModules True to include modules not manager by the WorkspaceModuleManagerExtensionPoint
127     * @return the project rights data
128     */
129    @Callable
130    public Map<String, Object> getProjectRightsData(String projectName, boolean includeAllModules)
131    {
132        // profiles
133        List<Object> profiles = getProfileList()
134            .stream()
135            .map(this::_getProfileRightData)
136            .collect(Collectors.toList());
137        
138        
139        Project project = projectName != null ? _projectManager.getProject(projectName) : null;
140        
141        // modules
142        Stream<Map<String, Object>> stream = _moduleManagerEP.getExtensionsIds().stream().map(moduleId -> _moduleManagerEP.getExtension(moduleId)).map(module -> _getModuleRightData(project, module));
143        if (includeAllModules)
144        {
145            stream = Stream.concat(Stream.of(_getProjectRightData()), stream);
146        }
147        List<Object> modules = stream.filter(Objects::nonNull).collect(Collectors.toList());
148        
149        Map<String, Object> result = new HashMap<>();
150        result.put("profiles", profiles);
151        result.put("modules", modules);
152        
153        return result;
154    }
155    
156    private Map<String, Object> _getProfileRightData(Profile profile)
157    {
158        Map<String, Object> data = new HashMap<>();
159        data.put("id", profile.getId());
160        data.put("label", profile.getLabel());
161        return data;
162    }
163    
164    private Map<String, Object> _getModuleRightData(Project project, WorkspaceModule module)
165    {
166        if (project != null && !_projectManager.isModuleActivated(project, module.getId()))
167        {
168            return null;
169        }
170        
171        Map<String, Object> data = new HashMap<>();
172        data.put("id", module.getId());
173        data.put("label", module.getModuleTitle());
174        return data;
175    }    
176    
177    private Map<String, Object> _getProjectRightData()
178    {
179        Map<String, Object> data = new HashMap<>();
180        data.put("id", __PROJECT_RIGHT_PROFILE);
181        data.put("label", new I18nizableText("plugin." + _pluginName, "PLUGINS_WORKSPACES_PROJECT_SERVICE_PROFILE_TO_PROJECT_LABEL"));
182        return data;
183    }
184    
185    /**
186     * Test if the current user has the right on the project
187     * @param rightId The right id
188     * @param projectId The project id
189     * @return true if has right
190     */
191    @Callable
192    public boolean hasRightOnProject(String rightId, String projectId)
193    {
194        try
195        {
196            return hasRight(rightId, _resolver.<Project>resolveById(projectId));
197        }
198        catch (UnknownAmetysObjectException e)
199        {
200            getLogger().warn("Trying to test right on an unknown project. Requested id : {}", projectId, e);
201            return false;
202        }
203    }
204    
205    /**
206     * Test if the current user has the right on the project
207     * @param rightId The right id
208     * @param project The project
209     * @return true if has right
210     */
211    public boolean hasRight(String rightId, Project project)
212    {
213        return _rightManager.hasRight(_currentUserProvider.getUser(), rightId, project) == RightResult.RIGHT_ALLOW;
214    }
215    
216    /**
217     * Test if the current user has a read access on the project
218     * @param projectId The project id
219     * @return true if has read access
220     */
221    @Callable
222    public boolean hasReadAccessOnProject(String projectId)
223    {
224        try
225        {
226            return hasReadAccess(_resolver.<Project>resolveById(projectId));
227        }
228        catch (UnknownAmetysObjectException e)
229        {
230            getLogger().warn("Trying to test read access on an unknown project. Requested id : {}", projectId, e);
231            return false;
232        }
233    }
234    
235    /**
236     * Test if the current user has a read access on the project
237     * @param project The project
238     * @return true if has read access
239     */
240    public boolean hasReadAccess(Project project)
241    {
242        return _rightManager.hasReadAccess(_currentUserProvider.getUser(), project);
243    }
244    
245    /**
246     * Test if the current user has the right on an explorer node
247     * @param rightId The right id
248     * @param explorerNodeId The explorer node id
249     * @return true if has right
250     */
251    @Callable
252    public boolean hasRightOnExplorerNode(String rightId, String explorerNodeId)
253    {
254        try
255        {
256            return hasRight(rightId, _resolver.<ExplorerNode>resolveById(explorerNodeId));
257        }
258        catch (UnknownAmetysObjectException e)
259        {
260            getLogger().warn("Trying to test right on an unknown explorer node. Requested id : {}", explorerNodeId, e);
261            return false;
262        }
263    }
264    
265    /**
266     * Test if the current user has the right on an explorer node
267     * @param rightId The right id
268     * @param explorerNode The explorer node
269     * @return true if has right
270     */
271    public boolean hasRight(String rightId, ExplorerNode explorerNode)
272    {
273        return _rightManager.hasRight(_currentUserProvider.getUser(), rightId, explorerNode) == RightResult.RIGHT_ALLOW;
274    }
275    
276    /**
277     * Test if the current user has a read access on an explorer node
278     * @param explorerNodeId The explorer node id
279     * @return true if has read access
280     */
281    @Callable
282    public boolean hasReadAccessOnExplorerNode(String explorerNodeId)
283    {
284        try
285        {
286            return hasReadAccess(_resolver.<ExplorerNode>resolveById(explorerNodeId));
287        }
288        catch (UnknownAmetysObjectException e)
289        {
290            getLogger().warn("Trying to test read access on an unknown explorer node. Requested id : {}", explorerNodeId, e);
291            return false;
292        }
293    }
294    
295    /**
296     * Test if the current user has a read access on an explorer node
297     * @param explorerNode The explorer node
298     * @return true if has read access
299     */
300    public boolean hasReadAccess(ExplorerNode explorerNode)
301    {
302        return _rightManager.currentUserHasReadAccess(explorerNode);
303    }
304    
305    /**
306     * Test if the current user has a read access on a resource
307     * @param resource The resource
308     * @return true if has read access
309     */
310    public boolean hasReadAccess(Resource resource)
311    {
312        return _rightManager.currentUserHasReadAccess(resource);
313    }
314}