001/*
002 *  Copyright 2015 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.survey.dao;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.LinkedHashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.commons.lang.StringUtils;
025
026import org.ametys.core.observation.Event;
027import org.ametys.core.ui.Callable;
028import org.ametys.plugins.repository.UnknownAmetysObjectException;
029import org.ametys.plugins.repository.jcr.NameHelper;
030import org.ametys.plugins.survey.SurveyEvents;
031import org.ametys.plugins.survey.repository.Survey;
032import org.ametys.plugins.survey.repository.SurveyPage;
033import org.ametys.plugins.survey.repository.SurveyQuestion;
034import org.ametys.plugins.survey.repository.SurveyQuestion.QuestionType;
035import org.ametys.plugins.survey.repository.SurveyRule;
036import org.ametys.plugins.survey.repository.SurveyRule.RuleType;
037
038/**
039 * DAO for manipulating survey questions.
040 *
041 */
042public class QuestionDAO extends AbstractDAO
043{
044    /** The Avalon role */
045    public static final String ROLE = QuestionDAO.class.getName();
046    
047    /**
048     * Gets properties of a survey question
049     * @param id The id of the survey question
050     * @return The properties
051     */
052    @Callable
053    public Map<String, Object> getQuestion (String id)
054    {
055        SurveyQuestion question = _resolver.resolveById(id);
056        
057        return getQuestion(question);
058    }
059    
060    /**
061     * Gets properties of a survey question
062     * @param question The survey question
063     * @return The properties
064     */
065    public Map<String, Object> getQuestion (SurveyQuestion question)
066    {
067        Map<String, Object> properties = new HashMap<>();
068        
069        properties.put("id", question.getId());
070        properties.put("type", question.getType());
071        properties.put("label", question.getLabel());
072        properties.put("title", question.getTitle());
073        properties.put("regexp", question.getRegExpType());
074        properties.put("mandatory", String.valueOf(question.isMandatory()));
075        properties.put("validated", String.valueOf(question.getSurvey().isValidated()));
076        
077        Map<String, String> columns = question.getColumns();
078        if (columns.size() > 0)
079        {
080            properties.put("columns", columns);
081        }
082        
083        Map<String, String> options = question.getOptions();
084        if (options.size() > 0)
085        {
086            properties.put("otherOption", String.valueOf(question.hasOtherOption()));
087            properties.put("options", options);
088        }
089        
090        properties.putAll(getPictureInfo(question));
091        
092        return properties;
093    }
094    
095    /**
096     * Creates a survey question.
097     * @param values The question's values
098     * @return The id of the created survey question, the id of the page and the id of the survey
099     */
100    @Callable
101    public Map<String, String> createQuestion (Map<String, Object> values)
102    {
103        Map<String, String> result = new HashMap<>();
104        
105        String pageId = StringUtils.defaultString((String) values.get("pageId"));
106        SurveyPage page = _resolver.resolveById(pageId);
107        
108        String label = StringUtils.defaultString((String) values.get("label"));
109        String originalName = NameHelper.filterName(label);
110        
111        // Find unique name
112        String uniqueName = page.getSurvey().findUniqueQuestionName(originalName);
113        
114        SurveyQuestion question = page.createChild(uniqueName, "ametys:survey-question");
115        
116        _setValues(question, values);
117        
118        page.saveChanges();
119        
120        Map<String, Object> eventParams = new HashMap<>();
121        eventParams.put("survey", page.getSurvey());
122        _observationManager.notify(new Event(SurveyEvents.SURVEY_MODIFIED, _getCurrentUser(), eventParams));
123        
124        result.put("id", question.getId());
125        result.put("pageId", page.getId());
126        result.put("surveyId", question.getSurvey().getId());
127        result.put("type", question.getType().toString());
128        
129        return result;
130    }
131    
132    /**
133     * Edits a survey question.
134     * @param values The question's values
135     * @return The id of the edited survey question, the id of the page and the id of the survey
136     */
137    @Callable
138    public Map<String, String> editQuestion (Map<String, Object> values)
139    {
140        Map<String, String> result = new HashMap<>();
141        
142        String id = StringUtils.defaultString((String) values.get("id"));
143        SurveyQuestion question = _resolver.resolveById(id);
144        
145        _setValues(question, values);
146        
147        question.saveChanges();
148        
149        Map<String, Object> eventParams = new HashMap<>();
150        eventParams.put("survey", question.getSurvey());
151        _observationManager.notify(new Event(SurveyEvents.SURVEY_MODIFIED, _getCurrentUser(), eventParams));
152        
153        result.put("id", question.getId());
154        result.put("pageId", question.getParent().getId());
155        result.put("surveyId", question.getSurvey().getId());
156        result.put("type", question.getType().toString());
157        
158        return result;
159    }
160    
161    private void _setValues (SurveyQuestion question, Map<String, Object> values)
162    {
163        question.setTitle(StringUtils.defaultString((String) values.get("title")));
164        question.setLabel(StringUtils.defaultString((String) values.get("label")));
165        question.setMandatory("true".equals(values.get("mandatory")));
166        
167        String qType = StringUtils.defaultString((String) values.get("type"));
168        question.setType(QuestionType.valueOf(qType));
169        question.setRegExpType(StringUtils.defaultString((String) values.get("regexp")));
170        
171        question.setPictureAlternative(StringUtils.defaultString((String) values.get("picture-alternative")));
172        setPicture(question, StringUtils.defaultString((String) values.get("picture")));
173        
174        boolean hasOtherOption = "true".equals(values.get("otherOption"));
175        
176        String options = (String) values.get("options");
177        if (StringUtils.isNotEmpty(options))
178        {
179            Map<String, Object> rawOpts = _jsonUtils.convertJsonToMap(options);
180            Map<String, String> opts = new LinkedHashMap<>();
181            
182            for (String optLabel : rawOpts.keySet())
183            {
184                String optVal = (String) rawOpts.get(optLabel);
185                if (StringUtils.isEmpty(optVal))
186                {
187                    optVal = NameHelper.filterName(SurveyQuestion.OPTION_NAME_PREFIX + optLabel);
188                }
189                opts.put(optVal, optLabel);
190            }
191            question.setOptions(opts);
192            question.setOtherOption(hasOtherOption);
193        }
194        
195        String columns = (String) values.get("columns");
196        if (StringUtils.isNotEmpty(columns))
197        {
198            Map<String, Object> rawCols = _jsonUtils.convertJsonToMap(columns);
199            Map<String, String> cols = new LinkedHashMap<>();
200            
201            for (String colLabel : rawCols.keySet())
202            {
203                String colVal = (String) rawCols.get(colLabel);
204                if (StringUtils.isEmpty(colVal))
205                {
206                    colVal = NameHelper.filterName(SurveyQuestion.OPTION_NAME_PREFIX + colLabel);
207                }
208                cols.put(colVal, colLabel);
209            }
210            
211            question.setColumns(cols);
212        }
213    }
214    
215    /**
216     * Copies and pastes a survey question.
217     * @param pageId The id of the page, target of the copy
218     * @param questionId The id of the question to copy
219     * @return The id of the created question, the id of the page and the id of the survey
220     */
221    @Callable
222    public Map<String, String> copyQuestion(String pageId, String questionId)
223    {
224        Map<String, String> result = new HashMap<>();
225        
226        SurveyQuestion originalQuestion = _resolver.resolveById(questionId);
227        SurveyPage parentPage = _resolver.resolveById(pageId);
228        
229        Survey originalSurvey = originalQuestion.getSurvey();
230        Survey parentSurvey = parentPage.getSurvey();
231        
232        String name = parentSurvey.findUniqueQuestionName(originalQuestion.getName());
233        SurveyQuestion cQuestion = originalQuestion.copyTo(parentPage, name);
234        
235        if (!originalSurvey.getId().equals(parentSurvey.getId()))
236        {
237            // Update rules references after copy
238            updateReferencesAfterCopy (originalSurvey, parentSurvey, cQuestion);
239        }
240        
241        parentPage.saveChanges();
242        
243        Map<String, Object> eventParams = new HashMap<>();
244        eventParams.put("survey", parentSurvey);
245        _observationManager.notify(new Event(SurveyEvents.SURVEY_MODIFIED, _getCurrentUser(), eventParams));
246        
247        result.put("id", cQuestion.getId());
248        result.put("pageId", parentPage.getId());
249        result.put("surveyId", parentSurvey.getId());
250        result.put("type", cQuestion.getType().toString());
251        
252        return result;
253    }
254    
255    /**
256     * Deletes a survey question.
257     * @param id The id of the survey question to delete
258     * @return The id of the deleted survey question, the id of the page and the id of the survey
259     */
260    @Callable
261    public Map<String, String> deleteQuestion (String id)
262    {
263        Map<String, String> result = new HashMap<>();
264        
265        SurveyQuestion question = _resolver.resolveById(id);
266        String type = question.getType().toString();
267        
268        SurveyPage page = question.getParent();
269        question.remove();
270        
271        page.saveChanges();
272        
273        Map<String, Object> eventParams = new HashMap<>();
274        eventParams.put("survey", page.getSurvey());
275        _observationManager.notify(new Event(SurveyEvents.SURVEY_MODIFIED, _getCurrentUser(), eventParams));
276        
277        result.put("id", id);
278        result.put("pageId", page.getId());
279        result.put("surveyId", page.getSurvey().getId());
280        result.put("type", type);
281        
282        return result;
283    }
284    
285    /**
286     * Adds a new rule to a question.
287     * @param id _resolver.resolveById(id);
288     * @param option The option
289     * @param rule The rule type
290     * @param page The page to jump or skip
291     * @return An empty map, or an error
292     */
293    @Callable
294    public Map<String, Object> addRule (String id, String option, String rule, String page)
295    {
296        Map<String, Object> result = new HashMap<>();
297        
298        SurveyQuestion question = _resolver.resolveById(id);
299        // Check if exists
300        if (question.hasRule(option))
301        {
302            result.put("error", "already-exists");
303            return result;
304        }
305        
306        question.addRules(option, RuleType.valueOf(rule), page);
307        question.saveChanges();
308        
309        Map<String, Object> eventParams = new HashMap<>();
310        eventParams.put("survey", question.getSurvey());
311        _observationManager.notify(new Event(SurveyEvents.SURVEY_MODIFIED, _getCurrentUser(), eventParams));
312        
313        return result;
314    }
315    
316    /**
317     * Deletes a rule to a question.
318     * @param id _resolver.resolveById(id);
319     * @param option The option to delete
320     * @return An empty map
321     */
322    @Callable
323    public Map<String, Object> deleteRule (String id, String option)
324    {
325        SurveyQuestion question = _resolver.resolveById(id);
326        
327        question.deleteRule(option);
328        question.saveChanges();
329        
330        Map<String, Object> eventParams = new HashMap<>();
331        eventParams.put("survey", question.getSurvey());
332        _observationManager.notify(new Event(SurveyEvents.SURVEY_MODIFIED, _getCurrentUser(), eventParams));
333        
334        return new HashMap<>();
335    }
336    
337    /**
338     * Gets the rules for a survey question.
339     * @param id The id of the survey question.
340     * @param number The question number
341     * @return The rules
342     */
343    @Callable
344    public Map<String, Object> getRules (String id, int number)
345    {
346        Map<String, Object> result = new HashMap<>();
347        
348        SurveyQuestion question = _resolver.resolveById(id);
349        Map<String, String> options = question.getOptions();
350        
351        result.put("id", question.getId());
352        result.put("number", String.valueOf(number));
353        result.put("title", question.getTitle());
354        
355        List<Object> rules = new ArrayList<>();
356        for (SurveyRule rule : question.getRules())
357        {
358            Map<String, Object> resultRule = new HashMap<>();
359            String option = rule.getOption();
360            resultRule.put("option", option);
361            resultRule.put("optionLabel", options.get(option));
362            resultRule.put("type", rule.getType().name());
363            String page = rule.getPage();
364            if (page != null)
365            {
366                try
367                {
368                    SurveyPage pageAO = _resolver.resolveById(page);
369                    resultRule.put("page", page);
370                    resultRule.put("pageName", pageAO.getLabel());
371                }
372                catch (UnknownAmetysObjectException e)
373                {
374                    // Page does not exist anymore
375                }
376            }
377                    
378            rules.add(resultRule);
379        }
380        
381        result.put("rules", rules);
382        
383        return result;
384    }
385
386}