001/*
002 *  Copyright 2023 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.impl.group.directory;
017
018import java.util.Collection;
019import java.util.List;
020import java.util.Map;
021import java.util.Set;
022import java.util.stream.Collectors;
023
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.avalon.framework.service.Serviceable;
027import org.apache.commons.lang3.StringUtils;
028
029import org.ametys.core.group.Group;
030import org.ametys.core.group.GroupIdentity;
031import org.ametys.core.group.directory.GroupDirectory;
032import org.ametys.core.user.User;
033import org.ametys.core.user.UserIdentity;
034import org.ametys.core.user.directory.UserDirectory;
035import org.ametys.core.user.population.PopulationContextHelper;
036import org.ametys.core.user.population.UserPopulation;
037import org.ametys.core.user.population.UserPopulationDAO;
038import org.ametys.core.util.I18nUtils;
039import org.ametys.core.util.SizeUtils.ExcludeFromSizeCalculation;
040import org.ametys.runtime.i18n.I18nizableText;
041import org.ametys.runtime.i18n.I18nizableTextParameter;
042import org.ametys.runtime.plugin.component.AbstractLogEnabled;
043
044/**
045 * Implementation of a {@link GroupDirectory} based on user's populations
046 *
047 */
048public class UserPopulationsGroupDirectory extends AbstractLogEnabled implements GroupDirectory, Serviceable
049{
050    /** The user population DAO */
051    protected UserPopulationDAO _userPopulationDAO;
052    
053    /** The population context helper */
054    protected PopulationContextHelper _populationContextHelper;
055    
056    /** The i18n utils */
057    protected I18nUtils _i18nUtils;
058    
059    private String _id;
060    private I18nizableText _label;
061    private String _gdModelId;
062    private Map<String, Object> _params;
063
064    
065    public void service(ServiceManager smanager) throws ServiceException
066    {
067        _userPopulationDAO = (UserPopulationDAO) smanager.lookup(UserPopulationDAO.ROLE);
068        _populationContextHelper = (PopulationContextHelper) smanager.lookup(PopulationContextHelper.ROLE);
069        _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE);
070    }
071    
072    @Override
073    public String getId()
074    {
075        return _id;
076    }
077
078    @Override
079    public I18nizableText getLabel()
080    {
081        return _label;
082    }
083
084    @Override
085    public void setId(String id)
086    {
087        _id = id;
088    }
089
090    @Override
091    public void setLabel(I18nizableText label)
092    {
093        _label = label;
094    }
095
096    @Override
097    public String getGroupDirectoryModelId()
098    {
099        return _gdModelId;
100    }
101
102    public Map<String, Object> getParameterValues()
103    {
104        return _params;
105    }
106
107    public void init(String groupDirectoryModelId, Map<String, Object> paramValues) throws Exception
108    {
109        _gdModelId = groupDirectoryModelId;
110        _params = paramValues;    
111    }
112
113    public Group getGroup(String groupID)
114    {
115        UserPopulation up = _userPopulationDAO.getUserPopulation(groupID);
116        if (up != null)
117        {
118            // Check user population is part of available populations
119            if (getAvailableUserPopulationsForContext().contains(up))
120            {
121                return new UserPopulationGroup(up, _id, _getGroupLabel(up), this);
122            }
123        }
124        return null;
125    }
126
127    public Set<Group> getGroups()
128    {
129        List<UserPopulation> userPopulations = getAvailableUserPopulationsForContext();
130        
131        return userPopulations.stream()
132            .map(up -> new UserPopulationGroup(up, _id, _getGroupLabel(up), this))
133            .collect(Collectors.toSet());
134    }
135    
136    private String _getGroupLabel(UserPopulation userPopulation)
137    {
138        Map<String, I18nizableTextParameter> i18nParams = Map.of("populationLabel", userPopulation.getLabel());
139        I18nizableText groupLabel = new I18nizableText("plugin.core-impl", "PLUGINS_CORE_GROUPS_USER_POULATIONS_GROUP_LABEL", i18nParams);
140        return _i18nUtils.translate(groupLabel);
141    }
142    
143    /**
144     * Get the available user populations for the current context
145     * @return the available user populations
146     */
147    protected List<UserPopulation> getAvailableUserPopulationsForContext()
148    {
149        // By default returns all enabled user populations except admin population
150        return _userPopulationDAO.getEnabledUserPopulations(false);
151    }
152
153    public Set<String> getUserGroups(UserIdentity userIdentity)
154    {
155        Group group = getGroup(userIdentity.getPopulationId());
156        
157        if (group != null)
158        {
159            return Set.of(group.getIdentity().getId());
160        }
161        else
162        {
163            return Set.of();
164        }
165    }
166
167    public List<Group> getGroups(int count, int offset, Map parameters)
168    {
169        String pattern = (String) parameters.get("pattern");
170        
171        return getGroups().stream()
172                .filter(group -> _filterMatchingGroup(group, pattern))
173                .skip(offset)
174                .limit(count < 0 ? Integer.MAX_VALUE : count)
175                .collect(Collectors.toList());
176    }
177    
178    private boolean _filterMatchingGroup(Group group, String pattern)
179    {
180        return StringUtils.isEmpty(pattern)
181                || group.getLabel().toLowerCase().indexOf(pattern.toLowerCase()) != -1
182                || group.getIdentity() != null && group.getIdentity().getId().toLowerCase().indexOf(pattern.toLowerCase()) != -1;
183    }
184    
185    private static final class UserPopulationGroup implements Group
186    {
187        private GroupIdentity _identity;
188        private String _label;
189        
190        @ExcludeFromSizeCalculation
191        private UserPopulation _userPopulation;
192
193        @ExcludeFromSizeCalculation
194        private GroupDirectory _groupDirectory;
195        
196        UserPopulationGroup(UserPopulation userPopulation, String directoryId, String label, GroupDirectory groupDirectory)
197        {
198            _identity = new GroupIdentity(userPopulation.getId(), directoryId);
199            _label = label;
200            _groupDirectory = groupDirectory;
201            _userPopulation = userPopulation;
202        }
203        
204        public GroupIdentity getIdentity()
205        {
206            return _identity;
207        }
208
209        public String getLabel()
210        {
211            return _label;
212        }
213
214        public GroupDirectory getGroupDirectory()
215        {
216            return _groupDirectory;
217        }
218
219        public Set<UserIdentity> getUsers()
220        {
221            Set<User> users = _userPopulation.getUserDirectories().stream()
222                        .map(UserDirectory::getUsers)
223                        .flatMap(Collection::stream)
224                        .collect(Collectors.toSet());
225            
226            return users.stream()
227                        .map(User::getIdentity)
228                        .collect(Collectors.toSet());
229        }
230        
231    }
232
233}