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.odf.course.search;
017
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.commons.lang3.StringUtils;
026
027import org.ametys.cms.contenttype.MetadataType;
028import org.ametys.cms.search.query.AndQuery;
029import org.ametys.cms.search.query.NotQuery;
030import org.ametys.cms.search.query.OrQuery;
031import org.ametys.cms.search.query.Query;
032import org.ametys.cms.search.query.Query.Operator;
033import org.ametys.cms.search.query.StringQuery;
034import org.ametys.cms.search.ui.model.impl.AbstractCustomSearchUICriterion;
035import org.ametys.odf.ODFHelper;
036import org.ametys.odf.ProgramItem;
037import org.ametys.odf.course.ShareableCourseConstants;
038import org.ametys.odf.course.ShareableCourseHelper;
039import org.ametys.odf.course.ShareableCourseStatusHelper.ShareableStatus;
040import org.ametys.odf.program.Container;
041import org.ametys.odf.program.Program;
042import org.ametys.plugins.repository.AmetysObjectResolver;
043import org.ametys.runtime.model.ModelItem;
044
045/**
046 * UI criteria for shareable course
047 */
048public class ShareableCourseSearchUICriteria extends AbstractCustomSearchUICriterion
049{
050    /** The ametys object resolver. */
051    protected AmetysObjectResolver _resolver;
052    
053    /** The ODF helper */
054    protected ODFHelper _odfHelper;
055    
056    /** The shareable course helper */
057    protected ShareableCourseHelper _shareableCourseHelper;
058    
059    @Override
060    public void service(ServiceManager manager) throws ServiceException
061    {
062        super.service(manager);
063        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
064        _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE);
065        _shareableCourseHelper = (ShareableCourseHelper) manager.lookup(ShareableCourseHelper.ROLE);
066    }
067    
068    public String getFieldId()
069    {
070        return "shareable.course.field";
071    }
072
073    public Operator getOperator()
074    {
075        // Not suppose to be used
076        return Operator.EQ;
077    }
078    
079    @Override
080    public MetadataType getType()
081    {
082        // Not suppose to be used
083        return MetadataType.STRING;
084    }
085
086    public Query getQuery(Object value, Operator customOperator, Map<String, Object> allValues, String language, Map<String, Object> contextualParameters)
087    {
088        if (!_shareableCourseHelper.handleShareableCourse())
089        {
090            return null;
091        }
092        
093        return _getShareableQuery(value, customOperator, allValues, language, contextualParameters);
094    }
095
096    /**
097     * Get the {@link Query} associated to shareable fields
098     * @param value The user-submitted value (or the default value if not set) for this criterion.
099     * @param customOperator In advanced search mode, the operator chosen by the user. <code>null</code> to use the criterion-defined operator (simple search mode).
100     * @param allValues All the user-submitted values.
101     * @param language The current search language.
102     * @param contextualParameters the search contextual parameters.
103     * @return {@link Query} associated to shareable fields
104     */
105    protected Query _getShareableQuery(Object value, Operator customOperator, Map<String, Object> allValues, String language, Map<String, Object> contextualParameters)
106    {
107        List<Query> queries = new ArrayList<>();
108        
109        // Shareable course must be validated
110        queries.add(_getValidatedShareableCourseQuery());
111        
112        if (contextualParameters.containsKey("courseListId"))
113        {
114            String courseListId = (String) contextualParameters.get("courseListId");
115            if (StringUtils.isNotBlank(courseListId))
116            {
117                ProgramItem courseList = _resolver.resolveById(courseListId);
118                queries.addAll(_getShareableFieldQueries(courseList));
119            }
120        }
121        
122        return queries.stream()
123                .filter(q -> q != null)
124                .collect(AndQuery.collector());
125    }
126    
127    /**
128     * Get the query to get only validated shareable course
129     * @return the query
130     */
131    protected Query _getValidatedShareableCourseQuery()
132    {
133        return new StringQuery(ShareableCourseConstants.SHAREABLE_COURSE_COMPOSITE_METADATA + ModelItem.ITEM_PATH_SEPARATOR + ShareableCourseConstants.SHAREABLE_COURSE_STATUS_METADATA, ShareableStatus.VALIDATED.name());
134    }
135    
136    /**
137     * Get query form each shareable field
138     * @param programItem the program item
139     * @return the list of query
140     */
141    protected List<Query> _getShareableFieldQueries(ProgramItem programItem)
142    {
143        List<Query> queries = new ArrayList<>();
144        
145        Set<Program> programs = _odfHelper.getParentPrograms(programItem);
146        Set<Container> containers = _odfHelper.getParentContainers(programItem);
147        
148        // Query for programs field
149        Set<String> programValues = _shareableCourseHelper.getProgramIds(programs);
150        queries.add(_getFieldQuery(programValues, ShareableCourseConstants.PROGRAMS_FIELD_ATTRIBUTE_NAME));
151        
152        // Query for periods field
153        Set<String> periodValues = _shareableCourseHelper.getPeriods(containers);
154        queries.add(_getFieldQuery(periodValues, ShareableCourseConstants.PERIODS_FIELD_ATTRIBUTE_NAME));
155        
156        // Query for degree field
157        Set<String> degreeValues = _shareableCourseHelper.getDegrees(programs);
158        queries.add(_getFieldQuery(degreeValues, ShareableCourseConstants.DEGREES_FIELD_ATTRIBUTE_NAME));
159        
160        // Query for orgunits field
161        Set<String> orgunitValues = _shareableCourseHelper.getOrgUnits(programs);
162        queries.add(_getFieldQuery(orgunitValues, ShareableCourseConstants.ORGUNITS_FIELD_ATTRIBUTE_NAME));
163        
164        return queries;
165    }
166    
167    /**
168     * Get query for the shareable course field. Query is "not(field) or field = values"
169     * @param values the values
170     * @param metadataName the metadata name of the field
171     * @return the fitler query
172     */
173    protected Query _getFieldQuery(Set<String> values, String metadataName)
174    {
175        if (values.isEmpty())
176        {
177            return null;
178        }
179        
180        Query programValuesQuery = values.stream()
181                .map(v -> new StringQuery(metadataName, v))
182                .collect(OrQuery.collector());
183        
184        Query noProgramValueQuery = new NotQuery(new StringQuery(metadataName));
185        
186        return new OrQuery(noProgramValueQuery, programValuesQuery);
187    }
188}