001/*
002 *  Copyright 2021 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.forms.question.types;
017
018import java.util.Arrays;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.cocoon.xml.XMLUtils;
024import org.apache.commons.lang.StringUtils;
025import org.xml.sax.ContentHandler;
026import org.xml.sax.SAXException;
027
028import org.ametys.plugins.forms.helper.FormElementDefinitionHelper;
029import org.ametys.plugins.forms.question.validators.FileFormValidator;
030import org.ametys.plugins.forms.repository.FormQuestion;
031import org.ametys.runtime.config.Config;
032import org.ametys.runtime.config.DisableCondition;
033import org.ametys.runtime.config.DisableCondition.OPERATOR;
034import org.ametys.runtime.config.DisableConditions;
035import org.ametys.runtime.i18n.I18nizableText;
036import org.ametys.runtime.model.ElementDefinition;
037import org.ametys.runtime.model.ModelItem;
038import org.ametys.runtime.model.SimpleViewItemGroup;
039import org.ametys.runtime.model.StaticEnumerator;
040import org.ametys.runtime.model.ViewElement;
041import org.ametys.runtime.model.type.ModelItemTypeConstants;
042import org.ametys.runtime.parameter.DefaultValidator;
043import org.ametys.runtime.servlet.RuntimeServlet;
044
045/**
046 * Class for creating file questions
047 */
048public class FileQuestionType extends AbstractFormQuestionType
049{
050    /** Constant for max size attribute. */
051    public static final String ATTRIBUTE_MAX_SIZE = "max-size";
052    
053    /** Constant for allowed extensions attribute. */
054    public static final String ATTRIBUTE_EXTENSIONS = "extensions";
055    
056    /** Constant for other allowed extensions attribute. */
057    public static final String ATTRIBUTE_EXTENSIONS_OTHER = "extensions-other";
058    
059    /** Constant for default title */
060    public static final String DEFAULT_TITLE = "PLUGIN_FORMS_QUESTION_DEFAULT_TITLE_FILE";
061    
062    /** Constant for all extensions */
063    public static final String ALL_EXTENSIONS_VALUE = "_ametys_all_extension";
064    
065    /** Constant for image extensions */
066    public static final String IMAGE_EXTENSIONS_VALUE = "_ametys_image_extension";
067    
068    /** Constant for video extensions */
069    public static final String VIDEO_EXTENSIONS_VALUE = "_ametys_video_extension";
070    
071    /** Constant for audio extensions */
072    public static final String AUDIO_EXTENSIONS_VALUE = "_ametys_audio_extension";
073    
074    /** Constant for document extensions */
075    public static final String DOCUMENT_EXTENSIONS_VALUE = "_ametys_document_extension";
076    
077    /** Constant for other extensions */
078    public static final String OTHER_EXTENSIONS_VALUE = "_ametys_other_extension";
079    
080    @Override
081    protected List<ModelItem> _getModelItems()
082    {
083        List<ModelItem> modelItems = super._getModelItems();
084        
085        ElementDefinition<Long> maxSize = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_MAX_SIZE, ModelItemTypeConstants.LONG_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_MAX_SIZE", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_MAX_SIZE_DESC", null);
086        
087        // Upload initialization
088        long maxSizeValue = _getMaxSizeValue();
089        maxSize.setWidget("edition.longfield");
090        Map<String, I18nizableText> widgetParameters  = new HashMap<>();
091        widgetParameters.put("maxValue", new I18nizableText(String.valueOf(maxSizeValue)));
092        widgetParameters.put("minValue", new I18nizableText("1"));
093        widgetParameters.put("emptyText", new I18nizableText(String.valueOf(maxSizeValue)));
094        maxSize.setWidgetParameters(widgetParameters);
095        modelItems.add(maxSize);
096        
097        ElementDefinition<String> extensions = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_EXTENSIONS, ModelItemTypeConstants.STRING_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_DESC", null);
098
099        StaticEnumerator<String> extensionEnum = new StaticEnumerator<>();
100        extensionEnum.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_ALL"), ALL_EXTENSIONS_VALUE);
101        extensionEnum.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_DOCUMENTS"), DOCUMENT_EXTENSIONS_VALUE);
102        extensionEnum.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_IMAGES"), IMAGE_EXTENSIONS_VALUE);
103        extensionEnum.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_VIDEO"), VIDEO_EXTENSIONS_VALUE);
104        extensionEnum.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_AUDIO"), AUDIO_EXTENSIONS_VALUE);
105        extensionEnum.add(new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_EXTENSIONS_OTHER"), OTHER_EXTENSIONS_VALUE);
106        extensions.setEnumerator(extensionEnum);
107        extensions.setDefaultValue(ALL_EXTENSIONS_VALUE);
108        
109        Map<String, I18nizableText> extWidgetParameters  = new HashMap<>();
110        extWidgetParameters.put("naturalOrder", new I18nizableText("true"));
111        extensions.setWidgetParameters(extWidgetParameters);
112        
113        modelItems.add(extensions);
114        
115        ElementDefinition otherExtensions = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_EXTENSIONS_OTHER, ModelItemTypeConstants.STRING_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_OTHER_EXTENSIONS", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_OTHER_EXTENSIONS_DESC", new DefaultValidator("^\\.[a-z0-9]+(,\\s*\\.[a-z0-9]+)*$", false));
116        DisableConditions disableConditions = new DisableConditions();
117        DisableCondition condition = new DisableCondition(ATTRIBUTE_EXTENSIONS, OPERATOR.NEQ, "_ametys_other_extension"); 
118        disableConditions.getConditions().add(condition);
119        otherExtensions.setDisableConditions(disableConditions);
120        Map<String, I18nizableText> otherExtWidgetParameters  = new HashMap<>();
121        otherExtWidgetParameters.put("ametysShowMultipleHint", new I18nizableText("true"));
122        otherExtensions.setWidgetParameters(otherExtWidgetParameters);
123        modelItems.add(otherExtensions);
124        
125        return modelItems;
126    }
127    
128    @Override
129    protected SimpleViewItemGroup _getMainTab()
130    {
131        SimpleViewItemGroup mainFieldset = super._getMainTab();
132        
133        ViewElement extensions = new ViewElement();
134        extensions.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_EXTENSIONS));
135        mainFieldset.addViewItem(extensions);
136        
137        ViewElement otherExtensions = new ViewElement();
138        otherExtensions.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_EXTENSIONS_OTHER));
139        mainFieldset.addViewItem(otherExtensions);
140        
141        return mainFieldset;
142    }
143    
144    @Override
145    protected SimpleViewItemGroup _getAdvancedTab()
146    {
147        SimpleViewItemGroup advancedFieldset =  super._getAdvancedTab();
148        
149        ViewElement maxSize = new ViewElement();
150        maxSize.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_MAX_SIZE));
151        advancedFieldset.addViewItem(maxSize);
152        
153        return advancedFieldset;
154    }
155    
156    @Override
157    public void validateQuestionValues(Map<String, Object> values, Map<String, I18nizableText> errors)
158    {
159        super.validateQuestionValues(values, errors);
160        
161        Number sizeAsNumber = (Number) values.getOrDefault(ATTRIBUTE_MAX_SIZE, null);
162        Long maxSize = _getMaxSizeValue();
163        Long size = sizeAsNumber != null ? sizeAsNumber.longValue() : maxSize;
164        if (size > maxSize)
165        {
166            List<String> errorParams = Arrays.asList(String.valueOf(maxSize));
167            
168            errors.put(ATTRIBUTE_MAX_SIZE, new I18nizableText("plugin.forms", "PLUGINS_FORMS_QUESTIONS_DIALOG_FILE_MAXSIZE_ERROR", errorParams));
169        }
170    }
171    
172    private long _getMaxSizeValue()
173    {
174        long maxSizeValue = RuntimeServlet.DEFAULT_MAX_UPLOAD_SIZE;
175        Long maxUploadSizeParam = Config.getInstance().getValue("runtime.upload.max-size");
176        if (maxUploadSizeParam != null)
177        {
178            maxSizeValue = maxUploadSizeParam.intValue();
179        }
180        
181        return maxSizeValue / (1024 * 1024);
182    }
183    
184    public String getStorageType(FormQuestion question)
185    {
186        return org.ametys.cms.data.type.ModelItemTypeConstants.FILE_ELEMENT_TYPE_ID;
187    }
188    
189    @Override
190    protected ModelItem _getEntryModelItem(FormQuestion question)
191    {
192        ModelItem item = super._getEntryModelItem(question);
193        ((ElementDefinition) item).setValidator(new FileFormValidator(null, isMandatory(question), question.getValue(ATTRIBUTE_MAX_SIZE, false, _getMaxSizeValue()), _getAllowedExtensions(question)));
194        return item;
195    }
196    
197    @Override
198    public void saxAdditionalInfos(ContentHandler contentHandler, FormQuestion question) throws SAXException
199    {
200        super.saxAdditionalInfos(contentHandler, question);
201        
202        XMLUtils.createElement(contentHandler, "allowed-extensions", _getAllowedExtensions(question));
203        
204        Long maxSize = question.getValue(ATTRIBUTE_MAX_SIZE, false, _getMaxSizeValue());
205        XMLUtils.createElement(contentHandler, "max-size", String.valueOf(maxSize));
206    }
207    
208    private String _getAllowedExtensions(FormQuestion question)
209    {
210        String value = question.getValue(ATTRIBUTE_EXTENSIONS, false, ALL_EXTENSIONS_VALUE);
211        switch (value)
212        {
213            case DOCUMENT_EXTENSIONS_VALUE:
214                return ".txt, .pdf, .xls, .xlsx, .doc, .docx, .ptt, .pttx, .odt, .ods, .odp, .odb, .odg, .odf";
215            case IMAGE_EXTENSIONS_VALUE:
216                return ".png, .gif, .jpg, .jpeg";
217            case VIDEO_EXTENSIONS_VALUE:
218                return ".mp4, .m4v, .mov, .avi, .flv, .wmv, .mpeg, .mkv";
219            case AUDIO_EXTENSIONS_VALUE:
220                return ".wav, .wave, .flac, .m4a, .wma, .wmv, .mp3, .ogg, .oga, .mogg, .aac, .aiff, .aif";
221            case OTHER_EXTENSIONS_VALUE:
222                return question.getValue(ATTRIBUTE_EXTENSIONS_OTHER, false, StringUtils.EMPTY);
223            case ALL_EXTENSIONS_VALUE:
224            default:
225                return StringUtils.EMPTY;
226        }
227    }
228    
229    public I18nizableText getDefaultTitle()
230    {
231        return new I18nizableText("plugin.forms", DEFAULT_TITLE);
232    }
233    
234    @Override
235    public List<String> getFieldToDisableIfFormPublished(FormQuestion question)
236    {
237        List<String> fieldNames =  super.getFieldToDisableIfFormPublished(question);
238        fieldNames.add(ATTRIBUTE_EXTENSIONS);
239        fieldNames.add(ATTRIBUTE_EXTENSIONS_OTHER);
240        return fieldNames;
241    }
242}