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.HashMap;
019import java.util.Map;
020
021import javax.jcr.RepositoryException;
022
023import org.apache.avalon.framework.component.Component;
024import org.apache.avalon.framework.context.Context;
025import org.apache.avalon.framework.context.ContextException;
026import org.apache.avalon.framework.context.Contextualizable;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.cocoon.Constants;
031import org.apache.cocoon.components.ContextHelper;
032import org.apache.cocoon.util.log.SLF4JLoggerAdapter;
033import org.apache.commons.lang.StringUtils;
034import org.slf4j.LoggerFactory;
035
036import org.ametys.cms.data.Binary;
037import org.ametys.core.observation.ObservationManager;
038import org.ametys.core.upload.Upload;
039import org.ametys.core.upload.UploadManager;
040import org.ametys.core.user.CurrentUserProvider;
041import org.ametys.core.user.UserIdentity;
042import org.ametys.core.util.JSONUtils;
043import org.ametys.plugins.explorer.resources.Resource;
044import org.ametys.plugins.repository.AmetysObject;
045import org.ametys.plugins.repository.AmetysObjectResolver;
046import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
047import org.ametys.plugins.repository.UnknownAmetysObjectException;
048import org.ametys.plugins.repository.jcr.JCRAmetysObject;
049import org.ametys.plugins.survey.repository.AbstractSurveyElement;
050import org.ametys.plugins.survey.repository.Survey;
051import org.ametys.plugins.survey.repository.SurveyPage;
052import org.ametys.plugins.survey.repository.SurveyQuestion;
053import org.ametys.plugins.survey.repository.SurveyRule;
054import org.ametys.plugins.survey.repository.SurveyRule.RuleType;
055import org.ametys.runtime.plugin.component.AbstractLogEnabled;
056import org.ametys.web.repository.site.SiteManager;
057
058/**
059 * Abstract DAO for objects in the plugin survey.
060 *
061 */
062public abstract class AbstractDAO extends AbstractLogEnabled implements Serviceable, Component, Contextualizable
063{
064    /** Ametys object resolver. */
065    protected AmetysObjectResolver _resolver;
066    /** The site manager */
067    protected SiteManager _siteManager;
068    /** Observer manager. */
069    protected ObservationManager _observationManager;
070    /** The current user provider. */
071    protected CurrentUserProvider _currentUserProvider;
072    /** Manager for retrieving uploaded files */
073    protected UploadManager _uploadManager;
074    /** JSON helper */
075    protected JSONUtils _jsonUtils;
076    
077    /** The Avalon context */
078    protected Context _context;
079    /** The cocoon context */
080    protected org.apache.cocoon.environment.Context _cocoonContext;
081    
082    @Override
083    public void service(ServiceManager serviceManager) throws ServiceException
084    {
085        _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE);
086        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
087        _observationManager = (ObservationManager) serviceManager.lookup(ObservationManager.ROLE);
088        _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE);
089        _uploadManager = (UploadManager) serviceManager.lookup(UploadManager.ROLE);
090        _jsonUtils = (JSONUtils) serviceManager.lookup(JSONUtils.ROLE);
091    }
092    
093    @Override
094    public void contextualize(Context context) throws ContextException
095    {
096        _context = context;
097        _cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
098    }
099    
100    /**
101     * Get the root node for surveys
102     * @param siteName the site name
103     * @param lang the language
104     * @return the root node
105     * @throws RepositoryException if an error occurs when manipulating the repository
106     */
107    protected ModifiableTraversableAmetysObject getSurveyRootNode (String siteName, String lang) throws RepositoryException
108    {
109        ModifiableTraversableAmetysObject pluginsNode = _siteManager.getSite(siteName).getRootPlugins();
110        
111        ModifiableTraversableAmetysObject surveyNode = null;
112        if (!pluginsNode.hasChild("survey"))
113        {
114            surveyNode = ((ModifiableTraversableAmetysObject) pluginsNode.createChild("survey", "ametys:unstructured")).createChild("ametys:surveys", "ametys:unstructured");
115        }
116        else
117        {
118            surveyNode = pluginsNode.getChild("survey/ametys:surveys");
119        }
120        
121        if (!surveyNode.hasChild(lang))
122        {
123            surveyNode.createChild(lang, "ametys:unstructured");
124            ((JCRAmetysObject) pluginsNode).getNode().getSession().save();
125        }
126        
127        return pluginsNode.getChild("survey/ametys:surveys/" + lang);
128    }
129    
130    /**
131     * Provides the current user.
132     * @return the user which cannot be <code>null</code>.
133     */
134    protected UserIdentity _getCurrentUser()
135    {      
136        return _currentUserProvider.getUser();
137    }
138    
139    /**
140     * Update references after a survey copy
141     * @param originalSurvey The original survey
142     * @param createdSurvey The created survey
143     */
144    protected void updateReferencesAfterCopy (Survey originalSurvey, Survey createdSurvey)
145    {
146        for (SurveyPage cPage : createdSurvey.getPages())
147        {
148            updateReferencesAfterCopy (originalSurvey, createdSurvey, cPage);
149        }
150    }
151    
152    /**
153     * Update references after copy
154     * @param originalSurvey The original survey
155     * @param createdSurvey The created survey
156     * @param createdPage The created survey page
157     */
158    protected void updateReferencesAfterCopy (Survey originalSurvey, Survey createdSurvey, SurveyPage createdPage)
159    {
160        if (createdPage.hasRule())
161        {
162            SurveyRule rule = createdPage.getRule();
163            String pageId = rule.getPage();
164            if (pageId != null)
165            {
166                try
167                {
168                    // Find symmetric page in created survey
169                    AmetysObject originalPage = _resolver.resolveById(pageId);
170                    AmetysObject symmetricPage = createdSurvey.getChild(originalPage.getName());
171                    createdPage.setRule(rule.getType(), symmetricPage.getId());
172                }
173                catch (UnknownAmetysObjectException e)
174                {
175                    // Delete the rule
176                    new SLF4JLoggerAdapter(LoggerFactory.getLogger(this.getClass())).warn("Symmetric page has not found during copy. The rule is deleted.");
177                    createdPage.deleteRule();
178                }
179            }
180        }
181        
182        for (SurveyQuestion cQuestion : createdPage.getQuestions())
183        {
184            updateReferencesAfterCopy (originalSurvey, createdSurvey, cQuestion);
185        }
186    }
187    
188    /**
189     * Update references after copy
190     * @param originalSurvey The original survey
191     * @param createdSurvey The created survey
192     * @param createdQuestion The created survey question
193     */
194    protected void updateReferencesAfterCopy (Survey originalSurvey, Survey createdSurvey, SurveyQuestion createdQuestion)
195    {
196        for (SurveyRule cRule : createdQuestion.getRules())
197        {
198            String pageId = cRule.getPage();
199            if (pageId != null)
200            {
201                String option = cRule.getOption();
202                try
203                {
204                    // Find symmetric page in created survey
205                    AmetysObject originalPage = _resolver.resolveById(pageId);
206                    AmetysObject symmetricPage = createdSurvey.getChild(originalPage.getName());
207                    
208                    RuleType type = cRule.getType();
209                    createdQuestion.deleteRule(option);
210                    createdQuestion.addRules(option, type, symmetricPage.getId());
211                }
212                catch (UnknownAmetysObjectException e)
213                {
214                    // Delete rule
215                    new SLF4JLoggerAdapter(LoggerFactory.getLogger(this.getClass())).warn("Symmetric page has not found during copy. The rule is deleted.");
216                    createdQuestion.deleteRule(option);
217                }
218            }
219        }
220    }
221    
222    /**
223     * Set the picture
224     * @param elmt The survey element
225     * @param valueAsStr The value as String
226     */
227    protected void setPicture (AbstractSurveyElement elmt, String valueAsStr)
228    {
229        if (StringUtils.isNotEmpty(valueAsStr))
230        {
231            Map<String, Object> picture = _jsonUtils.convertJsonToMap(valueAsStr);
232            
233            if (!picture.isEmpty())
234            {
235                String pictureType = (String) picture.get("type");
236                String value = (String) picture.get("id");
237                
238                if (pictureType.equals("explorer") && !"untouched".equals(value))
239                {
240                    elmt.setResourcePicture(value);
241                }
242                else if (!"untouched".equals(value))
243                {
244                    UserIdentity user = _currentUserProvider.getUser();
245                    Upload upload = _uploadManager.getUpload(user, value);
246                    
247                    String filename = upload.getFilename();
248                    String mimeType = upload.getMimeType() != null ? upload.getMimeType() : _cocoonContext.getMimeType(filename);
249                    String finalMimeType = mimeType != null ? mimeType : "application/unknown";
250                    
251                    elmt.setExternalPicture(finalMimeType, filename, upload.getInputStream());
252                }
253            }
254            else
255            {
256                // Remove picture
257                elmt.setNoPicture(); 
258            }
259            
260        }
261        else
262        {
263            // Remove picture
264            elmt.setNoPicture();
265        }
266    }
267    
268    /**
269     * Get the information about picture
270     * @param elmt The survey element
271     * @return The picture
272     */
273    protected Map<String, Object> getPictureInfo (AbstractSurveyElement elmt)
274    {
275        Map<String, Object> properties = new HashMap<>();
276        
277        properties.put("pictureAlternative", StringUtils.defaultString(elmt.getPictureAlternative()));
278        
279        Map<String, Object> pictureInfos = new HashMap<>();
280        String pictureType = elmt.getPictureType();
281        
282        if (StringUtils.isNotBlank(pictureType))
283        {
284            if (pictureType.equals("resource"))
285            {
286                String resourceId = elmt.getResourcePictureId();
287                pictureInfos.put("id", resourceId);
288                try
289                {
290                    Resource resource = _resolver.resolveById(resourceId);
291                    
292                    pictureInfos.put("filename", resource.getName());
293                    pictureInfos.put("size", resource.getLength());
294                    pictureInfos.put("type", "explorer");
295                    pictureInfos.put("lastModified", resource.getLastModified());
296                    
297                    String contextPath = ContextHelper.getRequest(_context).getContextPath();
298                    String viewUrl = contextPath + "/plugins/explorer/resource?id=" + resource.getId();
299                    String downloadUrl = viewUrl + "&download=true";
300                    pictureInfos.put("viewUrl", viewUrl);
301                    pictureInfos.put("downloadUrl", downloadUrl);
302                }
303                catch (UnknownAmetysObjectException e)
304                {
305                    getLogger().error("The resource of id'" + resourceId + "' does not exist anymore. The picture for element of id '" + elmt.getId() + "' will be ignored.", e);
306                    properties.put("pictureNotFound", true);
307                }
308            }
309            else if (pictureType.equals("external"))
310            {
311                Binary picMeta = elmt.getExternalPicture();
312                
313                pictureInfos.put("path", AbstractSurveyElement.PROPERTY_PICTURE);
314                pictureInfos.put("filename", picMeta.getFilename());
315                pictureInfos.put("size", picMeta.getLength());
316                pictureInfos.put("lastModified", picMeta.getLastModificationDate());
317                pictureInfos.put("type", "metadata");
318                
319                String contextPath = ContextHelper.getRequest(_context).getContextPath();
320                String viewUrl = contextPath + "/plugins/cms/binary/" + AbstractSurveyElement.PROPERTY_PICTURE + "?objectId=" + elmt.getId();
321                String downloadUrl = viewUrl + "&download=true";
322                pictureInfos.put("viewUrl", viewUrl);
323                pictureInfos.put("downloadUrl", downloadUrl);
324                
325            }
326        }
327        
328        properties.put("picture", pictureInfos);
329        
330        return properties;
331    }
332
333}