001/*
002 *  Copyright 2015 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.core.group;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.logger.AbstractLogEnabled;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.commons.lang3.StringUtils;
030
031import org.ametys.core.group.Group;
032import org.ametys.core.group.GroupDirectoryDAO;
033import org.ametys.core.group.GroupIdentity;
034import org.ametys.core.group.GroupManager;
035import org.ametys.core.group.InvalidModificationException;
036import org.ametys.core.group.ModifiableGroup;
037import org.ametys.core.group.directory.GroupDirectory;
038import org.ametys.core.group.directory.ModifiableGroupDirectory;
039import org.ametys.core.ui.Callable;
040import org.ametys.core.user.CurrentUserProvider;
041import org.ametys.core.user.UserIdentity;
042import org.ametys.plugins.core.user.UserHelper;
043
044/**
045 * DAO for manipulating {@link Group}
046 *
047 */
048public class GroupDAO extends AbstractLogEnabled implements Serviceable, Component
049{
050    /** The service manager */
051    protected ServiceManager _smanager;
052    /** The current user provider. */
053    protected CurrentUserProvider _currentUserProvider;
054    /** The group manager */
055    protected GroupManager _groupManager;
056    /** The DAO for group directories */
057    protected GroupDirectoryDAO _groupDirectoryDAO;
058    /** The user helper */
059    protected UserHelper _userHelper;
060
061    public void service(ServiceManager smanager) throws ServiceException
062    {
063        _smanager = smanager;
064        _groupManager = (GroupManager) smanager.lookup(GroupManager.ROLE);
065        _groupDirectoryDAO = (GroupDirectoryDAO) smanager.lookup(GroupDirectoryDAO.ROLE);
066        _userHelper = (UserHelper) smanager.lookup(UserHelper.ROLE);
067    }
068    
069    /**
070     * Creates a new group
071     * @param groupDirectoryId The id of the group directory
072     * @param name The group's name
073     * @return The group's information
074     * @throws InvalidModificationException If modification are not possible
075     */
076    @Callable
077    public Map<String, Object> addGroup(String groupDirectoryId, String name) throws InvalidModificationException
078    {
079        GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(groupDirectoryId);
080        
081        if (!(groupDirectory instanceof ModifiableGroupDirectory))
082        {
083            getLogger().error("Groups are not modifiable !");
084            throw new InvalidModificationException("Groups are not modifiable !");
085        }
086        
087        ModifiableGroupDirectory modifiableGroupDirectory = (ModifiableGroupDirectory) groupDirectory;
088        
089        if (getLogger().isDebugEnabled())
090        {
091            getLogger().debug("Starting group creation");
092        }
093        
094        if (StringUtils.isBlank(name))
095        {
096            throw new IllegalArgumentException("The new group name cannot be empty");
097        }
098        
099        if (getLogger().isInfoEnabled())
100        {
101            getLogger().info(String.format("User %s is adding a new group '%s'", _getCurrentUser(), name));
102        }
103
104        Group group = modifiableGroupDirectory.add(name);
105        
106        if (getLogger().isDebugEnabled())
107        {
108            getLogger().debug("Ending group creation");
109        }
110        
111        return group2Json(group);
112    }
113    
114    /**
115     * Set the users' group
116     * @param groupDirectoryId The id of the group directory
117     * @param groupId The group's id
118     * @param users The group's users
119     * @return The group's information
120     * @throws InvalidModificationException If modification are not possible
121     */
122    @Callable
123    public Map<String, Object> setUsersGroup (String groupDirectoryId, String groupId, List<Map<String, String>> users) throws InvalidModificationException
124    {
125        GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(groupDirectoryId);
126        
127        if (!(groupDirectory instanceof ModifiableGroupDirectory))
128        {
129            getLogger().error("Groups are not modifiable !");
130            throw new InvalidModificationException("Groups are not modifiable !");
131        }
132        
133        ModifiableGroupDirectory modifiableGroupDirectory = (ModifiableGroupDirectory) groupDirectory;
134        
135        if (getLogger().isDebugEnabled())
136        {
137            getLogger().debug("Starting group modification");
138        }
139        
140        if (getLogger().isInfoEnabled())
141        {
142            getLogger().info(String.format("User %s is editing the group '%s'", _getCurrentUser(), groupId));
143        }
144
145        ModifiableGroup group = modifiableGroupDirectory.getGroup(groupId);
146        if (group == null)
147        {
148            getLogger().warn(String.format("User %s tries to edit the group '%s' but the group does not exist.", _getCurrentUser(), groupId));
149            
150            Map<String, Object> result = new HashMap<>();
151            result.put("error", "unknown-group");
152            return result;
153        }
154        else
155        {
156            // Edit users
157            group.removeUsers();
158            
159            for (Map<String, String> user : users)
160            {
161                UserIdentity userIdentity = _userHelper.json2userIdentity(user);
162                if (userIdentity != null)
163                {
164                    group.addUser(userIdentity);
165                }
166            }
167            modifiableGroupDirectory.update(group);
168        }
169        
170        if (getLogger().isDebugEnabled())
171        {
172            getLogger().debug("Ending group modification");
173        }
174
175        return group2Json(group);
176    }
177    
178    /**
179     * Add users to group
180     * @param groupDirectoryId The id of the group directory
181     * @param groupId The group's id
182     * @param users The users to add
183     * @return The group's information
184     * @throws InvalidModificationException If modification are not possible
185     */
186    @Callable
187    public Map<String, Object> addUsersGroup (String groupDirectoryId, String groupId, List<Map<String, String>> users) throws InvalidModificationException
188    {
189        return _updateUsersGroup(groupDirectoryId, groupId, users, false);
190    }
191    
192    /**
193     * Remove users from group
194     * @param groupDirectoryId The id of the group directory
195     * @param groupId The group's id
196     * @param users The users to add
197     * @return The group's information
198     * @throws InvalidModificationException If modification are not possible
199     */
200    @Callable
201    public Map<String, Object> removeUsersGroup (String groupDirectoryId, String groupId, List<Map<String, String>> users) throws InvalidModificationException
202    {
203        return _updateUsersGroup(groupDirectoryId, groupId, users, true);
204    }
205    
206    private Map<String, Object> _updateUsersGroup (String groupDirectoryId, String groupId, List<Map<String, String>> users, boolean remove) throws InvalidModificationException
207    {
208        GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(groupDirectoryId);
209        
210        if (!(groupDirectory instanceof ModifiableGroupDirectory))
211        {
212            getLogger().error("Groups are not modifiable !");
213            throw new InvalidModificationException("Groups are not modifiable !");
214        }
215        
216        ModifiableGroupDirectory modifiableGroupDirectory = (ModifiableGroupDirectory) groupDirectory;
217        
218        if (getLogger().isDebugEnabled())
219        {
220            getLogger().debug("Starting group modification");
221        }
222        
223        if (getLogger().isInfoEnabled())
224        {
225            getLogger().info(String.format("User %s is editing the group '%s'", _getCurrentUser(), groupId));
226        }
227
228        ModifiableGroup group = modifiableGroupDirectory.getGroup(groupId);
229        if (group == null)
230        {
231            getLogger().warn(String.format("User %s tries to edit the group '%s' but the group does not exist.", _getCurrentUser(), groupId));
232            
233            Map<String, Object> result = new HashMap<>();
234            result.put("error", "unknown-group");
235            return result;
236        }
237        else
238        {
239            for (Map<String, String> user : users)
240            {
241                UserIdentity userIdentity = _userHelper.json2userIdentity(user);
242                if (userIdentity != null)
243                {
244                    if (remove)
245                    {
246                        group.removeUser(userIdentity);
247                    }
248                    else
249                    {
250                        group.addUser(userIdentity);
251                    }
252                }
253            }
254            modifiableGroupDirectory.update(group);
255        }
256        
257        if (getLogger().isDebugEnabled())
258        {
259            getLogger().debug("Ending group modification");
260        }
261
262        return group2Json(group);
263    }
264    
265    /**
266     * Get the list of groups of a user
267     * @param user The user (using the format of {@link UserHelper#json2userIdentity(Map)}
268     * @return The list of groups information
269     */
270    @Callable
271    public List<Map<String, Object>> getUsersGroup(Map<String, String> user)
272    {
273        List<Map<String, Object>> jsonifiedGroups = new ArrayList<>();
274        
275        UserIdentity userIdentity = _userHelper.json2userIdentity(user);
276        
277        Set<GroupIdentity> userGroups = _groupManager.getUserGroups(userIdentity);
278        for (GroupIdentity userGroup : userGroups)
279        {
280            GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(userGroup.getDirectoryId());
281            if (groupDirectory != null)
282            {
283                Group group = groupDirectory.getGroup(userGroup.getId());
284                if (group != null)
285                {
286                    Map<String, Object> jsonifiedGroup = group2Json(group);
287                    jsonifiedGroups.add(jsonifiedGroup);
288                }
289            }
290        }
291        
292        return jsonifiedGroups;
293    }
294    
295    /**
296     * Renames a group
297     * @param groupDirectoryId The id of the group directory
298     * @param groupId The group'sid
299     * @param name The new name
300     * @return The group's information
301     * @throws InvalidModificationException If modification are not possible
302     */
303    @Callable
304    public Map<String, Object> renameGroup (String groupDirectoryId, String groupId, String name) throws InvalidModificationException
305    {
306        GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(groupDirectoryId);
307        
308        if (!(groupDirectory instanceof ModifiableGroupDirectory))
309        {
310            getLogger().error("Groups are not modifiable !");
311            throw new InvalidModificationException("Groups are not modifiable !");
312        }
313        
314        ModifiableGroupDirectory modifiableGroupDirectory = (ModifiableGroupDirectory) groupDirectory;
315        
316        if (getLogger().isDebugEnabled())
317        {
318            getLogger().debug("Starting group renaming");
319        }
320        
321        if (StringUtils.isBlank(name))
322        {
323            throw new IllegalArgumentException("The new group name cannot be empty");
324        }
325        
326        if (getLogger().isInfoEnabled())
327        {
328            getLogger().info(String.format("User %s is renaming the group '%s' to '%s'", _getCurrentUser(), groupId, name));
329        }
330        
331        ModifiableGroup group = modifiableGroupDirectory.getGroup(groupId);
332        if (group == null)
333        {
334            getLogger().warn(String.format("User %s tries to rename the group '%s' but the group does not exist.", _getCurrentUser(), groupId));
335            
336            Map<String, Object> result = new HashMap<>();
337            result.put("error", "unknown-group");
338            return result;
339        }
340        else
341        {
342            group.setLabel(name);
343            modifiableGroupDirectory.update(group);
344        }
345        
346        if (getLogger().isDebugEnabled())
347        {
348            getLogger().debug("Ending group renaming");
349        }
350        
351        return group2Json(group);
352    }
353    
354    /**
355     * Deletes groups
356     * @param groupDirectoryId The id of the group directory
357     * @param groupIds The ids of groups to delete
358     * @throws InvalidModificationException If modification are not possible
359     */
360    @Callable
361    public void deleteGroups (String groupDirectoryId, List<String> groupIds) throws InvalidModificationException
362    {
363        GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(groupDirectoryId);
364        
365        if (!(groupDirectory instanceof ModifiableGroupDirectory))
366        {
367            getLogger().error("Groups are not modifiable !");
368            throw new InvalidModificationException("Groups are not modifiable !");
369        }
370        
371        ModifiableGroupDirectory modifiableGroupDirectory = (ModifiableGroupDirectory) groupDirectory;
372        
373        if (getLogger().isDebugEnabled())
374        {
375            getLogger().debug("Starting group removal");
376        }
377        
378        for (String groupId : groupIds)
379        {
380            if (getLogger().isInfoEnabled())
381            {
382                getLogger().info(String.format("User %s is is removing group '%s'", _getCurrentUser(), groupId));
383            }
384            
385            modifiableGroupDirectory.remove(groupId);
386        }
387
388        if (getLogger().isDebugEnabled())
389        {
390            getLogger().debug("Ending group removal");
391        }
392    }
393    
394    /**
395     * Get group's information
396     * @param groupDirectoryId The id of the group directory
397     * @param id the group id
398     * @return group's information
399     */
400    @Callable
401    public Map<String, Object> getGroup (String groupDirectoryId, String id)
402    {
403        GroupDirectory groupDirectory = _groupDirectoryDAO.getGroupDirectory(groupDirectoryId);
404        
405        Group group = groupDirectory.getGroup(id);
406        if (group != null)
407        {
408            return group2Json(group);
409        }
410        return null;
411    }
412    
413    /**
414     * Checks if the group is modifiable
415     * @param groupDirectoryId The id of the group directory
416     * @param id The group id
417     * @return True if the group is modifiable
418     */
419    @Callable
420    public boolean isModifiable (String groupDirectoryId, String id)
421    {
422        return _groupDirectoryDAO.getGroupDirectory(groupDirectoryId) instanceof ModifiableGroupDirectory;
423    }
424    
425    /**
426     * Get the JSON representation of a group
427     * @param group The group
428     * @return The group
429     */
430    protected Map<String, Object> group2Json (Group group)
431    {
432        Map<String, Object> infos = new HashMap<>();
433        infos.put("id", group.getIdentity().getId());
434        infos.put("label", group.getLabel());
435        infos.put("groupDirectory", group.getIdentity().getDirectoryId());
436        infos.put("groupDirectoryLabel", _groupDirectoryDAO.getGroupDirectory(group.getIdentity().getDirectoryId()).getLabel());
437
438        return infos;
439    }
440    
441    /**
442     * Provides the current user.
443     * @return the user which cannot be <code>null</code>.
444     */
445    protected UserIdentity _getCurrentUser()
446    {
447        if (_currentUserProvider == null)
448        {
449            try
450            {
451                _currentUserProvider = (CurrentUserProvider) _smanager.lookup(CurrentUserProvider.ROLE);
452            }
453            catch (ServiceException e)
454            {
455                throw new IllegalStateException(e);
456            }
457        }
458        
459        return _currentUserProvider.getUser();
460    }
461}