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}