001/*
002 *  Copyright 2017 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.extraction.execution;
017
018import java.io.File;
019import java.util.HashMap;
020import java.util.LinkedHashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Optional;
024import java.util.Set;
025
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.commons.lang3.StringUtils;
029import org.apache.excalibur.source.Source;
030import org.apache.excalibur.source.SourceResolver;
031import org.apache.excalibur.source.impl.FileSource;
032
033import org.ametys.cms.contenttype.ContentType;
034import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
035import org.ametys.cms.contenttype.ContentTypesHelper;
036import org.ametys.core.ui.Callable;
037import org.ametys.core.ui.StaticClientSideElement;
038import org.ametys.core.user.User;
039import org.ametys.core.user.UserIdentity;
040import org.ametys.core.user.UserManager;
041import org.ametys.plugins.extraction.ExtractionConstants;
042import org.ametys.plugins.extraction.execution.Extraction.ClausesVariable;
043import org.ametys.plugins.extraction.execution.Extraction.ClausesVariableType;
044import org.ametys.plugins.extraction.execution.pipeline.PipelineManager;
045import org.ametys.runtime.i18n.I18nizableText;
046
047/**
048 * This client site element creates a button to execute an extraction
049 */
050public class ExecuteExtractionClientSideElement extends StaticClientSideElement
051{
052    private UserManager _userManager;
053    private ExtractionDefinitionReader _reader;
054    private SourceResolver _sourceResolver;
055    private PipelineManager _pipelineManager;
056    private ContentTypeExtensionPoint _contentTypeExtensionPoint;
057    private ContentTypesHelper _contentTypesHelper;
058    private ExecuteExtractionRunnableHelper _executeExtractionRunnableHelper;
059    
060    @Override
061    public void service(ServiceManager serviceManager) throws ServiceException
062    {
063        super.service(serviceManager);
064        _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE);
065        _reader = (ExtractionDefinitionReader) serviceManager.lookup(ExtractionDefinitionReader.ROLE);
066        _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
067        _pipelineManager = (PipelineManager) serviceManager.lookup(PipelineManager.ROLE);
068        _contentTypeExtensionPoint = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE);
069        _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE);
070        _executeExtractionRunnableHelper = (ExecuteExtractionRunnableHelper) serviceManager.lookup(ExecuteExtractionRunnableHelper.ROLE);
071    }
072    
073    /**
074     * Retrieve needed extraction parameters.
075     * @param definitionFile The extraction definition file path
076     * @return a <code>Map</code> containing parameters infos used to configure form to fill the parameters
077     * @throws Exception if an error occurs
078     */
079    @Callable (rights = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID)
080    public Map<String, Object> getExecutionParameters(String definitionFile) throws Exception
081    {
082        Map<String, Object> executionParameters = new LinkedHashMap<>();
083
084        String definitionFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionFile;
085        Source src = _sourceResolver.resolveURI(definitionFilePath);
086        File file = ((FileSource) src).getFile();
087        
088        if (!file.exists())
089        {
090            throw new IllegalArgumentException("The file " + definitionFilePath + " does not exist.");
091        }
092
093        executionParameters.put("pipeline", _getPipelineInputConfig(definitionFile));
094        
095        Extraction extraction = _reader.readExtractionDefinitionFile(file);
096        
097        List<ClausesVariable> clausesVariables = extraction.getClausesVariables();
098        List<String> optionalColumns = extraction.getDisplayOptionalColumnsNames();
099
100        if (!clausesVariables.isEmpty())
101        {
102            Map<String, Object> clausesVariablesFieldSet = new HashMap<>();
103            clausesVariablesFieldSet.put("role", "fieldset");
104            clausesVariablesFieldSet.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLES_FIELDSET_LABEL"));
105        
106            Map<String, Object> clausesVariablesFieldSetElements = new HashMap<>();
107            for (ClausesVariable clausesVariable : clausesVariables)
108            {
109                clausesVariablesFieldSetElements.put(clausesVariable.name(), _getClausesVariableInputConfig(clausesVariable));
110            }
111            clausesVariablesFieldSet.put("elements", clausesVariablesFieldSetElements);
112            
113            executionParameters.put("clausesVariables", clausesVariablesFieldSet);
114        }
115        
116        if (!optionalColumns.isEmpty())
117        {
118            Map<String, Object> optionalColumnsFieldSet = new HashMap<>();
119            optionalColumnsFieldSet.put("role", "fieldset");
120            optionalColumnsFieldSet.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_FIELDSET_LABEL"));
121        
122            Map<String, Object> optionalColumnsFieldSetElements = new HashMap<>();
123            for (String optionalColumn : optionalColumns)
124            {
125                optionalColumnsFieldSetElements.put(optionalColumn, _getOptionalColumnsInputConfig(optionalColumn));
126            }
127            optionalColumnsFieldSet.put("elements", optionalColumnsFieldSetElements);
128            
129            executionParameters.put("optionalColumns", optionalColumnsFieldSet);
130        }
131            
132        executionParameters.put("recipient", _getRecipientInputConfig());
133        
134        return executionParameters;
135    }
136    
137    private Map<String, Object> _getPipelineInputConfig(String definitionFile)
138    {
139        Map<String, Object> inputConfig = new HashMap<>();
140        
141        inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_PIPELINE_INPUT_LABEL"));
142        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_PIPELINE_INPUT_DESCRIPTION"));
143        inputConfig.put("type", "string");
144        
145        inputConfig.put("default-value", _pipelineManager.getDefaultPipeline());
146        inputConfig.put("validation", _getMandatoryValidation());
147        
148        inputConfig.put("widget", "edition.select-pipeline");
149        
150        Map<String, Object> widgetParams = new HashMap<>();
151        widgetParams.put("extraction", definitionFile);
152        inputConfig.put("widget-params", widgetParams);
153        
154        return inputConfig;
155    }
156    
157    private Map<String, Object> _getClausesVariableInputConfig(ClausesVariable clausesVariable)
158    {
159        Map<String, Object> inputConfig = new HashMap<>();
160        
161        inputConfig.put("label", clausesVariable.name());
162        
163        if (ClausesVariableType.SOLR_REQUEST.equals(clausesVariable.type()))
164        {
165            inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLE_SOLR_REQUEST_INPUT_DESCRIPTION"));
166
167            inputConfig.put("type", "string");
168            inputConfig.put("widget", "edition.solr-code");
169            
170            Map<String, Object> widgetParams = new HashMap<>();
171            
172            Set<String> commonAncestors = _contentTypesHelper.getCommonAncestors(clausesVariable.contentTypeIds());
173            widgetParams.put("ctypes", commonAncestors);            
174            widgetParams.put("singleLine", true);
175            widgetParams.put("height", 66);
176            widgetParams.put("mode", "text/x-solr-ametys");
177            
178            inputConfig.put("widget-params", widgetParams);
179        }
180        else
181        {
182            inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_CLAUSES_VARIABLE_SELECT_CONTENTS_INPUT_DESCRIPTION"));
183    
184            inputConfig.put("type", "content");
185            inputConfig.put("multiple", true);
186            
187            String widget = "edition.select-content";
188            Map<String, Object> widgetParams = new HashMap<>();
189            
190            Optional<String> contentTypeId = clausesVariable.contentTypeIds().stream().findFirst();
191            if (contentTypeId.isPresent())
192            {
193                ContentType contentType = _contentTypeExtensionPoint.getExtension(contentTypeId.get());
194                if (contentType.isReferenceTable())
195                {
196                    widget = "edition.select-referencetable-content";
197                }
198                
199                widgetParams.put("contentType", contentTypeId.get());
200            }
201            
202            clausesVariable.searchModelId()
203                           .ifPresent(searchModelId -> widgetParams.put("modelId", searchModelId));
204            
205            clausesVariable.solrRequest()
206                           .ifPresent(solrRequest -> widgetParams.put("solrRequest", solrRequest));
207
208            inputConfig.put("widget", widget);
209            inputConfig.put("widget-params", widgetParams);
210        }
211        
212        inputConfig.put("validation", _getMandatoryValidation());
213        
214        return inputConfig;
215    }
216    
217    private Map<String, Object> _getOptionalColumnsInputConfig(String optionalColumn)
218    {
219        Map<String, Object> inputConfig = new HashMap<>();
220        
221        inputConfig.put("label", optionalColumn);
222        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_OPTIONAL_COLUMNS_INPUTS_DESCRIPTION"));
223        
224        inputConfig.put("type", "boolean");
225        inputConfig.put("widget", "edition.checkbox");
226        
227        inputConfig.put("validation", _getMandatoryValidation());
228        
229        return inputConfig;
230    }
231    
232    private Map<String, Object> _getRecipientInputConfig()
233    {
234        Map<String, Object> inputConfig = new HashMap<>();
235        
236        // Get current user email
237        String currentUserEmail = null;
238        UserIdentity currentUser = _currentUserProvider.getUser();
239        
240        String login = currentUser.getLogin();
241        if (StringUtils.isNotBlank(login))
242        {
243            String userPopulationId = currentUser.getPopulationId();
244            User user = _userManager.getUser(userPopulationId, login);
245            currentUserEmail = user.getEmail();
246        }
247        
248        inputConfig.put("label", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_LABEL"));
249        inputConfig.put("description", new I18nizableText(ExtractionConstants.PLUGIN_NAME, "PLUGINS_EXTRACTION_EXECUTE_EXTRACTION_RECIPIENT_INPUT_DESCRIPTION"));
250        inputConfig.put("type", "string");
251        inputConfig.put("default-value", currentUserEmail);
252        
253        return inputConfig;
254    }
255    
256    private Map<String, Object> _getMandatoryValidation()
257    {
258        Map<String, Object> mandatoryValidation = new HashMap<>();
259        mandatoryValidation.put("mandatory", true);
260        return mandatoryValidation;
261    }
262    
263    /**
264     * Execute the extraction
265     * @param definitionFilePath The extraction definition file path
266     * @param variables clauses variables and optional columns
267     * @param recipient An email will be sent at this address when the extraction is complete
268     * @param pipelineId The id of the extraction pipeline
269     * @return a Map with error if one occurs
270     * @throws Exception if an error occurs
271     */
272    @Callable (rights = ExtractionConstants.EXECUTE_EXTRACTION_RIGHT_ID)
273    public Map<String, Object> executeExtraction(String definitionFilePath, Map<String, Object> variables, String recipient, String pipelineId) throws Exception
274    {
275        return _executeExtractionRunnableHelper.executeExtraction(definitionFilePath, variables, recipient, pipelineId);
276    }
277}