001/*
002 *  Copyright 2019 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.search.misc;
017
018import java.util.Arrays;
019import java.util.Collection;
020import java.util.List;
021import java.util.Map;
022import java.util.stream.Collectors;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.cocoon.components.ContextHelper;
032import org.apache.cocoon.environment.Request;
033import org.apache.commons.lang3.StringUtils;
034
035import org.ametys.cms.search.query.AndQuery;
036import org.ametys.cms.search.query.Query;
037import org.ametys.cms.search.query.Query.Operator;
038import org.ametys.core.util.JSONUtils;
039import org.ametys.web.repository.site.Site;
040import org.ametys.web.search.query.SiteQuery;
041
042import com.google.common.collect.ImmutableMap;
043
044/**
045 * Helper for getting a {@link SiteQuery} from a user-submitted value.
046 */
047public class SiteQueryHelper implements Component, Serviceable, Contextualizable
048{
049    /** Avalon Role */
050    public static final String ROLE = SiteQueryHelper.class.getName();
051    
052    private JSONUtils _jsonUtils;
053    private Context _context;
054    
055    @Override
056    public void contextualize(Context context) throws ContextException
057    {
058        _context = context;
059    }
060    
061    @Override
062    public void service(ServiceManager manager) throws ServiceException
063    {
064        _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE);
065    }
066    
067    /**
068     * Gets a {@link Query} testing {@link Site} from a user-submitted value
069     * @param value a user-submitted value
070     * @param operator The operator
071     * @param contextualParameters  the search contextual parameters.
072     * @param criterionId The criterion id (for logging purposes only)
073     * @return The {@link Query}
074     */
075    @SuppressWarnings("unchecked")
076    public Query getQuery(Object value, Operator operator, Map<String, Object> contextualParameters, String criterionId)
077    {
078        // Handles a list of given site names (SITES_LIST) as well as "CURRENT_SITE", "OTHER_SITES" and "SITES" (all sites).
079        Map<String, Object> valueMap = _parseSite(value, criterionId);
080        
081        String context = (String) valueMap.get("context");
082        
083        Request request = ContextHelper.getRequest(_context);
084        String currentSite = (String) request.getAttribute("siteName");
085        if (StringUtils.isBlank(currentSite))
086        {
087            currentSite = (String) contextualParameters.get("siteName");
088        }
089        
090        if ("CURRENT_SITE".equals(context))
091        {
092            return new SiteQuery(Operator.EQ, currentSite);
093        }
094        else if ("OTHER_SITES".equals(context))
095        {
096            return new AndQuery(new SiteQuery(), new SiteQuery(Operator.NE, currentSite));
097        }
098        else if ("SITES".equals(context))
099        {
100            return new SiteQuery();
101        }
102        
103        // "SITES_LIST" context: get the site list from the value map.
104        List<String> names = (List<String>) valueMap.get("sites");
105        
106        // Standard context: site list.
107        return new SiteQuery(operator, names);
108    }
109    
110    @SuppressWarnings("unchecked")
111    private Map<String, Object> _parseSite(Object value, String criterionId)
112    {
113        if (value instanceof Map)
114        {
115            return (Map<String, Object>) value;
116        }
117        else if (value instanceof Collection)
118        {
119            String strValue = ((Collection<?>) value).stream()
120                    .filter(String.class::isInstance)
121                    .map(String.class::cast)
122                    .collect(Collectors.joining(","));
123            return _parseSite(strValue, criterionId);
124        }
125        else if (value instanceof String)
126        {
127            String strValue = (String) value;
128            if (strValue.startsWith("{"))
129            {
130                // Usually when coming from BO site widget
131                return _jsonUtils.convertJsonToMap(strValue);
132            }
133            else
134            {
135                // Consider it as the list of sites itself
136                // Usually when coming from FO
137                return ImmutableMap.of(
138                        "context", "SITES_LIST", 
139                        "sites", Arrays.asList(strValue.split(","))
140                );
141            }
142        }
143        else
144        {
145            throw new IllegalArgumentException("The value " + value + " for criterion " + criterionId + " is not a valid Site value.");
146        }
147    }
148}
149