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.frontedition;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.HashMap;
022import java.util.LinkedHashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import javax.jcr.RepositoryException;
028
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032import org.apache.commons.lang3.ArrayUtils;
033import org.apache.commons.lang3.StringUtils;
034
035import org.ametys.cms.repository.Content;
036import org.ametys.cms.repository.WorkflowAwareContent;
037import org.ametys.cms.workflow.ContentWorkflowHelper;
038import org.ametys.core.right.RightManager;
039import org.ametys.core.right.RightManager.RightResult;
040import org.ametys.core.ui.ClientSideElement;
041import org.ametys.core.ui.ClientSideElement.Script;
042import org.ametys.core.ui.ClientSideElement.ScriptFile;
043import org.ametys.core.ui.widgets.richtext.RichTextConfiguration;
044import org.ametys.core.ui.widgets.richtext.RichTextConfigurationExtensionPoint;
045import org.ametys.core.util.JSONUtils;
046import org.ametys.plugins.core.ui.minimize.HashCache;
047import org.ametys.plugins.repository.AmetysObject;
048import org.ametys.plugins.repository.AmetysObjectResolver;
049import org.ametys.plugins.repository.AmetysRepositoryException;
050import org.ametys.plugins.repository.UnknownAmetysObjectException;
051import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
052import org.ametys.plugins.repository.jcr.JCRAmetysObject;
053import org.ametys.plugins.repository.version.VersionableAmetysObject;
054import org.ametys.plugins.workflow.support.WorkflowHelper;
055import org.ametys.web.WebConstants;
056import org.ametys.web.cache.PageHelper;
057import org.ametys.web.renderingcontext.RenderingContext;
058import org.ametys.web.repository.page.ModifiablePage;
059import org.ametys.web.repository.page.ModifiableZone;
060import org.ametys.web.repository.page.Page;
061import org.ametys.web.repository.page.ZoneItem;
062import org.ametys.web.repository.site.Site;
063import org.ametys.web.repository.site.SiteManager;
064import org.ametys.web.repository.sitemap.Sitemap;
065import org.ametys.web.transformation.xslt.AmetysXSLTHelper;
066
067/**
068 * Helper for preparing the Ametys Edition
069 */
070public class AmetysFrontEditionHelper implements Serviceable
071{
072    /** The right's id from front-edition access */
073    public static final String FRONT_EDITION_RIGHT_ID = "Front_Edition_Access_Right";
074    
075    private static AmetysObjectResolver _ametysObjectResolver;
076    private static HashCache _hashCache;
077    private static RichTextConfigurationExtensionPoint _richTextConfigurationExtensionPoint;
078    private static RightManager _rightManager;
079    private static ContentWorkflowHelper _contentWorkflowHelper;
080    private static PageHelper _pageHelper;
081    private static WorkflowHelper _workflowHelper;
082    private static JSONUtils _jsonUtils;
083    private static SiteManager _siteManager;
084
085    public void service(ServiceManager manager) throws ServiceException
086    {
087        _ametysObjectResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
088        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
089        _hashCache = (HashCache) manager.lookup(HashCache.ROLE);
090        _richTextConfigurationExtensionPoint = (RichTextConfigurationExtensionPoint) manager.lookup(RichTextConfigurationExtensionPoint.ROLE);
091        _rightManager = (RightManager) manager.lookup(RightManager.ROLE);
092        _contentWorkflowHelper = (ContentWorkflowHelper) manager.lookup(ContentWorkflowHelper.ROLE);
093        _pageHelper = (PageHelper) manager.lookup(PageHelper.ROLE);
094        _workflowHelper = (WorkflowHelper) manager.lookup(WorkflowHelper.ROLE);
095        _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE);
096    }
097    
098    /**
099     * Prepare a hashcode for js files
100     * @param locale The language code to use
101     * @param rtlMode Is for right-to-left language?
102     * @return The new hashcode to read the minimified concatened file
103     */
104    public static String prepareJSFiles(String locale, boolean rtlMode)
105    {
106        Map<String, String> filesInfos = new HashMap<>();
107        filesInfos.put("media", "");
108        filesInfos.put("tag", "script");
109        
110        Map<String, Map<String, String>> files = new LinkedHashMap<>();
111        files.put("/plugins/extjs6/resources/ext-all.js", filesInfos);
112        files.put("/plugins/extjs6/resources/classic/locale/locale-" + locale + ".js", filesInfos);
113        files.put("/plugins/extjs6/resources/classic/theme-triton/theme-triton.js", filesInfos);
114
115        files.put("/plugins/core-ui/resources/js/Ext.fixes.js", filesInfos);
116        files.put("/plugins/core-ui/resources/js/Ext.enhancements.js", filesInfos);
117        
118        files.put("/plugins/core-ui/resources/js/Ametys.js", filesInfos);
119        files.put("/plugins/core-ui/resources/js/Ametys/mask/GlobalLoadMask.js", filesInfos);
120        
121        files.put("/plugins/core-ui/resources/js/Ametys/log/Logger.js", filesInfos);
122        files.put("/plugins/core-ui/resources/js/Ametys/log/Logger/Entry.js", filesInfos);
123        files.put("/plugins/core-ui/resources/js/Ametys/log/LoggerFactory.js", filesInfos);
124        files.put("/plugins/core-ui/resources/js/Ametys/log/ErrorDialog.js", filesInfos);
125        
126        files.put("/plugins/core-ui/resources/js/Ametys/window/DialogBox.js", filesInfos);
127        files.put("/plugins/core-ui/resources/js/Ametys/window/MessageBox.js", filesInfos);
128        
129        files.put("/plugins/core-ui/resources/js/Ametys/form/AbstractField.js", filesInfos);
130        files.put("/plugins/core-ui/resources/js/Ametys/form/AbstractFieldsWrapper.js", filesInfos);
131        files.put("/plugins/core-ui/resources/js/Ametys/form/AbstractQueryableComboBox.js", filesInfos);
132        files.put("/plugins/core-ui/resources/js/Ametys/form/field/DateTime.js", filesInfos);
133        files.put("/plugins/core-ui/resources/js/Ametys/form/field/StringTime.js", filesInfos);
134        files.put("/plugins/core-ui/resources/js/Ametys/form/field/Password.js", filesInfos);
135        files.put("/plugins/core-ui/resources/js/Ametys/form/field/ChangePassword.js", filesInfos);
136        files.put("/plugins/core-ui/resources/js/Ametys/form/field/ReferencedNumberField.js", filesInfos);
137        files.put("/plugins/core-ui/resources/js/Ametys/form/field/RichText.js", filesInfos);
138        files.put("/plugins/core-ui/resources/js/Ametys/form/field/RichText/SplitterTracker.js", filesInfos);
139        files.put("/plugins/core-ui/resources/js/Ametys/form/field/TextArea.js", filesInfos);
140        files.put("/plugins/core-ui/resources/js/Ametys/form/field/ColorSelector.js", filesInfos);
141        files.put("/plugins/core-ui/resources/js/Ametys/form/field/SelectUserDirectory.js", filesInfos);
142        files.put("/plugins/core-ui/resources/js/Ametys/form/field/SelectGroupDirectories.js", filesInfos);
143        files.put("/plugins/core-ui/resources/js/Ametys/form/field/Code.js", filesInfos);
144        files.put("/plugins/tiny_mce/resources/js/tinymce.js", filesInfos);
145        files.put("/plugins/codemirror/resources/js/codemirror.js", filesInfos);
146        files.put("/plugins/codemirror/resources/js/addon/edit/matchbrackets.js", filesInfos);
147        files.put("/plugins/codemirror/resources/js/addon/selection/active-line.js", filesInfos);
148        files.put("/plugins/codemirror/resources/js/mode/xml/xml.js", filesInfos);
149        files.put("/plugins/codemirror/resources/js/mode/javascript/javascript.js", filesInfos);
150        files.put("/plugins/codemirror/resources/js/mode/css/css.js", filesInfos);
151        files.put("/plugins/codemirror/resources/js/mode/htmlmixed/htmlmixed.js", filesInfos);
152        
153        files.put("/plugins/core-ui/resources/js/Ametys/data/ServerCaller.js", filesInfos);
154        files.put("/plugins/core-ui/resources/js/Ametys/data/ServerComm.js", filesInfos);
155        files.put("/plugins/core-ui/resources/js/Ametys/data/ServerCommProxy.js", filesInfos);
156        files.put("/plugins/core-ui/resources/js/Ametys/data/ServerComm/TimeoutDialog.js", filesInfos);
157
158        files.put("/plugins/core-ui/resources/js/Ametys/form/widget/RichText/RichTextConfiguration.js", filesInfos);
159        
160        files.put("/plugins/core-ui/resources/js/Ametys/plugins/coreui/system/devmode/StacktraceHelper.js", filesInfos);
161
162        files.put("/plugins/front-edition/resources/js/front-comm.js", filesInfos);
163        files.put("/plugins/front-edition/resources/js/front-widget.js", filesInfos);
164//        files.put("/plugins/front-edition/resources/js/front-page.js", filesInfos);
165        files.put("/plugins/core-ui/resources/js/Ametys/helper/EnterURL.js", filesInfos);
166        files.put("/plugins/core-ui/resources/js/Ametys/helper/FileUpload.js", filesInfos);
167        files.put("/plugins/web/resources/js/Ametys/web/helper/ChoosePage.js", filesInfos);
168        files.put("/plugins/web/resources/js/Ametys/web/helper/ContextToolbar.js", filesInfos);
169        files.put("/plugins/web/resources/js/Ametys/web/sitemap/SitemapTree.js", filesInfos);
170        files.put("/plugins/web/resources/js/Ametys/web/sitemap/SitemapTree/Page.js", filesInfos);
171        files.put("/plugins/web/resources/js/Ametys/web/sitemap/SitemapTree/Sitemap.js", filesInfos);
172        files.put("/plugins/web/resources/js/Ametys/web/site/SitesTree/Site.js", filesInfos);
173        files.put("/plugins/cms/resources/js/Ametys/cms/editor/LinkHandler.js", filesInfos);
174        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/editor/Links.js", filesInfos);
175        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/editor/Links/LinkHandler.js", filesInfos);
176        files.put("/plugins/web/resources/js/Ametys/plugins/web/editor/Links.js", filesInfos);
177        files.put("/plugins/web/resources/js/Ametys/plugins/web/editor/PageLinkHandler.js", filesInfos);
178        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/editor/Images.js", filesInfos);
179        
180        files.put("/plugins/front-edition/resources/js/tinymce/lists.js", filesInfos);
181        files.put("/plugins/front-edition/resources/js/tinymce/links.js", filesInfos);
182        files.put("/plugins/front-edition/resources/js/tinymce/styles.js", filesInfos);
183        files.put("/plugins/front-edition/resources/js/tinymce/images.js", filesInfos);
184        files.put("/plugins/front-edition/resources/js/tinymce/save.js", filesInfos);
185
186        //TinyMCE Tables
187        files.put("/plugins/front-edition/resources/js/tinymce/tables.js", filesInfos);
188        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/editor/Tables.js", filesInfos);
189        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/editor/BasicActions.js", filesInfos);
190        //TinyMCE Images
191        files.put("/plugins/cms/resources/js/Ametys/cms/uihelper/ChooseResource.js", filesInfos);
192        files.put("/plugins/explorer/resources/js/Ametys/explorer/tree/ExplorerTree.js", filesInfos);
193        files.put("/plugins/explorer/resources/js/Ametys/explorer/tree/ExplorerTree/NodeEntry.js", filesInfos);
194        files.put("/plugins/explorer/resources/js/Ametys/explorer/Resource.js", filesInfos);
195        files.put("/plugins/explorer/resources/js/Ametys/explorer/ExplorerNodeDAO.js", filesInfos);
196        files.put("/plugins/explorer/resources/js/Ametys/explorer/applications/ExplorerApplicationProvider.js", filesInfos);
197        files.put("/plugins/cms/resources/js/Ametys/cms/attach/AttachmentsExplorerTree.js", filesInfos);
198        files.put("/plugins/cms/resources/js/Ametys/cms/uihelper/ChooseAttachmentFile.js", filesInfos);
199        files.put("/plugins/front-edition/resources/js/Ametys/override/cms/uihelper/ChooseAttachmentFile.js", filesInfos);
200        files.put("/plugins/explorer/resources/js/Ametys/explorer/resources/actions/FileActions.js", filesInfos);
201        files.put("/plugins/explorer/resources/js/Ametys/explorer/resources/helper/ResourceUpload.js", filesInfos);
202
203        //Empty Message class
204        files.put("/plugins/core-ui/resources/js/Ametys/message/Message.js", filesInfos);
205        files.put("/plugins/core-ui/resources/js/Ametys/message/MessageTarget.js", filesInfos);
206        files.put("/plugins/core-ui/resources/js/Ametys/message/MessageTargetFactory.js", filesInfos);
207        files.put("/plugins/core-ui/resources/js/Ametys/message/factory/DefaultMessageTargetFactory.js", filesInfos);
208        files.put("/plugins/front-edition/resources/js/Ametys/message/MessageTargetHelper.js", filesInfos);
209        //add page
210        files.put("/plugins/web/resources/js/Ametys/plugins/web/page/AddPageWizard.js", filesInfos);
211        files.put("/plugins/front-edition/resources/js/Ametys/override/plugins/web/page/AddPageWizard.js", filesInfos);
212        files.put("/plugins/web/resources/js/Ametys/web/sitemap/SitemapDAO.js", filesInfos);
213        files.put("/plugins/web/resources/js/Ametys/web/sitemap/Sitemap.js", filesInfos);
214        files.put("/plugins/web/resources/js/Ametys/web/page/PageDAO.js", filesInfos);
215        files.put("/plugins/front-edition/resources/js/Ametys/override/web/page/PageDAO.js", filesInfos);
216        files.put("/plugins/web/resources/js/Ametys/plugins/web/page/AddPageWizard/Card.js", filesInfos);
217        files.put("/plugins/web/resources/js/Ametys/plugins/web/page/AddPageWizard/CreatePageCard.js", filesInfos);
218        files.put("/plugins/web/resources/js/Ametys/plugins/web/page/AddPageWizard/PageContentCard.js", filesInfos);
219        files.put("/plugins/front-edition/resources/js/Ametys/override/plugins/web/page/AddPageWizard/PageContentCard.js", filesInfos);
220        files.put("/plugins/cms/resources/js/Ametys/cms/content/ContentDAO.js", filesInfos);
221        files.put("/plugins/web/resources/js/Ametys/web/content/ContentDAO.js", filesInfos);
222        files.put("/plugins/front-edition/resources/js/Ametys/override/cms/content/ContentDAO.js", filesInfos);
223        files.put("/plugins/cms/resources/js/Ametys/cms/content/Content.js", filesInfos);
224        files.put("/plugins/core-ui/resources/js/Ametys/navhistory/HistoryDAO.js", filesInfos);
225        files.put("/plugins/core-ui/resources/js/Ametys/window/MessageBox.js", filesInfos);
226        files.put("/plugins/front-edition/resources/js/Ametys/tool/ToolsManager.js", filesInfos);
227
228        files.put("/plugins/web/resources/js/Ametys/plugins/web/page/AddPageWizard/PageTypeCard.js", filesInfos);
229        files.put("/plugins/front-edition/resources/js/Ametys/override/plugins/web/page/AddPageWizard/PageTypeCard.js", filesInfos);
230        files.put("/plugins/web/resources/js/Ametys/web/form/widget/SelectPage.js", filesInfos);
231        files.put("/plugins/front-edition/resources/js/Ametys/override/web/form/widget/SelectPage.js", filesInfos);
232        files.put("/plugins/web/resources/js/Ametys/web/form/widget/SelectSite.js", filesInfos);
233        files.put("/plugins/web/resources/js/Ametys/web/helper/ChooseSite.js", filesInfos);
234        files.put("/plugins/web/resources/js/Ametys/web/site/SitesTree.js", filesInfos);
235        files.put("/plugins/web/resources/js/Ametys/web/site/SitesTree/Site.js", filesInfos);
236        files.put("/plugins/web/resources/js/Ametys/web/helper/ContextToolbar.js", filesInfos);
237        files.put("/plugins/web/resources/js/Ametys/web/site/SitesTree/Site.js", filesInfos);
238        files.put("/plugins/web/resources/js/Ametys/web/form/widget/SelectPage/PageEntry.js", filesInfos);
239        files.put("/plugins/web/resources/js/Ametys/plugins/web/page/AddPageWizard/TagsCard.js", filesInfos);
240        files.put("/plugins/web/resources/js/Ametys/web/page/Page.js", filesInfos);
241        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/tag/TagsTreePanel.js", filesInfos);
242        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/tag/TagsTreePanel/TagNode.js", filesInfos);
243
244        //delete page
245        files.put("/plugins/front-edition/resources/js/Ametys/override/Ametys.js", filesInfos);
246        files.put("/plugins/web/resources/js/Ametys/plugins/web/sitemap/SitemapActions.js", filesInfos);
247
248        //page tags
249        files.put("/plugins/web/resources/js/Ametys/plugins/web/tag/AffectTagAction.js", filesInfos);
250        files.put("/plugins/cms/resources/js/Ametys/cms/uihelper/ChooseTagHelper.js", filesInfos);
251        files.put("/plugins/cms/resources/js/Ametys/cms/uihelper/ChooseTag.js", filesInfos);
252        files.put("/plugins/web/resources/js/Ametys/web/helper/ChooseTag.js", filesInfos);
253        files.put("/plugins/cms/resources/js/Ametys/plugins/cms/tag/TagActions.js", filesInfos);
254        files.put("/plugins/web/resources/js/Ametys/plugins/web/tag/TagsTreePanel.js", filesInfos);
255
256        // ping
257        files.put("/plugins/core-ui/resources/js/Ametys/plugins/coreui/system/StartTimeChecker.js", filesInfos);
258
259        // actions on content
260        files.put("/plugins/web/resources/js/Ametys/plugins/web/zone/ZoneActions.js", filesInfos);
261        files.put("/plugins/web/resources/js/Ametys/plugins/web/zone/ZoneDAO.js", filesInfos);
262
263        // file widget
264        files.put("/plugins/core-ui/resources/js/Ametys/form/widget/File.js", filesInfos);
265        files.put("/plugins/core-ui/resources/js/Ametys/form/widget/File/FileSource.js", filesInfos);
266        files.put("/plugins/core-ui/resources/js/Ametys/form/widget/File/External.js", filesInfos);
267        files.put("/plugins/cms/resources/js/Ametys/cms/form/widget/File/Resource.js", filesInfos);
268
269        // Let's add all richtextconfiguration files
270        _addRichTextConfigurationFiles(files, filesInfos, locale, rtlMode, true);
271
272        return _hashCache.createHash(files, locale);
273    }
274
275    /**
276     * Prepare a hashcode for css files
277     * @param locale The language code to use
278     * @param rtlMode Is for right-to-left language?
279     * @return The new hashcode to read the minimified concatened file
280     */
281    public static String prepareCSSFiles(String locale, boolean rtlMode)
282    {
283        Map<String, String> filesInfos = new HashMap<>();
284        filesInfos.put("media", "");
285        filesInfos.put("tag", "link");
286        
287        Map<String, Map<String, String>> files = new LinkedHashMap<>();
288        files.put("/plugins/extjs6/resources/classic/theme-triton/resources/theme-triton-all.css", filesInfos); 
289        files.put("/plugins/front-edition/resources/css/theme-ametys-base-light.css", filesInfos);
290        files.put("/plugins/core-ui/resources/font/ametys/AmetysIcon.css", filesInfos);
291        
292        // Let's add all richtextconfiguration files
293        _addRichTextConfigurationFiles(files, filesInfos, locale, rtlMode, false);
294        
295        return _hashCache.createHash(files, locale);
296    }
297
298    private static List<ScriptFile> _getRichTextConfigurationFiles(boolean scripts, Map<String, Object> contextParameters)
299    {
300        List<ScriptFile> files = new ArrayList<>();
301        
302        for (String richTextConfigurationId : _richTextConfigurationExtensionPoint.getExtensionsIds())
303        {
304            RichTextConfiguration richTextConfiguration = _richTextConfigurationExtensionPoint.getExtension(richTextConfigurationId);
305            for (String category : richTextConfiguration.getCategories())
306            {
307                Set<ClientSideElement> convertors = richTextConfiguration.getConvertors(category, contextParameters);
308                if (convertors != null)
309                {
310                    for (ClientSideElement convertor : convertors)
311                    {
312                        List<Script> scriptsToAdd = convertor.getScripts(Collections.EMPTY_MAP);
313                        if (scriptsToAdd != null)
314                        {
315                            for (Script script : scriptsToAdd)
316                            {
317                                List<ScriptFile> scriptFiles = scripts ? script.getScriptFiles() : script.getCSSFiles();
318                                if (scriptFiles != null)
319                                {
320                                    files.addAll(scriptFiles);
321                                }
322                            }
323                        }
324                    }
325                }
326
327                Set<ClientSideElement> validators = richTextConfiguration.getValidators(category, contextParameters);
328                if (validators != null)
329                {
330                    for (ClientSideElement validator : validators)
331                    {
332                        List<Script> scriptsToAdd = validator.getScripts(Collections.EMPTY_MAP);
333                        if (scriptsToAdd != null)
334                        {
335                            for (Script script : scriptsToAdd)
336                            {
337                                List<ScriptFile> scriptFiles = scripts ? script.getScriptFiles() : script.getCSSFiles();
338                                if (scriptFiles != null)
339                                {
340                                    files.addAll(scriptFiles);
341                                }
342                            }
343                        }
344                    }
345                }
346            }
347        }
348
349        return files;
350    }
351
352    private static void _addRichTextConfigurationFiles(Map<String, Map<String, String>> files, Map<String, String> filesInfos, String locale, boolean rtlMode, boolean scripts)
353    {
354        Map<String, Object> contextParameters = new HashMap<>();
355        contextParameters.put("siteName", AmetysXSLTHelper.site());
356        
357        List<ScriptFile> richTextConfigurationFiles = _getRichTextConfigurationFiles(scripts, contextParameters);
358        for (ScriptFile file : richTextConfigurationFiles)
359        {
360            String uri = null;
361            if (file.isLangSpecific())
362            {
363                if (file.getLangPaths().containsKey(locale))
364                {
365                    uri = file.getLangPaths().get(locale);
366                }
367                else if (file.getLangPaths().containsKey(file.getDefaultLang()))
368                {
369                    uri = file.getLangPaths().get(file.getDefaultLang());
370                }
371            }
372            else
373            {
374                if (file.getRtlMode() == null || "all".equals(file.getRtlMode()) || Boolean.toString(rtlMode).equals(file.getRtlMode()))
375                {
376                    uri = file.getPath();
377                }
378            }
379            
380            if (uri != null)
381            {
382                files.put(uri, filesInfos);
383            }
384        }
385    }
386    /**
387     * Check if we can display the front edition button for a specific right
388     * Checks :
389     * * Rendering context == front
390     * * Edition mode
391     * * Front_Edition_Access_Right
392     * * RightId available
393     * @param rightId right to check (can be null)
394     * @param inputPageId page to check
395     * @return true if all is OK, false if at least one is false
396     * @deprecated Use the version with three arguments
397     */
398    @Deprecated
399    public static boolean hasFrontEditionRight(String rightId, String inputPageId)
400    {
401        return hasFrontEditionRight(rightId, inputPageId, true);
402    }
403    /**
404     * Check if we can display the front edition button for a specific right
405     * Checks :
406     * * Rendering context == front
407     * * Edition mode
408     * * Front_Edition_Access_Right
409     * * RightId available
410     * @param rightId right to check (can be null)
411     * @param objectId page/content to check
412     * @param editionModeOnly Check if the user is in edition mode
413     * @return true if all is OK, false if at least one is false
414     */
415    public static boolean hasFrontEditionRight(String rightId, String objectId, boolean editionModeOnly)
416    {
417        String pageId = objectId;
418        if (StringUtils.isEmpty(pageId))
419        {
420            pageId = AmetysXSLTHelper.pageId();
421        }
422        
423        if (StringUtils.isEmpty(pageId)                                 // No page to check
424            || !RenderingContext.FRONT.toString().equals(AmetysXSLTHelper.renderingContext())     // We are no on front
425            || (editionModeOnly && !AmetysXSLTHelper.isEditionMode())   // Not in edition mode
426            || !hasFrontEditionRight())                                 // The user has the front edition right
427        {
428            
429            return false;
430        }
431        
432        
433        return StringUtils.isEmpty(rightId) // There is no right to check OR the user has the right
434                || _rightManager.currentUserHasRight(rightId, _ametysObjectResolver.resolveById(pageId)) == RightResult.RIGHT_ALLOW;   // Check right on page (If this page does not exists an exception will be thrown... this is fine)
435    }
436    /**
437     * Check if the current user has the Front_Edition_Access_Right right
438     * @return true if right granted
439     */
440    public static boolean hasFrontEditionRight()
441    {
442        String pageId = AmetysXSLTHelper.pageId();
443        if (StringUtils.isNotEmpty(pageId))
444        {
445            Page page = _ametysObjectResolver.resolveById(pageId);
446            return _rightManager.currentUserHasRight(FRONT_EDITION_RIGHT_ID, page) == RightResult.RIGHT_ALLOW;
447        }
448        
449        String lang = AmetysXSLTHelper.lang();
450        String siteName = AmetysXSLTHelper.site();
451        
452        if (StringUtils.isNotEmpty(siteName) && StringUtils.isNoneEmpty(lang))
453        {
454            Site site = _siteManager.getSite(siteName);
455            Sitemap sitemap = site.getSitemap(lang);
456            return _rightManager.currentUserHasRight(FRONT_EDITION_RIGHT_ID, sitemap) == RightResult.RIGHT_ALLOW;
457        }
458        
459        return false;
460    }
461    /**
462     * Check if the current workflow action is available on this content
463     * @param actionId action to check
464     * @param contentId content to check
465     * @param checkEditionMode check also if we are in edition mode
466     * @return true if right is granted
467     */
468    public static boolean hasWorkflowRight(int actionId, String contentId, boolean checkEditionMode)
469    {
470        List<Integer> actionIds = new ArrayList<>();
471        actionIds.add(actionId);
472        return hasWorkflowRight(actionIds, contentId, checkEditionMode);
473    }
474    /**
475     * Check if a list of workflow actions are available on this content
476     * @param actionIds list of action ids
477     * @param contentId id of the content to check
478     * @param checkEditionMode check also if we are in edition mode
479     * @return true if all actions are available
480     */
481    public static boolean hasWorkflowRight(List<Integer> actionIds, String contentId, boolean checkEditionMode)
482    {
483        Content content = _ametysObjectResolver.resolveById(contentId);
484        return hasWorkflowRight(actionIds, content, checkEditionMode);
485    }
486    /**
487     * Check if a list of workflow actions are available on this content
488     * @param actionIds list of action ids
489     * @param content content to check
490     * @param checkEditionMode check also if we are in edition mode
491     * @return true if all actions are available
492     */
493    public static boolean hasWorkflowRight(List<Integer> actionIds, Content content, boolean checkEditionMode)
494    {
495        if (checkEditionMode)
496        {
497            boolean editionModeOk = AmetysXSLTHelper.isEditionMode();
498            if (!editionModeOk)
499            {
500                return false;
501            }
502        }
503        boolean result = false;
504        if (content instanceof WorkflowAwareContent)
505        {
506            WorkflowAwareContent wcontent = (WorkflowAwareContent) content;
507            int[] availableActions = _contentWorkflowHelper.getAvailableActions(wcontent);
508            for (int actionId : actionIds)
509            {
510                result = result || ArrayUtils.contains(availableActions, actionId);
511                if (result)
512                {
513                    break;
514                }
515            }
516        }
517        return result;
518    }
519    /**
520     * Get a string representing a json map of the contentIds with true/false if they can/can't be modified 
521     * @param actionId action to check
522     * @param inputPageId page (can be null)
523     * @param checkEditionMode check also if we are in edition mode
524     * @return {contentId : true/false, ....}
525     */
526    public static String getContentModifiables(int actionId, String inputPageId, boolean checkEditionMode)
527    {
528        Map<String, Boolean> jsonObject = new HashMap<>();
529        List<Integer> actionIds = new ArrayList<>();
530        actionIds.add(actionId);
531        String pageId = inputPageId;
532        if (StringUtils.isEmpty(inputPageId))
533        {
534            pageId = AmetysXSLTHelper.pageId();
535        }
536        if (!StringUtils.isEmpty(pageId))
537        {
538            AmetysObject resolveById = _ametysObjectResolver.resolveById(pageId);
539            if (resolveById instanceof Page)
540            {
541                Page page = (Page) resolveById;
542                List<Content> contents = _pageHelper.getAllContents(page);
543                for (Content content : contents)
544                {
545                    jsonObject.put(content.getId(), hasWorkflowRight(actionIds, content, checkEditionMode));
546                }
547            }
548        }
549
550        return _jsonUtils.convertObjectToJson(jsonObject);
551    }
552    /**
553     * Get the name of a workflow action
554     * @param workflowName workflow name
555     * @param actionId action id in the workflow
556     * @return name of the workflow action
557     */
558    public static String getWorkflowName(String workflowName, int actionId)
559    {
560        String workflowNameKey = _workflowHelper.getActionName(workflowName, actionId);
561        String translatedName = org.ametys.core.util.AmetysXSLTHelper.translate(workflowNameKey);
562        return translatedName;
563    }
564    /**
565     * Get the status (validated/draft) of all contents in a page
566     * @param pageId id of the page to check
567     * @return "" if not a page, "draft" if all contents are drafts, "validated" if all contents are validated, and "mixed" if there are both
568     */
569    public String getPageStatus(String pageId)
570    {
571        boolean hasDraft = false;
572        boolean hasValidated = false;
573        AmetysObject resolveById = _ametysObjectResolver.resolveById(pageId);
574        if (resolveById instanceof Page)
575        {
576            Page page = (Page) resolveById;
577            List<Content> contents = _pageHelper.getAllContents(page);
578            for (Content content : contents)
579            {
580                if (isContentLive(content))
581                {
582                    hasValidated = true;
583                }
584                else
585                {
586                    hasDraft = true;
587                }
588            }
589            String result = "none";
590            if (hasDraft && !hasValidated)
591            {
592                result = "draft";
593            }
594            else if (!hasDraft && hasValidated)
595            {
596                result = "validated";
597            }
598            else if (hasDraft && hasValidated)
599            {
600                result = "mixed";
601            }
602            return result;
603        }
604        else
605        {
606            return "";
607        }
608    }
609
610    /**
611     * Get the workflow step id of a content
612     * @param contentId id of the content
613     * @return the step Id
614     */
615    public long getContentWorkflowId(String contentId)
616    {
617        AmetysObject resolvedById = _ametysObjectResolver.resolveById(contentId);
618        if (resolvedById instanceof Content)
619        {
620            Content content = (Content) resolvedById;
621            return getContentWorkflowId(content);
622        }
623        else
624        {
625            return 0;
626        }
627    }
628    /**
629     * Get the workflow step id of a content
630     * @param content content
631     * @return the step Id
632     */
633    public long getContentWorkflowId(Content content)
634    {
635        WorkflowAwareContent wContent = (WorkflowAwareContent) content;
636        return wContent.getCurrentStepId();
637    }
638
639    /**
640     * check if a content is published ot not
641     * @param contentId id of the content
642     * @return "validated" or "draft", "" if not found
643     */
644    public String getContentStatus(String contentId)
645    {
646        AmetysObject resolvedById = _ametysObjectResolver.resolveById(contentId);
647        if (resolvedById instanceof Content)
648        {
649            Content content = (Content) resolvedById;
650            return getContentStatus(content);
651        }
652        else
653        {
654            return "";
655        }
656    }
657    /**
658     * check if a content is published ot not
659     * @param content content
660     * @return "validated" or "draft"
661     */
662    public String getContentStatus(Content content)
663    {
664        return isContentLive(content) ? "validated" : "draft";
665    }
666    /**
667     * check if a content is published ot not
668     * @param contentId id of the content
669     * @return true if validated
670     */
671    public boolean isContentLive(String contentId)
672    {
673        AmetysObject resolvedById = _ametysObjectResolver.resolveById(contentId);
674        if (resolvedById instanceof Content)
675        {
676            Content content = (Content) resolvedById;
677            return isContentLive(content);
678        }
679        else
680        {
681            return false;
682        }
683    }
684    /**
685     * check if a content is published ot not
686     * @param content content
687     * @return true if validated
688     */
689    public boolean isContentLive(Content content)
690    {
691        return Arrays.asList(((VersionableAmetysObject) content).getLabels()).contains(WebConstants.LIVE_LABEL);
692    }
693    /**
694     * Get the position of this zoneItem in the zone, or -1 if not found
695     * @param zoneItemId zoneitem to search
696     * @param pageId page id
697     * @return zero based position, -1 if not found
698     * @throws UnknownAmetysObjectException If an error occurred
699     * @throws AmetysRepositoryException If an error occurred
700     * @throws RepositoryException If an error occurred
701     */
702    public long getZoneItemPosition(String zoneItemId, String pageId) throws UnknownAmetysObjectException, AmetysRepositoryException, RepositoryException
703    {
704        ModifiablePage page = _ametysObjectResolver.resolveById(pageId);
705        ZoneItem zoneItem = page instanceof JCRAmetysObject ? (ZoneItem) _ametysObjectResolver.resolveById(zoneItemId, ((JCRAmetysObject) page).getNode().getSession()) : (ZoneItem) _ametysObjectResolver.resolveById(zoneItemId);
706        AmetysObject parent = zoneItem.getParent();
707        if (parent instanceof DefaultTraversableAmetysObject)
708        {
709            return ((DefaultTraversableAmetysObject) parent).getChildPosition(zoneItem);
710        }
711        return -1;
712    }
713    /**
714     * Return the size of a zone
715     * @param zoneName zone name
716     * @param pageId page Id
717     * @return size of the zone (-1 if not found)
718     */
719    public long getZoneSize(String zoneName, String pageId)
720    {
721        ModifiablePage page = _ametysObjectResolver.resolveById(pageId);
722        ModifiableZone zone = page.getZone(zoneName);
723        if (zone != null)
724        {
725            return zone.getZoneItems().getSize();
726        }
727        return -1;
728    }
729}