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.web.population;
017
018import java.util.Collection;
019import java.util.HashSet;
020import java.util.LinkedHashSet;
021import java.util.Map;
022import java.util.Set;
023import java.util.stream.Collectors;
024
025import org.apache.commons.lang3.tuple.Pair;
026
027import org.ametys.core.right.RightManager.RightResult;
028import org.ametys.core.user.UserIdentity;
029import org.ametys.core.user.population.UserPopulation;
030import org.ametys.runtime.authentication.AccessDeniedException;
031import org.ametys.web.AmetysContextHelper;
032
033
034/**
035 * Helper for associating {@link UserPopulation}s to contexts.
036 * This override allows a user to get user populations on a 'site' context if user belongs to the BO+FO site context ('/sites/SITENAME') or FO site context  ('/sites-fo/SITENAME')
037 */
038public class PopulationContextHelper extends org.ametys.core.user.population.PopulationContextHelper
039{
040    @Override
041    public Set<String> getUserPopulationsOnContexts(Collection<String> contexts, boolean withDisabled, boolean checkRights)
042    {
043        UserIdentity currentUser = getCurrentUserProvider().getUser();
044        
045        if (!checkRights || contexts.contains(ADMIN_CONTEXT) || currentUser == null)
046        {
047            // no override required
048            return super.getUserPopulationsOnContexts(contexts, withDisabled, checkRights);
049        }
050        
051        boolean isAdministrator = getRightManager().currentUserHasRight(__ADMIN_RIGHT_ACCESS, ADMIN_CONTEXT) == RightResult.RIGHT_ALLOW;
052        Set<String> populations = new LinkedHashSet<>();
053        
054        Set<String> handledContexts = new HashSet<>();
055        
056        for (String context : contexts)
057        {
058            if (!handledContexts.contains(context))
059            {
060                Set<String> ctxPopulations = getUserPopulationsOnContext(context, withDisabled);
061                handledContexts.add(context);
062                if (!isAdministrator)
063                {
064                    Set<String> ctxPopulationsToCheckAccess = new HashSet<>(ctxPopulations);
065                    
066                    String complementaryContext = AmetysContextHelper.getSiteComplementaryContext(context);
067                    if (complementaryContext != null)
068                    {
069                        Set<String> compPopulations = getUserPopulationsOnContext(complementaryContext, withDisabled);
070                        ctxPopulationsToCheckAccess.addAll(compPopulations);
071                        
072                        if (contexts.contains(complementaryContext))
073                        {
074                            handledContexts.add(complementaryContext);
075                            ctxPopulations.addAll(compPopulations);
076                        }
077                    }
078                    
079                    if (!ctxPopulationsToCheckAccess.contains(currentUser.getPopulationId()))
080                    {
081                        throw new AccessDeniedException("User " + currentUser +  " tried to access the list of user populations on context '" + context + "', but he does not belong to any populations on this context.");
082                    }
083                }
084                
085                populations.addAll(ctxPopulations);
086            }
087        }
088        
089        return populations;
090    }
091    
092    @Override
093    protected Set<String> _getSharedCompatibleContexts(Map<String, Set<Pair<String, Integer>>> cacheAsMap, String context, String userPopulation1, String userPopulation2)
094    {
095        String complementaryContext = AmetysContextHelper.getSiteComplementaryContext(context);
096        // If there is no complementary context, just check the populations for the context
097        if (complementaryContext == null)
098        {
099            return super._getSharedCompatibleContexts(cacheAsMap, context, userPopulation1, userPopulation2);
100        }
101        // Else check the populations for the two contexts
102        else
103        {
104            // Add the user populations of the two contexts to a new set
105            Set<Pair<String, Integer>> cacheForContexts = new HashSet<>(cacheAsMap.get(context));
106            cacheForContexts.addAll(cacheAsMap.get(complementaryContext));
107            
108            Set<String> populationsForContext = cacheForContexts.stream().map(popPair -> popPair.getLeft()).collect(Collectors.toSet());
109            
110            if (populationsForContext.contains(userPopulation1) && populationsForContext.contains(userPopulation2))
111            {
112                return Set.of(context, complementaryContext);
113            }
114        }
115        
116        return Set.of();
117    }
118}