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