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.web.repository.page; 017 018import java.time.ZonedDateTime; 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.Date; 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Locale; 028import java.util.Map; 029import java.util.Set; 030 031import javax.jcr.Node; 032import javax.jcr.Repository; 033import javax.jcr.RepositoryException; 034import javax.jcr.Session; 035 036import org.apache.avalon.framework.component.Component; 037import org.apache.avalon.framework.logger.AbstractLogEnabled; 038import org.apache.avalon.framework.service.ServiceException; 039import org.apache.avalon.framework.service.ServiceManager; 040import org.apache.avalon.framework.service.Serviceable; 041import org.apache.commons.lang.StringUtils; 042 043import org.ametys.cms.FilterNameHelper; 044import org.ametys.cms.contenttype.ContentType; 045import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 046import org.ametys.cms.languages.Language; 047import org.ametys.cms.repository.Content; 048import org.ametys.cms.repository.ContentDAO.TagMode; 049import org.ametys.cms.repository.ModifiableContent; 050import org.ametys.cms.repository.TaggableAmetysObject; 051import org.ametys.cms.repository.WorkflowAwareContent; 052import org.ametys.cms.tag.CMSTag; 053import org.ametys.cms.tag.Tag; 054import org.ametys.cms.tag.TagProviderExtensionPoint; 055import org.ametys.core.observation.Event; 056import org.ametys.core.observation.ObservationManager; 057import org.ametys.core.right.RightManager; 058import org.ametys.core.right.RightManager.RightResult; 059import org.ametys.core.ui.Callable; 060import org.ametys.core.user.CurrentUserProvider; 061import org.ametys.core.user.UserIdentity; 062import org.ametys.plugins.explorer.ExplorerNode; 063import org.ametys.plugins.explorer.resources.ModifiableResourceCollection; 064import org.ametys.plugins.explorer.resources.Resource; 065import org.ametys.plugins.repository.AmetysObject; 066import org.ametys.plugins.repository.AmetysObjectIterable; 067import org.ametys.plugins.repository.AmetysObjectIterator; 068import org.ametys.plugins.repository.AmetysObjectResolver; 069import org.ametys.plugins.repository.AmetysRepositoryException; 070import org.ametys.plugins.repository.CopiableAmetysObject; 071import org.ametys.plugins.repository.ModifiableAmetysObject; 072import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 073import org.ametys.plugins.repository.RemovableAmetysObject; 074import org.ametys.plugins.repository.TraversableAmetysObject; 075import org.ametys.plugins.repository.UnknownAmetysObjectException; 076import org.ametys.plugins.repository.jcr.JCRAmetysObject; 077import org.ametys.plugins.repository.jcr.SimpleAmetysObject; 078import org.ametys.plugins.repository.lock.LockHelper; 079import org.ametys.plugins.repository.lock.LockableAmetysObject; 080import org.ametys.plugins.repository.version.VersionableAmetysObject; 081import org.ametys.plugins.workflow.support.WorkflowProvider; 082import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 083import org.ametys.runtime.i18n.I18nizableText; 084import org.ametys.runtime.model.type.ElementType; 085import org.ametys.runtime.model.type.ModelItemTypeConstants; 086import org.ametys.web.ObservationConstants; 087import org.ametys.web.WebConstants; 088import org.ametys.web.alias.Alias.TargetType; 089import org.ametys.web.alias.AliasHelper; 090import org.ametys.web.alias.DefaultAlias; 091import org.ametys.web.languages.WebLanguagesManager; 092import org.ametys.web.repository.content.SharedContent; 093import org.ametys.web.repository.content.WebContent; 094import org.ametys.web.repository.content.WebContentDAO; 095import org.ametys.web.repository.content.shared.SharedContentManager; 096import org.ametys.web.repository.page.Page.LinkType; 097import org.ametys.web.repository.page.Page.PageType; 098import org.ametys.web.repository.page.ZoneItem.ZoneType; 099import org.ametys.web.repository.page.jcr.DefaultPage; 100import org.ametys.web.repository.site.Site; 101import org.ametys.web.repository.sitemap.Sitemap; 102import org.ametys.web.rights.PageRightAssignmentContext; 103import org.ametys.web.service.Service; 104import org.ametys.web.service.ServiceExtensionPoint; 105import org.ametys.web.skin.Skin; 106import org.ametys.web.skin.SkinTemplate; 107import org.ametys.web.skin.SkinTemplateZone; 108import org.ametys.web.skin.SkinsManager; 109import org.ametys.web.skin.TemplatesAssignmentHandler; 110import org.ametys.web.synchronization.SynchronizeComponent; 111 112/** 113 * DAO for manipulating pages 114 * 115 */ 116public class PageDAO extends AbstractLogEnabled implements Serviceable, Component 117{ 118 /** Constant for untouched binary metadata. */ 119 public static final String __SERVICE_PARAM_UNTOUCHED_BINARY = "untouched"; 120 121 /** Avalon Role */ 122 public static final String ROLE = PageDAO.class.getName(); 123 124 private AmetysObjectResolver _resolver; 125 private ObservationManager _observationManager; 126 private CurrentUserProvider _currentUserProvider; 127 private SkinsManager _skinsManager; 128 private TemplatesAssignmentHandler _templatesHandler; 129 private ServicesAssignmentHandler _serviceHandler; 130 private ContentTypesAssignmentHandler _cTypeHandler; 131 private ContentTypeExtensionPoint _contentTypeExtensionPoint; 132 private ServiceExtensionPoint _serviceExtensionPoint; 133 private WorkflowProvider _workflowProvider; 134 private SharedContentManager _sharedContentManager; 135 private TagProviderExtensionPoint _tagProvider; 136 private WebLanguagesManager _webLanguagesManager; 137 private WebContentDAO _contentDAO; 138 private CopySiteComponent _copySiteComponent; 139 private RightManager _rightManager; 140 private SynchronizeComponent _synchronizeComponent; 141 private Repository _repository; 142 private PageDataTypeExtensionPoint _pageDataTypeExtensionPoint; 143 144 @Override 145 public void service(ServiceManager smanager) throws ServiceException 146 { 147 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 148 _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE); 149 _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 150 _skinsManager = (SkinsManager) smanager.lookup(SkinsManager.ROLE); 151 _templatesHandler = (TemplatesAssignmentHandler) smanager.lookup(TemplatesAssignmentHandler.ROLE); 152 _cTypeHandler = (ContentTypesAssignmentHandler) smanager.lookup(ContentTypesAssignmentHandler.ROLE); 153 _serviceHandler = (ServicesAssignmentHandler) smanager.lookup(ServicesAssignmentHandler.ROLE); 154 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE); 155 _serviceExtensionPoint = (ServiceExtensionPoint) smanager.lookup(ServiceExtensionPoint.ROLE); 156 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 157 _sharedContentManager = (SharedContentManager) smanager.lookup(SharedContentManager.ROLE); 158 _tagProvider = (TagProviderExtensionPoint) smanager.lookup(TagProviderExtensionPoint.ROLE); 159 _webLanguagesManager = (WebLanguagesManager) smanager.lookup(WebLanguagesManager.ROLE); 160 _contentDAO = (WebContentDAO) smanager.lookup(WebContentDAO.ROLE); 161 _copySiteComponent = (CopySiteComponent) smanager.lookup(CopySiteComponent.ROLE); 162 _rightManager = (RightManager) smanager.lookup(RightManager.ROLE); 163 _synchronizeComponent = (SynchronizeComponent) smanager.lookup(SynchronizeComponent.ROLE); 164 _repository = (Repository) smanager.lookup(Repository.class.getName()); 165 _pageDataTypeExtensionPoint = (PageDataTypeExtensionPoint) smanager.lookup(PageDataTypeExtensionPoint.ROLE); 166 } 167 168 /** 169 * Get the properties of given pages 170 * @param pageIds the id of pages 171 * @return the properties of pages in a result map 172 */ 173 @Callable 174 public Map<String, Object> getPagesInfos (List<String> pageIds) 175 { 176 Map<String, Object> result = new HashMap<>(); 177 178 List<Map<String, Object>> pages = new ArrayList<>(); 179 List<String> pagesNotFound = new ArrayList<>(); 180 181 for (String pageId : pageIds) 182 { 183 try 184 { 185 Page page = _resolver.resolveById(pageId); 186 pages.add(getPageInfos(page)); 187 } 188 catch (UnknownAmetysObjectException e) 189 { 190 pagesNotFound.add(pageId); 191 } 192 } 193 194 result.put("pages", pages); 195 result.put("pagesNotFound", pagesNotFound); 196 197 return result; 198 } 199 200 /** 201 * Get the page's properties 202 * @param pageId the page ID 203 * @return the properties 204 */ 205 @Callable 206 public Map<String, Object> getPageInfos (String pageId) 207 { 208 Page page = _resolver.resolveById(pageId); 209 return getPageInfos(page); 210 } 211 212 /** 213 * Get the page's properties 214 * @param page the page 215 * @return the properties 216 */ 217 public Map<String, Object> getPageInfos (Page page) 218 { 219 Map<String, Object> infos = new HashMap<>(); 220 221 infos.put("id", page.getId()); 222 infos.put("name", page.getName()); 223 infos.put("parentId", page.getParent().getId()); 224 infos.put("title", page.getTitle()); 225 infos.put("longTitle", page.getLongTitle()); 226 infos.put("path", page.getPathInSitemap()); 227 infos.put("siteName", page.getSiteName()); 228 infos.put("type", page.getType()); 229 infos.put("lang", page.getSitemapName()); 230 infos.put("isModifiable", page instanceof ModifiablePage); 231 infos.put("isMoveable", page instanceof MoveablePage); 232 infos.put("isTaggable", page instanceof TaggableAmetysObject); 233 infos.put("isVisible", page.isVisible()); 234 infos.put("isParentInvisible", _isParentInvisible(page)); 235 // Publication information 236 infos.put("publication", _publication2Json(page)); 237 infos.put("isPreviewable", _isPreviewable(page)); 238 239 String skinId = page.getSite().getSkinId(); 240 Skin skin = _skinsManager.getSkin(skinId); 241 infos.put("isPageValid", _synchronizeComponent.isPageValid(page, skin)); 242 243 Session liveSession = null; 244 try 245 { 246 liveSession = _repository.login(WebConstants.LIVE_WORKSPACE); 247 infos.put("isLiveHierarchyValid", _synchronizeComponent.isHierarchyValid(page, liveSession)); 248 } 249 catch (RepositoryException e) 250 { 251 throw new RuntimeException("Unable to check live workspace", e); 252 } 253 finally 254 { 255 if (liveSession != null) 256 { 257 liveSession.logout(); 258 } 259 } 260 261 PageType type = page.getType(); 262 switch (type) 263 { 264 case CONTAINER: 265 infos.put("template", page.getTemplate()); 266 267 List<Map<String, Object>> zones = new ArrayList<>(); 268 for (Zone zone : page.getZones()) 269 { 270 zones.add(_zone2json(zone)); 271 } 272 infos.put("zones", zones); 273 break; 274 275 case LINK: 276 infos.put("url", page.getURL()); 277 278 LinkType urlType = page.getURLType(); 279 infos.put("urlType", urlType.toString()); 280 281 switch (urlType) 282 { 283 case PAGE: 284 try 285 { 286 Page targetPage = _resolver.resolveById(page.getURL()); 287 infos.put("urlTitle", targetPage.getTitle()); 288 } 289 catch (UnknownAmetysObjectException e) 290 { 291 getLogger().error("Page '" + page.getId() + "' redirects to an unexisting page '" + page.getURL() + "'"); 292 } 293 break; 294 295 default: 296 break; 297 } 298 break; 299 default: 300 AmetysObjectIterator< ? extends Page> iterator = page.getChildrenPages().iterator(); 301 if (iterator.hasNext()) 302 { 303 Page firstSubPage = iterator.next(); 304 infos.put("url", firstSubPage.getId()); 305 infos.put("urlTitle", firstSubPage.getTitle()); 306 infos.put("urlType", LinkType.PAGE.toString()); 307 break; 308 309 } 310 break; 311 } 312 313 314 infos.put("rights", getUserRights(page)); 315 316 return infos; 317 } 318 319 /** 320 * Get the page's properties 321 * @param pageId the id of page 322 * @return the properties 323 */ 324 @Callable 325 public Map<String, Object> getPageProperties (String pageId) 326 { 327 Page page = _resolver.resolveById(pageId); 328 329 Map<String, Object> infos = new HashMap<>(); 330 331 infos.put("id", page.getId()); 332 infos.put("name", page.getName()); 333 infos.put("parentId", page.getParent().getId()); 334 infos.put("title", page.getTitle()); 335 infos.put("longTitle", page.getLongTitle()); 336 infos.put("path", page.getPathInSitemap()); 337 infos.put("siteName", page.getSiteName()); 338 infos.put("siteTitle", page.getSite().getTitle()); 339 infos.put("type", page.getType()); 340 341 String lang = page.getSitemapName(); 342 infos.put("lang", lang); 343 Language language = _webLanguagesManager.getAvailableLanguages().get(lang); 344 if (language != null) 345 { 346 infos.put("langIcon", language.getSmallIcon()); 347 infos.put("langLabel", language.getLabel()); 348 } 349 350 PageType type = page.getType(); 351 switch (type) 352 { 353 case CONTAINER: 354 infos.put("template", page.getTemplate()); 355 break; 356 357 case LINK: 358 infos.put("url", page.getURL()); 359 LinkType urlType = page.getURLType(); 360 infos.put("urlType", urlType.toString()); 361 break; 362 default: 363 break; 364 } 365 366 Map<String, Object> contextParameters = new HashMap<>(); 367 contextParameters.put("siteName", page.getSiteName()); 368 369 // Tags 370 List<I18nizableText> tags = new ArrayList<>(); 371 for (String tagName : page.getTags()) 372 { 373 Tag tag = _tagProvider.getTag(tagName, contextParameters); 374 tags.add(tag.getTitle()); 375 } 376 infos.put("tags", tags); 377 378 // Incoming references 379 List<Map<String, Object>> incomingContents = new ArrayList<>(); 380 AmetysObjectIterable<Content> contents = _getIncomingContentReferences (page.getId()); 381 for (Content content : contents) 382 { 383 incomingContents.add(_content2Json(content, new Locale(page.getSitemapName()))); 384 } 385 infos.put("inComingContents", incomingContents); 386 387 List<Map<String, Object>> incomingPages = new ArrayList<>(); 388 AmetysObjectIterable<Page> pages = _getIncomingPageReferences (page.getId()); 389 for (Page pageRef : pages) 390 { 391 incomingPages.add(_page2Json(pageRef)); 392 } 393 infos.put("inComingPages", incomingPages); 394 395 // Publication information 396 infos.put("publication", _publication2Json(page)); 397 398 return infos; 399 } 400 401 /** 402 * Check current user right on given page or sitemap 403 * @param id The id of the page or sitemap 404 * @param rightId The if of right to check 405 * @return true if user has right 406 */ 407 @Callable 408 public boolean hasRight(String id, String rightId) 409 { 410 UserIdentity user = _currentUserProvider.getUser(); 411 PagesContainer page = _resolver.resolveById(id); 412 413 return _rightManager.hasRight(user, rightId, page) == RightResult.RIGHT_ALLOW; 414 } 415 416 /** 417 * Create a new page 418 * @param parentId The parent id. Can not be null. 419 * @param title The page's title. Can not be null. 420 * @param longTitle The page's long title. Can be null or blank. 421 * @return The result map with id of created page 422 */ 423 @Callable 424 public Map<String, Object> createPage (String parentId, String title, String longTitle) 425 { 426 Map<String, Object> result = new HashMap<>(); 427 428 PagesContainer parent = _resolver.resolveById(parentId); 429 430 assert parent instanceof ModifiableTraversableAmetysObject; 431 432 Site site = parent.getSite(); 433 String originalPageName = ""; 434 try 435 { 436 originalPageName = FilterNameHelper.filterName(title); 437 } 438 catch (IllegalArgumentException e) 439 { 440 result.put("invalid-name", title); 441 return result; 442 } 443 444 String pageName = originalPageName; 445 int index = 2; 446 while (parent.hasChild(pageName)) 447 { 448 pageName = originalPageName + "-" + (index++); 449 } 450 451 ModifiablePage page = ((ModifiableTraversableAmetysObject) parent).createChild(pageName, "ametys:defaultPage"); 452 453 // Check rights 454 if (!_canCreate(parent)) 455 { 456 throw new IllegalStateException("You do not have the rights to create a page under '/" + parent.getSitemapName() + "/" + parent.getPathInSitemap() + "'"); 457 } 458 459 page.setTitle(title); 460 page.setType(PageType.NODE); 461 page.setSiteName(site.getName()); 462 page.setSitemapName(page.getSitemap().getName()); 463 464 if (!StringUtils.isBlank(longTitle)) 465 { 466 page.setLongTitle(longTitle); 467 } 468 469 site.saveChanges(); 470 471 Map<String, Object> eventParams = new HashMap<>(); 472 eventParams.put(ObservationConstants.ARGS_PAGE, page); 473 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_ADDED, _currentUserProvider.getUser(), eventParams)); 474 475 result.put("id", page.getId()); 476 result.put("parentId", parent.getId()); 477 result.put("lang", page.getSitemapName()); 478 result.put("title", page.getTitle()); 479 480 return result; 481 } 482 483 /** 484 * Copy a page 485 * @param id The id of page to copy 486 * @param target The id of parent target page 487 * @param keepReferences true to keep references 488 * @return the result map 489 * @throws RepositoryException if an error occurred during copy 490 */ 491 @Callable 492 public Map<String, String> copyPage (String id, String target, boolean keepReferences) throws RepositoryException 493 { 494 Map<String, String> result = new HashMap<>(); 495 496 Page page = _resolver.resolveById(id); 497 498 if (!(page instanceof CopiableAmetysObject)) 499 { 500 throw new IllegalArgumentException("The page '" + page.getId() + "' is not a copiable ametys object, it can not be copied"); 501 } 502 503 if (!(page instanceof JCRAmetysObject)) 504 { 505 throw new IllegalArgumentException("The page '" + page.getId() + "' is not a JCR ametys object, it can not be copied"); 506 } 507 508 PagesContainer parent = _resolver.resolveById(target); 509 510 // Check rights 511 if (!_canCreate(parent)) 512 { 513 throw new IllegalStateException("You do not have the rights to create a page under '/" + parent.getSitemapName() + "/" + parent.getPathInSitemap() + "'"); 514 } 515 516 if (parent instanceof ModifiableTraversableAmetysObject) 517 { 518 Page cPage = null; 519 if (!keepReferences) 520 { 521 // Restrict the copy to the page and its current children to avoid infinitive loop 522 List<String> pagesToCopy = new ArrayList<>(); 523 pagesToCopy.add(page.getId()); 524 pagesToCopy.addAll(_getChildrenPageIds(page)); 525 526 // Copy and duplicate contents 527 cPage = (Page) ((CopiableAmetysObject) page).copyTo((ModifiableTraversableAmetysObject) parent, null, pagesToCopy); 528 _copySiteComponent.updateReferencesAfterCopy(page, cPage); 529 530 // Creates the first version on all copied contents 531 _updateContentsAfterCopy (cPage); 532 } 533 else 534 { 535 // Copy without duplicating contents (keep references) 536 537 if (!page.getSitemapName().equals(parent.getSitemapName())) 538 { 539 throw new IllegalArgumentException("The page '" + page.getId() + "' from sitemap '" + page.getSitemapName() + "' cannot be copied to a different sitemap '" + parent.getSitemapName() + "' while keeping references to contents"); 540 } 541 542 String pageName = page.getName(); 543 int index = 2; 544 while (parent.hasChild(pageName)) 545 { 546 pageName = page.getName() + "-" + (index++); 547 } 548 549 String pagePath = ((SimpleAmetysObject) parent).getNode().getPath() + "/" + pageName; 550 Node node = ((JCRAmetysObject) page).getNode(); 551 node.getSession().getWorkspace().copy(node.getPath(), pagePath); 552 553 cPage = parent.getChild(pageName); 554 } 555 556 ((ModifiableTraversableAmetysObject) parent).saveChanges(); 557 result.put("id", cPage.getId()); 558 559 Map<String, Object> eventParams = new HashMap<>(); 560 eventParams.put(ObservationConstants.ARGS_PAGE, cPage); 561 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_ADDED, _currentUserProvider.getUser(), eventParams)); 562 } 563 564 return result; 565 } 566 567 /** 568 * Copy a page under another page 569 * @param targetId the page to copy in 570 * @param sourceId the page to copy 571 * @param keepReferences true to keep references for contents, or false to duplicate contents 572 * @return The id of created page is a result map. 573 * @throws RepositoryException if an error occurs 574 */ 575 @Callable 576 @Deprecated 577 public Map<String, String> pastePage(String targetId, String sourceId, boolean keepReferences) throws RepositoryException 578 { 579 return copyPage(sourceId, targetId, keepReferences); 580 } 581 582 /** 583 * Move a page 584 * @param id The page id 585 * @param parentId The id of parent destination 586 * @param index The position in parent child nodes where page will be inserted. -1 means as the last child. 587 * @return the result map 588 */ 589 @Callable 590 public Map<String, Object> movePage (String id, String parentId, int index) 591 { 592 Map<String, Object> result = new HashMap<>(); 593 594 String oldPathInSitemap = null; 595 String newPathInSitemap = null; 596 597 Page page = _resolver.resolveById(id); 598 PagesContainer srcParent = page.getParent(); 599 oldPathInSitemap = page.getPathInSitemap(); 600 Sitemap sitemap = page.getSitemap(); 601 602 // check rights of deletion on old parent page 603 if (!srcParent.getId().equals(parentId) && !_canDelete(page)) 604 { 605 throw new IllegalStateException("You do not have the rights to delete the page '/" + page.getSitemapName() + "/" + oldPathInSitemap + "'"); 606 } 607 608 if (!(page instanceof MoveablePage)) 609 { 610 throw new IllegalArgumentException("The page '/" + page.getSitemapName() + "/" + oldPathInSitemap + "' is not a moveable page"); 611 } 612 613 if (srcParent.getId().equals(parentId) && index != -1) 614 { 615 try 616 { 617 Page brother = srcParent.getChildPageAt(index); 618 ((MoveablePage) page).orderBefore(brother); 619 } 620 catch (UnknownAmetysObjectException e) 621 { 622 // Move the last child position 623 ((MoveablePage) page).orderBefore(null); 624 } 625 626 // Path is not modified 627 newPathInSitemap = oldPathInSitemap; 628 } 629 else 630 { 631 PagesContainer newParentPage = _resolver.resolveById(parentId); 632 633 // check right on creation on new parent page 634 if (!_canCreate(newParentPage)) 635 { 636 throw new IllegalStateException("You do not have the rights to create a page under '/" + newParentPage.getSitemapName() + "/" + newParentPage.getPathInSitemap() + "'"); 637 } 638 639 ((MoveablePage) page).moveTo(newParentPage, true); 640 if (index != -1) 641 { 642 Page brother = newParentPage.getChildPageAt(index); 643 644 ((MoveablePage) page).orderBefore(brother); 645 } 646 647 // Path is modified 648 newPathInSitemap = page.getPathInSitemap(); 649 } 650 651 if (sitemap.needsSave()) 652 { 653 sitemap.saveChanges(); 654 } 655 656 // Notify observers that the page has been moved 657 Map<String, Object> eventParams = new HashMap<>(); 658 eventParams.put(ObservationConstants.ARGS_SITEMAP, sitemap); 659 eventParams.put(ObservationConstants.ARGS_PAGE, page); 660 eventParams.put("page.old.path", oldPathInSitemap); 661 eventParams.put("page.old.parent", srcParent); 662 eventParams.put(ObservationConstants.ARGS_PAGE_PATH, newPathInSitemap); 663 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_MOVED, _currentUserProvider.getUser(), eventParams)); 664 665 result.put("id", page.getId()); 666 result.put("parentId", page.getParent().getId()); 667 668 return result; 669 } 670 671 private boolean _canCreate(PagesContainer parentPage) 672 { 673 UserIdentity user = _currentUserProvider.getUser(); 674 if (_rightManager.hasRight(user, "Web_Rights_Page_Create", parentPage) == RightResult.RIGHT_ALLOW) 675 { 676 return true; 677 } 678 679 if (getLogger().isInfoEnabled()) 680 { 681 getLogger().info("The user '" + user + "' tried to create page under '/" + parentPage.getSitemapName() + "/" + parentPage.getPathInSitemap() + "' without sufficient rights"); 682 } 683 684 return false; 685 } 686 687 private boolean _canDelete(Page page) 688 { 689 UserIdentity user = _currentUserProvider.getUser(); 690 PagesContainer parent = page.getParent(); 691 if (_rightManager.hasRight(user, "Web_Rights_Page_Delete", parent) == RightResult.RIGHT_ALLOW) 692 { 693 return true; 694 } 695 696 if (getLogger().isInfoEnabled()) 697 { 698 getLogger().info("The user '" + user + "' tried to move page '/" + page.getSitemapName() + "/" + page.getPathInSitemap() + "' without sufficient rights"); 699 } 700 701 return false; 702 } 703 704 /** 705 * Set pages as redirection 706 * @param pageIds the id of pages to modify 707 * @param url the url of redirection 708 * @param urlType the type of redirection 709 * @return the id of pages which succeeded or failed. 710 */ 711 @Callable 712 public Map<String, Object> setLink (List<String> pageIds, String url, String urlType) 713 { 714 Map<String, Object> result = new HashMap<>(); 715 716 if (StringUtils.isEmpty(url)) 717 { 718 throw new IllegalArgumentException("Can not set page as a redirection with an empty url"); 719 } 720 721 List<String> successes = new ArrayList<>(); 722 List<Map<String, Object>> failures = new ArrayList<>(); 723 724 for (String pageId : pageIds) 725 { 726 try 727 { 728 Page page = _resolver.resolveById(pageId); 729 if (!(page instanceof ModifiablePage)) 730 { 731 throw new IllegalArgumentException("Can not set page as a redirection on a non-modifiable page " + pageId); 732 } 733 734 ModifiablePage mPage = (ModifiablePage) page; 735 736 if (page.getType().equals(PageType.CONTAINER)) 737 { 738 // Remove zones 739 for (ModifiableZone zone : mPage.getZones()) 740 { 741 zone.remove(); 742 } 743 } 744 745 if (pageId.equals(url)) 746 { 747 throw new IllegalArgumentException("A page can not redirect to itself"); 748 } 749 750 mPage.setType(PageType.LINK); 751 mPage.setURL(LinkType.valueOf(urlType), url); 752 mPage.getSitemap().saveChanges(); 753 754 successes.add(pageId); 755 756 Map<String, Object> eventParams = new HashMap<>(); 757 eventParams.put(ObservationConstants.ARGS_PAGE, page); 758 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_CHANGED, _currentUserProvider.getUser(), eventParams)); 759 } 760 catch (Exception e) 761 { 762 getLogger().error("Cannot set the page '" + pageId + "' as link [" + url + ", " + urlType.toString() + "]", e); 763 764 Map<String, Object> failure = new HashMap<>(); 765 failure.put("id", pageId); 766 failure.put("error", e.toString()); 767 failures.add(failure); 768 } 769 } 770 771 result.put("success", successes); 772 result.put("failure", failures); 773 774 return result; 775 } 776 777 /** 778 * Get available template for specified page 779 * @param pageId The page's id 780 * @return the list of available template 781 */ 782 @Callable 783 public List<Map<String, Object>> getAvailableTemplates (String pageId) 784 { 785 List<Map<String, Object>> templates = new ArrayList<>(); 786 787 Page page = _resolver.resolveById(pageId); 788 789 Set<String> availableTemplateIds = _templatesHandler.getAvailablesTemplates(page); 790 for (String templateName : availableTemplateIds) 791 { 792 String skinId = page.getSite().getSkinId(); 793 Skin skin = _skinsManager.getSkin(skinId); 794 795 SkinTemplate template = skin.getTemplate(templateName); 796 797 Map<String, Object> template2json = new HashMap<>(); 798 template2json.put("id", template.getId()); 799 template2json.put("label", template.getLabel()); 800 template2json.put("description", template.getDescription()); 801 template2json.put("iconSmall", template.getSmallImage()); 802 template2json.put("iconMedium", template.getMediumImage()); 803 template2json.put("iconLarge", template.getLargeImage()); 804 template2json.put("zone", template.getDefaultZoneId()); 805 806 templates.add(template2json); 807 } 808 809 return templates; 810 } 811 812 /** 813 * Get available content types for specified page 814 * @param pageId The page's id 815 * @param zoneName the name of the zone 816 * @return the list of available content types 817 */ 818 @Callable 819 public List<Map<String, Object>> getAvailableContentTypes (String pageId, String zoneName) 820 { 821 List<Map<String, Object>> contenttypes = new ArrayList<>(); 822 823 Page page = _resolver.resolveById(pageId); 824 825 Set<String> contentTypeIds = _cTypeHandler.getAvailableContentTypes(page, zoneName); 826 for (String contentTypeId : contentTypeIds) 827 { 828 ContentType cType = _contentTypeExtensionPoint.getExtension(contentTypeId); 829 830 if (cType != null && _hasRight(cType, page)) 831 { 832 Map<String, Object> ctype2json = new HashMap<>(); 833 ctype2json.put("id", cType.getId()); 834 ctype2json.put("label", cType.getLabel()); 835 ctype2json.put("description", cType.getDescription()); 836 ctype2json.put("iconGlyph", cType.getIconGlyph()); 837 ctype2json.put("iconDecorator", cType.getIconDecorator()); 838 ctype2json.put("iconSmall", cType.getSmallIcon()); 839 ctype2json.put("iconMedium", cType.getMediumIcon()); 840 ctype2json.put("iconLarge", cType.getLargeIcon()); 841 ctype2json.put("defaultTitle", cType.getDefaultTitle()); 842 843 contenttypes.add(ctype2json); 844 } 845 } 846 847 return contenttypes; 848 } 849 850 /** 851 * Get available content types for a page being created 852 * @param pageId The page's id. Can be null of the page is not yet created 853 * @param zoneName the name of the zone 854 * @param parentId The id of parent page 855 * @param pageTitle The title of page to create 856 * @param template The template of page to create 857 * @return the list of available services 858 */ 859 @Callable 860 public List<Map<String, Object>> getAvailableContentTypesForCreation(String pageId, String zoneName, String parentId, String pageTitle, String template) 861 { 862 if (StringUtils.isNotEmpty(pageId)) 863 { 864 // Get available services for a page 865 return getAvailableContentTypes(pageId, zoneName); 866 } 867 else if (StringUtils.isNotEmpty(parentId)) 868 { 869 // Get available services for a not yet existing page 870 PagesContainer parent = _resolver.resolveById(parentId); 871 872 // Create page temporarily 873 Page page = _createPage(parent, pageTitle, template); 874 875 List<Map<String, Object>> availableServices = getAvailableContentTypes(page.getId(), zoneName); 876 877 // Cancel page creation 878 page.getSitemap().revertChanges(); 879 880 return availableServices; 881 } 882 883 return Collections.EMPTY_LIST; 884 } 885 886 private boolean _hasRight(ContentType contentType, Page page) 887 { 888 String right = contentType.getRight(); 889 890 if (right == null) 891 { 892 return true; 893 } 894 else 895 { 896 UserIdentity user = _currentUserProvider.getUser(); 897 return _rightManager.hasRight(user, right, page) == RightResult.RIGHT_ALLOW; 898 } 899 } 900 901 /** 902 * Get available services for specified page 903 * @param pageId The page's id 904 * @param zoneName the name of the zone 905 * @return the list of available services 906 */ 907 @Callable 908 public List<Map<String, Object>> getAvailableServices (String pageId, String zoneName) 909 { 910 List<Map<String, Object>> services = new ArrayList<>(); 911 912 Page page = _resolver.resolveById(pageId); 913 914 Set<String> serviceIds = _serviceHandler.getAvailableServices(page, zoneName); 915 for (String serviceId : serviceIds) 916 { 917 Service service = _serviceExtensionPoint.getExtension(serviceId); 918 if (service != null && _hasRight(service, page)) 919 { 920 Map<String, Object> serviceMap = new HashMap<>(); 921 serviceMap.put("id", service.getId()); 922 serviceMap.put("label", service.getLabel()); 923 serviceMap.put("description", service.getDescription()); 924 serviceMap.put("iconGlyph", service.getIconGlyph()); 925 serviceMap.put("iconDecorator", service.getIconDecorator()); 926 serviceMap.put("iconSmall", service.getSmallIcon()); 927 serviceMap.put("iconMedium", service.getMediumIcon()); 928 serviceMap.put("iconLarge", service.getLargeIcon()); 929 serviceMap.put("parametersAction", service.getParametersScript().getScriptClassname()); 930 931 services.add(serviceMap); 932 } 933 } 934 935 return services; 936 } 937 938 /** 939 * Get available services for a page being created 940 * @param pageId The page's id. Can be null of the page is not yet created 941 * @param zoneName the name of the zone 942 * @param parentId The id of parent page 943 * @param pageTitle The title of page to create 944 * @param template The template of page to create 945 * @return the list of available services 946 */ 947 @Callable 948 public List<Map<String, Object>> getAvailableServicesForCreation(String pageId, String zoneName, String parentId, String pageTitle, String template) 949 { 950 if (StringUtils.isNotEmpty(pageId)) 951 { 952 // Get available services for a page 953 return getAvailableServices(pageId, zoneName); 954 } 955 else if (StringUtils.isNotEmpty(parentId)) 956 { 957 // Get available services for a not yet existing page 958 PagesContainer parent = _resolver.resolveById(parentId); 959 960 // Create page temporarily 961 Page page = _createPage(parent, pageTitle, template); 962 963 List<Map<String, Object>> availableServices = getAvailableServices(page.getId(), zoneName); 964 965 // Cancel page creation 966 page.getSitemap().revertChanges(); 967 968 return availableServices; 969 } 970 971 return Collections.EMPTY_LIST; 972 } 973 974 private Page _createPage (PagesContainer parent, String pageTitle, String template) 975 { 976 Site site = parent.getSite(); 977 String originalPageName = FilterNameHelper.filterName(pageTitle); 978 979 String pageName = originalPageName; 980 int index = 2; 981 while (parent.hasChild(pageName)) 982 { 983 pageName = originalPageName + "-" + index++; 984 } 985 986 ModifiablePage page = ((ModifiableTraversableAmetysObject) parent).createChild(pageName, "ametys:defaultPage"); 987 988 page.setTitle(pageTitle); 989 page.setType(PageType.NODE); 990 page.setSiteName(site.getName()); 991 page.setSitemapName(page.getSitemap().getName()); 992 993 if (template != null) 994 { 995 String skinId = page.getSite().getSkinId(); 996 SkinTemplate tpl = _skinsManager.getSkin(skinId).getTemplate(template); 997 if (tpl == null) 998 { 999 throw new IllegalStateException("Template '" + template + "' does not exist on skin '" + skinId + "'"); 1000 } 1001 1002 // Set temporary the template to get available services 1003 page.setType(PageType.CONTAINER); 1004 page.setTemplate(template); 1005 } 1006 1007 return page; 1008 } 1009 1010 private boolean _hasRight(Service service, Page page) 1011 { 1012 String right = service.getRight(); 1013 1014 if (right == null) 1015 { 1016 return true; 1017 } 1018 else 1019 { 1020 UserIdentity user = _currentUserProvider.getUser(); 1021 return _rightManager.hasRight(user, right, page) == RightResult.RIGHT_ALLOW; 1022 } 1023 } 1024 1025 /** 1026 * Get available template for specified pages 1027 * @param pageIds The id of pages 1028 * @return the list of available template 1029 */ 1030 @Callable 1031 public List<Map<String, Object>> getAvailableTemplates (List<String> pageIds) 1032 { 1033 List<String> templateIds = new ArrayList<>(); 1034 1035 List<Map<String, Object>> templates = new ArrayList<>(); 1036 1037 for (String pageId : pageIds) 1038 { 1039 List<Map<String, Object>> pageTemplates = getAvailableTemplates(pageId); 1040 1041 for (Map<String, Object> template : pageTemplates) 1042 { 1043 String templateName = (String) template.get("id"); 1044 1045 if (!templateIds.contains(templateName)) 1046 { 1047 templateIds.add(templateName); 1048 templates.add(template); 1049 } 1050 } 1051 } 1052 1053 return templates; 1054 } 1055 1056 /** 1057 * Get available content types for a page being created 1058 * @param pageId The page's id. Can be null of the page is not yet created 1059 * @param parentId The id of parent page 1060 * @param pageTitle The title of page to create 1061 * @return the list of available services 1062 */ 1063 @Callable 1064 public List<Map<String, Object>> getAvailableTemplatesForCreation (String pageId, String parentId, String pageTitle) 1065 { 1066 if (StringUtils.isNotEmpty(pageId)) 1067 { 1068 // Get available template for a page 1069 return getAvailableTemplates(pageId); 1070 } 1071 else if (StringUtils.isNotEmpty(parentId)) 1072 { 1073 // Get available template for a not yet existing page 1074 PagesContainer parent = _resolver.resolveById(parentId); 1075 1076 // Create page temporarily 1077 Page page = _createPage(parent, pageTitle, null); 1078 1079 List<Map<String, Object>> availableTemplates = getAvailableTemplates(page.getId()); 1080 1081 // Cancel page creation 1082 page.getSitemap().revertChanges(); 1083 1084 return availableTemplates; 1085 } 1086 1087 return Collections.EMPTY_LIST; 1088 } 1089 1090 /** 1091 * Get service info 1092 * @param pageId Optional, the page id of the service. To get some basic info about the page. 1093 * @param serviceId The id of the service 1094 * @return a Map containing some info about the service (label, url..) 1095 */ 1096 @Callable 1097 public Map<String, Object> getServiceInfo(String pageId, String serviceId) 1098 { 1099 Map<String, Object> info = new HashMap<>(); 1100 1101 if (StringUtils.isNotEmpty(pageId)) 1102 { 1103 Page page = _resolver.resolveById(pageId); 1104 info.put("page-id", page.getId()); 1105 info.put("page-title", page.getTitle()); 1106 } 1107 1108 Service service = _serviceExtensionPoint.getExtension(serviceId); 1109 info.put("id", service.getId()); 1110 info.put("label", service.getLabel()); 1111 info.put("url", service.getURL()); 1112 info.put("smallIcon", service.getSmallIcon()); 1113 info.put("iconGlyph", service.getIconGlyph()); 1114 info.put("iconDecorator", service.getIconDecorator()); 1115 return info; 1116 } 1117 1118 /** 1119 * Rename a page 1120 * @param pageId The id of page to rename 1121 * @param title The page's title 1122 * @param longTitle The page's long title. 1123 * @param updatePath true to update page's path 1124 * @param createAlias true to create a alias 1125 * @return the result map 1126 */ 1127 @Callable (right = "Web_Rights_Page_Rename", rightContext = PageRightAssignmentContext.ID, paramIndex = 0) 1128 public Map<String, Object> renamePage (String pageId, String title, String longTitle, boolean updatePath, boolean createAlias) 1129 { 1130 Map<String, Object> result = new HashMap<>(); 1131 1132 Page page = _resolver.resolveById(pageId); 1133 1134 if (!(page instanceof ModifiablePage)) 1135 { 1136 throw new IllegalArgumentException("Can not rename a non-modifiable page '/" + page.getSitemapName() + "/" + page.getPathInSitemap() + "'"); 1137 } 1138 1139 ModifiablePage mPage = (ModifiablePage) page; 1140 mPage.setTitle(title); 1141 mPage.setLongTitle(longTitle); 1142 1143 if (updatePath) 1144 { 1145 String oldPathInSitemap = page.getPathInSitemap(); 1146 String oldPath = "/" + page.getSitemapName() + "/" + page.getPathInSitemap() + ".html"; 1147 String oldPathForChild = "/" + page.getSitemapName() + "/" + page.getPathInSitemap() + "/**.html"; 1148 1149 String pageName = ""; 1150 try 1151 { 1152 pageName = FilterNameHelper.filterName(title); 1153 } 1154 catch (IllegalArgumentException e) 1155 { 1156 result.put("invalid-name", title); 1157 return result; 1158 } 1159 1160 if (!page.getName().equals(pageName)) 1161 { 1162 int index = 1; 1163 String initialPageName = pageName; 1164 PagesContainer parent = page.getParent(); 1165 while (parent.hasChild(pageName)) 1166 { 1167 pageName = initialPageName + "-" + (index++); 1168 } 1169 1170 mPage.rename(pageName); 1171 1172 if (createAlias) 1173 { 1174 ModifiableTraversableAmetysObject rootNode = AliasHelper.getRootNode(page.getSite()); 1175 1176 DefaultAlias alias = rootNode.createChild(AliasHelper.getAliasNextUniqueName(rootNode), "ametys:alias"); 1177 alias.setUrl(oldPath); 1178 alias.setTarget(page.getId()); 1179 alias.setType(TargetType.PAGE); 1180 alias.setCreationDate(new Date()); 1181 1182 // Alias for child pages 1183 alias = rootNode.createChild(AliasHelper.getAliasNextUniqueName(rootNode), "ametys:alias"); 1184 alias.setUrl(oldPathForChild); 1185 alias.setTarget("/" + page.getSitemapName() + "/" + page.getPathInSitemap() + "/{1}.html"); 1186 alias.setType(TargetType.URL); 1187 alias.setCreationDate(new Date()); 1188 1189 rootNode.saveChanges(); 1190 } 1191 1192 // Notify observers that the page has been renamed 1193 Map<String, Object> eventParams = new HashMap<>(); 1194 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1195 eventParams.put("path.old.path", oldPathInSitemap); 1196 eventParams.put(ObservationConstants.ARGS_PAGE_PATH, page.getPathInSitemap()); 1197 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_RENAMED, _currentUserProvider.getUser(), eventParams)); 1198 1199 } 1200 else 1201 { 1202 // Notify observers that the page's title has been modified 1203 Map<String, Object> eventParams = new HashMap<>(); 1204 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1205 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams)); 1206 } 1207 1208 } 1209 else 1210 { 1211 // Notify observers that the page's title has been modified 1212 Map<String, Object> eventParams = new HashMap<>(); 1213 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1214 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams)); 1215 } 1216 1217 Sitemap sitemap = page.getSitemap(); 1218 if (sitemap.needsSave()) 1219 { 1220 sitemap.saveChanges(); 1221 } 1222 1223 result.put("id", page.getId()); 1224 result.put("path", page.getPath()); 1225 result.put("title", page.getTitle()); 1226 1227 return result; 1228 } 1229 1230 /** 1231 * Delete a page and its sub-pages. 1232 * The contents that belong only to the deleted page will be deleted if 'deleteBelongingContents' is set to true. 1233 * The newly created contents are deleted whatever the value if 'deleteBelongingContents'. 1234 * @param pageId the id of page to delete 1235 * @param deleteBelongingContents true to delete the contents that belong to the page and its sub-pages only 1236 * @return The id of deleted pages 1237 */ 1238 @Callable 1239 public Map<String, Object> deletePage(String pageId, boolean deleteBelongingContents) 1240 { 1241 ModifiablePage page = _resolver.resolveById(pageId); 1242 1243 // Check rights on parent 1244 if (!_canDelete(page)) 1245 { 1246 throw new IllegalStateException("You do not have the rights to delete the page '/" + page.getSitemapName() + "/" + page.getPathInSitemap() + "'"); 1247 } 1248 1249 return deletePage(page, deleteBelongingContents); 1250 } 1251 1252 /** 1253 * Delete a page and its sub-pages. 1254 * The contents that belong only to the deleted page will be deleted if 'deleteBelongingContents' is set to true. 1255 * The newly created contents are deleted whatever the value if 'deleteBelongingContents'. 1256 * @param page the page to delete 1257 * @param deleteBelongingContents true to delete the contents that belong to the page and its sub-pages only 1258 * @return The id of deleted pages 1259 */ 1260 public Map<String, Object> deletePage(ModifiablePage page, boolean deleteBelongingContents) 1261 { 1262 Map<String, Object> result = new HashMap<>(); 1263 1264 List<String> contentToDelete = getDeleteablePageContentIds(page.getId(), !deleteBelongingContents); 1265 1266 Sitemap sitemap = page.getSitemap(); 1267 PagesContainer parent = page.getParent(); 1268 String pagePathInSitemap = page.getPathInSitemap(); 1269 1270 List<String> childPagesIds = _getChildrenPageIds(page); 1271 1272 Map<String, Object> eventParams = new HashMap<>(); 1273 eventParams.put(ObservationConstants.ARGS_PAGE_ID, page.getId()); 1274 eventParams.put(ObservationConstants.ARGS_PAGE_PARENT, parent); 1275 eventParams.put(ObservationConstants.ARGS_PAGE_PATH, pagePathInSitemap); 1276 eventParams.put(ObservationConstants.ARGS_SITEMAP, sitemap); 1277 eventParams.put(ObservationConstants.ARGS_PAGE_CONTENTS, getPageContents(page)); 1278 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_DELETING, _currentUserProvider.getUser(), eventParams)); 1279 1280 // FIXME API test if this is not modifiable 1281 page.getParent(); 1282 page.remove(); 1283 ((ModifiableAmetysObject) parent).saveChanges(); 1284 1285 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_DELETED, _currentUserProvider.getUser(), eventParams)); 1286 1287 result.put("id", page.getId()); 1288 result.put("childPages", childPagesIds); 1289 1290 result.putAll(_contentDAO.deleteContents(contentToDelete, true)); 1291 return result; 1292 } 1293 1294 /** 1295 * Set pages as blank page 1296 * @param pageIds the id of pages to modify 1297 * @return the id of pages which succeeded or failed. 1298 */ 1299 @Callable 1300 public Map<String, Object> setBlank (List<String> pageIds) 1301 { 1302 Map<String, Object> result = new HashMap<>(); 1303 1304 List<String> successes = new ArrayList<>(); 1305 List<Map<String, Object>> failures = new ArrayList<>(); 1306 1307 for (String pageId : pageIds) 1308 { 1309 try 1310 { 1311 Page page = _resolver.resolveById(pageId); 1312 if (!(page instanceof ModifiablePage)) 1313 { 1314 throw new IllegalArgumentException("Can not set page as blank a non-modifiable page " + pageId); 1315 } 1316 1317 ModifiablePage mPage = (ModifiablePage) page; 1318 1319 if (page.getType().equals(PageType.CONTAINER)) 1320 { 1321 // Remove zones 1322 for (ModifiableZone zone : mPage.getZones()) 1323 { 1324 zone.remove(); 1325 } 1326 } 1327 1328 mPage.setType(PageType.NODE); 1329 mPage.getSitemap().saveChanges(); 1330 1331 successes.add(pageId); 1332 1333 Map<String, Object> eventParams = new HashMap<>(); 1334 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1335 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_CHANGED, _currentUserProvider.getUser(), eventParams)); 1336 } 1337 catch (Exception e) 1338 { 1339 getLogger().error("Cannot set the page '" + pageId + "' as blank page", e); 1340 1341 Map<String, Object> failure = new HashMap<>(); 1342 failure.put("id", pageId); 1343 failure.put("error", e.toString()); 1344 failures.add(failure); 1345 } 1346 } 1347 1348 result.put("success", successes); 1349 result.put("failure", failures); 1350 1351 return result; 1352 } 1353 1354 /** 1355 * Set a template to pages 1356 * @param pageIds the id of pages to update 1357 * @param templateName The template name 1358 * @return the id of pages which succeeded 1359 */ 1360 @Callable 1361 public Map<String, Object> setTemplate (List<String> pageIds, String templateName) 1362 { 1363 return setTemplate(pageIds, templateName, true); 1364 } 1365 1366 /** 1367 * Set a template to pages 1368 * @param pageIds the id of pages to update 1369 * @param templateName The template name 1370 * @param checkAvailableTemplate true if you want to check available template 1371 * @return the id of pages which succeeded 1372 */ 1373 public Map<String, Object> setTemplate (List<String> pageIds, String templateName, boolean checkAvailableTemplate) 1374 { 1375 Map<String, Object> result = new HashMap<>(); 1376 1377 List<String> successes = new ArrayList<>(); 1378 1379 String defaultZoneName = null; 1380 1381 for (String pageId : pageIds) 1382 { 1383 Page page = _resolver.resolveById(pageId); 1384 if (!(page instanceof ModifiablePage)) 1385 { 1386 throw new IllegalArgumentException("Can not set template a non-modifiable page " + pageId); 1387 } 1388 1389 ModifiablePage mPage = (ModifiablePage) page; 1390 1391 if (defaultZoneName == null) 1392 { 1393 String skinId = page.getSite().getSkinId(); 1394 SkinTemplate tpl = _skinsManager.getSkin(skinId).getTemplate(templateName); 1395 if (tpl == null) 1396 { 1397 throw new IllegalStateException("Template '" + templateName + "' does not exist on skin '" + skinId + "'"); 1398 } 1399 1400 defaultZoneName = tpl.getDefaultZoneId(); 1401 } 1402 1403 if (checkAvailableTemplate && !_templatesHandler.getAvailablesTemplates(mPage).contains(templateName)) 1404 { 1405 throw new IllegalStateException("Template '" + templateName + "' is not available for page '" + pageId + "'"); 1406 } 1407 1408 if (page.getType().equals(PageType.CONTAINER)) 1409 { 1410 _removeOldZones (mPage, templateName); 1411 } 1412 1413 mPage.setTemplate(templateName); 1414 mPage.setType(PageType.CONTAINER); 1415 mPage.getSitemap().saveChanges(); 1416 1417 successes.add(pageId); 1418 1419 Map<String, Object> eventParams = new HashMap<>(); 1420 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1421 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_CHANGED, _currentUserProvider.getUser(), eventParams)); 1422 } 1423 1424 if (defaultZoneName != null) 1425 { 1426 result.put("zonename", defaultZoneName); 1427 } 1428 1429 result.put("success", successes); 1430 1431 return result; 1432 } 1433 1434 /** 1435 * Get the script class name to execute to add or update this service 1436 * @param serviceId the service id 1437 * @return the script class name. Can be empty 1438 */ 1439 @Callable 1440 public String getServiceParametersAction (String serviceId) 1441 { 1442 try 1443 { 1444 Service service = _serviceExtensionPoint.getExtension(serviceId); 1445 return service.getParametersScript().getScriptClassname(); 1446 } 1447 catch (IllegalArgumentException e) 1448 { 1449 throw new IllegalArgumentException("Service with id '" + serviceId + "' does not exist", e); 1450 } 1451 } 1452 1453 private void _removeOldZones (ModifiablePage page, String templateName) 1454 { 1455 String skinId = page.getSite().getSkinId(); 1456 1457 SkinTemplate oldTemplate = _skinsManager.getSkin(skinId).getTemplate(templateName); 1458 1459 Map<String, SkinTemplateZone> templateZones = oldTemplate.getZones(); 1460 1461 for (ModifiableZone zone : page.getZones()) 1462 { 1463 if (!templateZones.containsKey(zone.getName())) 1464 { 1465 zone.remove(); 1466 } 1467 } 1468 } 1469 1470 /** 1471 * Get the tags from the pages 1472 * @param pageIds The ids of the pages 1473 * @return the tags of the pages 1474 */ 1475 @Callable 1476 public Set<String> getTags (List<String> pageIds) 1477 { 1478 Set<String> tags = new HashSet<>(); 1479 1480 for (String pageId : pageIds) 1481 { 1482 Page page = _resolver.resolveById(pageId); 1483 tags.addAll(page.getTags()); 1484 } 1485 1486 return tags; 1487 } 1488 1489 /** 1490 * Tag a list of pages 1491 * @param pageIds The ids of pages to tag 1492 * @param tagNames The tags 1493 * @param mode The mode for updating tags: 'REPLACE' to replace tags, 'INSERT' to add tags or 'REMOVE' to remove tags. 1494 * @param contextualParameters Contextual parameters. Must contain the site name 1495 * @return the result 1496 */ 1497 @Callable 1498 public Map<String, Object> tag (List<String> pageIds, List<String> tagNames, String mode, Map<String, Object> contextualParameters) 1499 { 1500 Map<String, Object> result = new HashMap<>(); 1501 1502 result.put("nomodifiable-pages", new ArrayList<Map<String, Object>>()); 1503 result.put("invalid-tags", new ArrayList<String>()); 1504 result.put("allright-pages", new ArrayList<Map<String, Object>>()); 1505 1506 for (String pageId : pageIds) 1507 { 1508 Page page = _resolver.resolveById(pageId); 1509 1510 Map<String, Object> page2json = new HashMap<>(); 1511 page2json.put("id", page.getId()); 1512 page2json.put("title", page.getTitle()); 1513 1514 if (page instanceof ModifiablePage) 1515 { 1516 ModifiablePage mPage = (ModifiablePage) page; 1517 1518 TagMode tagMode = TagMode.valueOf(mode); 1519 1520 Set<String> oldTags = mPage.getTags(); 1521 if (TagMode.REPLACE.equals(tagMode)) 1522 { 1523 // First delete old tags 1524 for (String tagName : oldTags) 1525 { 1526 mPage.untag(tagName); 1527 } 1528 } 1529 1530 1531 // Then set new tags 1532 for (String tagName : tagNames) 1533 { 1534 if (_isTagValid(page, tagName)) 1535 { 1536 if (TagMode.REMOVE.equals(tagMode)) 1537 { 1538 mPage.untag(tagName); 1539 } 1540 else if (TagMode.REPLACE.equals(tagMode) || !oldTags.contains(tagName)) 1541 { 1542 mPage.tag(tagName); 1543 } 1544 } 1545 else 1546 { 1547 @SuppressWarnings("unchecked") 1548 List<String> invalidTags = (List<String>) result.get("invalid-tags"); 1549 invalidTags.add(tagName); 1550 } 1551 } 1552 1553 mPage.saveChanges(); 1554 1555 page2json.put("tags", page.getTags()); 1556 @SuppressWarnings("unchecked") 1557 List<Map<String, Object>> allRightPages = (List<Map<String, Object>>) result.get("allright-pages"); 1558 allRightPages.add(page2json); 1559 1560 if (!oldTags.equals(page.getTags())) 1561 { 1562 // Notify observers that the content has been tagged 1563 Map<String, Object> eventParams = new HashMap<>(); 1564 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1565 eventParams.put("page.tags", page.getTags()); 1566 eventParams.put("page.old.tags", page); 1567 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams)); 1568 } 1569 } 1570 else 1571 { 1572 @SuppressWarnings("unchecked") 1573 List<Map<String, Object>> nomodifiablePages = (List<Map<String, Object>>) result.get("nomodifiable-pages"); 1574 nomodifiablePages.add(page2json); 1575 } 1576 } 1577 1578 return result; 1579 } 1580 1581 /** 1582 * Tag a list of contents with the given tags 1583 * @param pageIds The ids of pages to tag 1584 * @param contentIds The ids of contents to tag 1585 * @param tagNames The tags 1586 * @param contextualParameters The contextual parameters 1587 * @return the result map 1588 */ 1589 @Callable 1590 public Map<String, Object> tag (List<String> pageIds, List<String> contentIds, List<String> tagNames, Map<String, Object> contextualParameters) 1591 { 1592 return tag(pageIds, contentIds, tagNames, TagMode.REPLACE.toString(), contextualParameters); 1593 } 1594 1595 /** 1596 * Tag a list of contents and/org pages 1597 * @param pageIds The ids of pages to tag 1598 * @param contentIds The ids of contents to tag 1599 * @param tagNames The tags 1600 * @param mode The mode for updating tags: 'REPLACE' to replace tags, 'INSERT' to add tags or 'REMOVE' to remove tags. 1601 * @param contextualParameters The contextual parameters 1602 * @return the result 1603 */ 1604 @Callable 1605 public Map<String, Object> tag (List<String> pageIds, List<String> contentIds, List<String> tagNames, String mode, Map<String, Object> contextualParameters) 1606 { 1607 // Tag pages 1608 Map<String, Object> result = tag(pageIds, tagNames, mode, contextualParameters); 1609 1610 // Tag contents 1611 result.putAll(_contentDAO.tag(contentIds, tagNames, mode, contextualParameters)); 1612 1613 // Invalid tags are ignored 1614 result.remove("invalid-tags"); 1615 return result; 1616 } 1617 1618 /** 1619 * Test if a tag is valid for a specific page 1620 * @param page The page 1621 * @param tagName The tag name 1622 * @return True if the tag is valid 1623 */ 1624 public boolean _isTagValid (Page page, String tagName) 1625 { 1626 Map<String, Object> params = new HashMap<>(); 1627 params.put("siteName", page.getSiteName()); 1628 CMSTag tag = _tagProvider.getTag(tagName, params); 1629 1630 return tag.getTarget().getName().equals("PAGE"); 1631 } 1632 1633 /** 1634 * Set the visible of pages 1635 * @param pageIds The id of pages 1636 * @param visible <code>true</code> to set pages as visible, <code>false</code> otherwise 1637 * @return The result map 1638 */ 1639 @Callable 1640 public Map<String, Object> setVisibility (List<String> pageIds, boolean visible) 1641 { 1642 Map<String, Object> result = new HashMap<>(); 1643 1644 result.put("nomodifiable-pages", new ArrayList<Map<String, Object>>()); 1645 result.put("allright-pages", new ArrayList<Map<String, Object>>()); 1646 1647 for (String id : pageIds) 1648 { 1649 Page page = _resolver.resolveById(id); 1650 1651 Map<String, Object> page2json = new HashMap<>(); 1652 page2json.put("id", page.getId()); 1653 page2json.put("title", page.getTitle()); 1654 1655 if (page instanceof ModifiablePage) 1656 { 1657 ModifiablePage mPage = (ModifiablePage) page; 1658 mPage.setVisible(visible); 1659 mPage.saveChanges(); 1660 1661 Map<String, Object> eventParams = new HashMap<>(); 1662 eventParams.put(ObservationConstants.ARGS_PAGE, page); 1663 eventParams.put(ObservationConstants.ARGS_PAGE_ID, page.getId()); 1664 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams)); 1665 1666 @SuppressWarnings("unchecked") 1667 List<Map<String, Object>> allRightPages = (List<Map<String, Object>>) result.get("allright-pages"); 1668 allRightPages.add(page2json); 1669 } 1670 else 1671 { 1672 @SuppressWarnings("unchecked") 1673 List<Map<String, Object>> nomodifiablePages = (List<Map<String, Object>>) result.get("nomodifiable-pages"); 1674 nomodifiablePages.add(page2json); 1675 } 1676 } 1677 1678 return result; 1679 } 1680 1681 /** 1682 * Get the contents of a {@link Page} and its subpages which can be deleted. 1683 * A content is deleteable if user has right, the content is not locked and not referenced by other pages. 1684 * @param id The id of page 1685 * @return The list of deletable contents 1686 */ 1687 @Callable 1688 public Map<String, Object> getDeleteablePageContents (String id) 1689 { 1690 Map<String, Object> results = new HashMap<>(); 1691 1692 results.put("deleteable-contents", new ArrayList<Map<String, Object>>()); 1693 results.put("referenced-contents", new ArrayList<Map<String, Object>>()); 1694 results.put("unauthorized-contents", new ArrayList<Map<String, Object>>()); 1695 results.put("locked-contents", new ArrayList<Map<String, Object>>()); 1696 1697 Page page = _resolver.resolveById(id); 1698 List<Content> contents = getPageContents(page, true); 1699 1700 for (Content content : contents) 1701 { 1702 Map<String, Object> contentParams = new HashMap<>(); 1703 contentParams.put("id", content.getId()); 1704 contentParams.put("title", content.getTitle(new Locale(page.getSitemapName()))); 1705 contentParams.put("name", content.getName()); 1706 1707 if (_isReferenced(content)) 1708 { 1709 // Content is referenced by at least another page 1710 @SuppressWarnings("unchecked") 1711 List<Map<String, Object>> referencedContents = (List<Map<String, Object>>) results.get("referenced-contents"); 1712 referencedContents.add(contentParams); 1713 } 1714 else if (!_contentDAO.canDelete(content)) 1715 { 1716 @SuppressWarnings("unchecked") 1717 List<Map<String, Object>> unauthorizedContents = (List<Map<String, Object>>) results.get("unauthorized-contents"); 1718 unauthorizedContents.add(contentParams); 1719 } 1720 else if (_isLocked(content)) 1721 { 1722 // If the content is locked by other 1723 @SuppressWarnings("unchecked") 1724 List<Map<String, Object>> lockedContents = (List<Map<String, Object>>) results.get("locked-contents"); 1725 lockedContents.add(contentParams); 1726 } 1727 else 1728 { 1729 Map<String, Object> content2json = new HashMap<>(); 1730 content2json.put("id", content.getId()); 1731 content2json.put("name", content.getName()); 1732 content2json.put("title", content.getTitle(new Locale(page.getSitemapName()))); 1733 content2json.put("isNew", _isNew(content)); 1734 content2json.put("isShared", content instanceof SharedContent); 1735 content2json.put("hasShared", _sharedContentManager.hasSharedContents(content)); 1736 1737 @SuppressWarnings("unchecked") 1738 List<Map<String, Object>> allrightContents = (List<Map<String, Object>>) results.get("deleteable-contents"); 1739 allrightContents.add(content2json); 1740 } 1741 } 1742 1743 return results; 1744 } 1745 1746 /** 1747 * Get the contents that belong to the {@link Page} and its sub-pages and that can be deleted. 1748 * A content is deleteable if user has right, the content is not locked and it's not referenced by other pages. 1749 * If 'onlyNewlyCreatedContents' is set to 'true', only newly created contents will be returned 1750 * @param pageId The id of page 1751 * @param onlyNewlyCreatedContents true to return only the newly created contents 1752 * @return The ids of deleteable contents 1753 */ 1754 public List<String> getDeleteablePageContentIds (String pageId, boolean onlyNewlyCreatedContents) 1755 { 1756 List<String> contentsId = new ArrayList<>(); 1757 1758 Page page = _resolver.resolveById(pageId); 1759 1760 List<Content> contents = getPageContents(page, true); 1761 1762 for (Content content : contents) 1763 { 1764 if (_contentDAO.canDelete(content) && !_isLocked(content) && !_isReferenced(content)) 1765 { 1766 if (!onlyNewlyCreatedContents || _isNew(content)) 1767 { 1768 contentsId.add(content.getId()); 1769 } 1770 } 1771 } 1772 1773 return contentsId; 1774 } 1775 1776 /** 1777 * Get the unreferenced contents of a {@link Page} or a {@link ZoneItem} 1778 * @param id The id of page or zone item 1779 * @return The list of unreferenced contents 1780 */ 1781 @Callable 1782 public List<Map<String, Object>> getUnreferencedContents (String id) 1783 { 1784 List<Map<String, Object>> unreferencedContents = new ArrayList<>(); 1785 1786 Page page = _resolver.resolveById(id); 1787 List<Content> contents = getPageContents(page, true); 1788 1789 for (Content content : contents) 1790 { 1791 if (!_isReferenced(content)) 1792 { 1793 Map<String, Object> content2json = new HashMap<>(); 1794 content2json.put("id", content.getId()); 1795 content2json.put("name", content.getName()); 1796 content2json.put("title", content.getTitle(new Locale(page.getSitemapName()))); 1797 content2json.put("isNew", _isNew(content)); 1798 content2json.put("isShared", content instanceof SharedContent); 1799 content2json.put("hasShared", _sharedContentManager.hasSharedContents(content)); 1800 1801 unreferencedContents.add(content2json); 1802 } 1803 } 1804 1805 return unreferencedContents; 1806 } 1807 1808 /** 1809 * Returns the page's attachments root node 1810 * @param id the page's id 1811 * @return The attachments' root node informations 1812 */ 1813 @Callable 1814 public Map<String, Object> getAttachmentsRootNode (String id) 1815 { 1816 Map<String, Object> result = new HashMap<>(); 1817 1818 Page page = _resolver.resolveById(id); 1819 1820 result.put("title", page.getTitle()); 1821 result.put("contentId", page.getId()); 1822 1823 TraversableAmetysObject attachments = page.getRootAttachments(); 1824 1825 if (attachments != null) 1826 { 1827 result.put("id", attachments.getId()); 1828 if (attachments instanceof ModifiableAmetysObject) 1829 { 1830 result.put("isModifiable", true); 1831 } 1832 if (attachments instanceof ModifiableResourceCollection) 1833 { 1834 result.put("canCreateChild", true); 1835 } 1836 1837 boolean hasChildNodes = false; 1838 boolean hasResources = false; 1839 1840 for (AmetysObject child : attachments.getChildren()) 1841 { 1842 if (child instanceof Resource) 1843 { 1844 hasResources = true; 1845 } 1846 else if (child instanceof ExplorerNode) 1847 { 1848 hasChildNodes = true; 1849 } 1850 } 1851 1852 if (hasChildNodes) 1853 { 1854 result.put("hasChildNodes", true); 1855 } 1856 1857 if (hasResources) 1858 { 1859 result.put("hasResources", true); 1860 } 1861 1862 return result; 1863 } 1864 1865 throw new IllegalArgumentException("Page with id '" + id + "' does not support attachments."); 1866 } 1867 /** 1868 * Returns the page's parents ids 1869 * @param id the page's id 1870 * @return The attachments' root node informations 1871 */ 1872 @Callable 1873 public Map<String, Object> getPageParents (String id) 1874 { 1875 Map<String, Object> result = new HashMap<>(); 1876 List<Map<String, Object>> pages = new ArrayList<>(); 1877 Page page = _resolver.resolveById(id); 1878 pages.add(_page2Json(page)); 1879 while (page.getParent() != null && page.getParent() instanceof Page) 1880 { 1881 page = page.getParent(); 1882 pages.add(_page2Json(page)); 1883 } 1884 result.put("parents", pages); 1885 return result; 1886 } 1887 1888 /** 1889 * Get the contents of a page and its child pages 1890 * @param page The page 1891 * @return The list of contents 1892 */ 1893 public List<Content> getPageContents (Page page) 1894 { 1895 return getPageContents(page, false); 1896 } 1897 1898 /** 1899 * Get the contents of a page and its child pages 1900 * @param page The page 1901 * @param ignoreContentsOfNonRemovablePage true to ignore contents of non-removable pages (virtual pages) 1902 * @return The list of contents 1903 */ 1904 public List<Content> getPageContents (Page page, boolean ignoreContentsOfNonRemovablePage) 1905 { 1906 List<Content> contents = new ArrayList<>(); 1907 1908 if ((!ignoreContentsOfNonRemovablePage || page instanceof RemovableAmetysObject) && page.getType() == Page.PageType.CONTAINER) 1909 { 1910 for (Zone zone : page.getZones()) 1911 { 1912 for (ZoneItem zoneItem : zone.getZoneItems()) 1913 { 1914 if (zoneItem.getType() == ZoneItem.ZoneType.CONTENT) 1915 { 1916 contents.add(zoneItem.getContent()); 1917 } 1918 } 1919 } 1920 } 1921 1922 AmetysObjectIterable< ? extends Page> childrenPages = page.getChildrenPages(); 1923 for (Page childPage : childrenPages) 1924 { 1925 contents.addAll(getPageContents(childPage, ignoreContentsOfNonRemovablePage)); 1926 } 1927 1928 return contents; 1929 } 1930 1931 /** 1932 * Get the user rights on page container (page or sitemap) 1933 * @param pagesCt The pages container 1934 * @return The user's rights 1935 */ 1936 protected Set<String> getUserRights (PagesContainer pagesCt) 1937 { 1938 UserIdentity user = _currentUserProvider.getUser(); 1939 1940 Set<String> userRights = _rightManager.getUserRights(user, pagesCt); 1941 1942 // Do some specific stuff here, because the right 'Web_Rights_Page_Delete' is a right to delete child pages and not the page itself. 1943 // So the right should be checked on parent context. 1944 if (pagesCt instanceof Page) 1945 { 1946 PagesContainer parent = pagesCt.getParent(); 1947 boolean canDelete = _rightManager.hasRight(user, "Web_Rights_Page_Delete", parent) == RightResult.RIGHT_ALLOW; 1948 if (!canDelete) 1949 { 1950 // No right on parent page, so remove the right if exists. 1951 userRights.remove("Web_Rights_Page_Delete"); 1952 } 1953 } 1954 else 1955 { 1956 // There is no right of deletion on the sitemap 1957 userRights.remove("Web_Rights_Page_Delete"); 1958 } 1959 1960 return userRights; 1961 } 1962 1963 private boolean _isReferenced (Content content) 1964 { 1965 return content instanceof WebContent && ((WebContent) content).getReferencingPages().size() > 1; 1966 } 1967 1968 private boolean _isLocked (Content content) 1969 { 1970 if (content instanceof LockableAmetysObject) 1971 { 1972 LockableAmetysObject lockableContent = (LockableAmetysObject) content; 1973 if (lockableContent.isLocked()) 1974 { 1975 boolean canUnlockAll = _rightManager.hasRight(_currentUserProvider.getUser(), "CMS_Rights_UnlockAll", "/cms") == RightResult.RIGHT_ALLOW; 1976 if (!LockHelper.isLockOwner(lockableContent, _currentUserProvider.getUser()) && !canUnlockAll) 1977 { 1978 return true; 1979 } 1980 } 1981 } 1982 1983 return false; 1984 } 1985 1986 private boolean _isNew (Content content) 1987 { 1988 boolean isNew = false; 1989 if (content instanceof WorkflowAwareContent) 1990 { 1991 WorkflowAwareContent waContent = (WorkflowAwareContent) content; 1992 long workflowId = waContent.getWorkflowId(); 1993 1994 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent); 1995 isNew = workflow.getHistorySteps(workflowId).isEmpty(); 1996 } 1997 return isNew; 1998 } 1999 2000 private Map<String, Object> _page2Json (Page page) 2001 { 2002 Map<String, Object> page2json = new HashMap<>(); 2003 page2json.put("id", page.getId()); 2004 page2json.put("title", page.getTitle()); 2005 page2json.put("siteName", page.getSiteName()); 2006 page2json.put("path", page.getPathInSitemap()); 2007 return page2json; 2008 } 2009 2010 private Map<String, Object> _content2Json (Content content, Locale locale) 2011 { 2012 Map<String, Object> content2json = new HashMap<>(); 2013 content2json.put("id", content.getId()); 2014 content2json.put("title", content.getTitle(locale)); 2015 content2json.put("name", content.getName()); 2016 2017 List<Map<String, Object>> pages = new ArrayList<>(); 2018 if (content instanceof WebContent) 2019 { 2020 content2json.put("siteName", ((WebContent) content).getSiteName()); 2021 Collection<Page> refPages = ((WebContent) content).getReferencingPages(); 2022 for (Page refPage : refPages) 2023 { 2024 pages.add(_page2Json(refPage)); 2025 } 2026 content2json.put("pages", pages); 2027 } 2028 2029 return content2json; 2030 } 2031 2032 private Map<String, Object> _publication2Json (Page page) 2033 { 2034 Map<String, Object> pub2json = new HashMap<>(); 2035 @SuppressWarnings("unchecked") 2036 ElementType<ZonedDateTime> dateType = (ElementType<ZonedDateTime>) _pageDataTypeExtensionPoint.getExtension(ModelItemTypeConstants.DATETIME_TYPE_ID); 2037 2038 ZonedDateTime startDate = page.getValue(DefaultPage.METADATA_PUBLICATION_START_DATE); 2039 if (startDate != null) 2040 { 2041 pub2json.put("startDate", dateType.valueToJSONForClient(startDate)); 2042 } 2043 2044 ZonedDateTime endDate = page.getValue(DefaultPage.METADATA_PUBLICATION_END_DATE); 2045 if (endDate != null) 2046 { 2047 pub2json.put("endDate", dateType.valueToJSONForClient(endDate)); 2048 } 2049 2050 return pub2json; 2051 2052 } 2053 2054 private AmetysObjectIterable<Content> _getIncomingContentReferences (String pageId) 2055 { 2056 String xpathQuery = "//element(*, ametys:content)[ametys-internal:consistency/@ametys-internal:link = 'page:" + pageId + "']"; 2057 return _resolver.query(xpathQuery); 2058 } 2059 2060 private AmetysObjectIterable<Page> _getIncomingPageReferences (String pageId) 2061 { 2062 String xpathQuery = "//element(*, ametys:page)[@ametys-internal:type = 'LINK' and @ametys-internal:url= '" + pageId + "']"; 2063 return _resolver.query(xpathQuery); 2064 } 2065 2066 private Map<String, Object> _zone2json (Zone zone) 2067 { 2068 Map<String, Object> jsonObject = new HashMap<>(); 2069 jsonObject.put("name", zone.getName()); 2070 jsonObject.put("isModifiable", zone instanceof ModifiableZone); 2071 2072 List<Map<String, Object>> zoneitems = new ArrayList<>(); 2073 for (ZoneItem zoneItem : zone.getZoneItems()) 2074 { 2075 zoneitems.add(_zoneitem2json(zoneItem)); 2076 } 2077 2078 jsonObject.put("zoneitems", zoneitems); 2079 2080 return jsonObject; 2081 } 2082 2083 private Map<String, Object> _zoneitem2json (ZoneItem zoneItem) 2084 { 2085 Map<String, Object> jsonObject = new HashMap<>(); 2086 jsonObject.put("name", zoneItem.getName()); 2087 jsonObject.put("id", zoneItem.getId()); 2088 jsonObject.put("isModifiable", zoneItem instanceof ModifiableZoneItem); 2089 2090 switch (zoneItem.getType()) 2091 { 2092 case CONTENT: 2093 try 2094 { 2095 jsonObject.put("metadataSetName", zoneItem.getViewName()); 2096 2097 Content content = zoneItem.getContent(); 2098 jsonObject.put("content", _contentDAO.getContentProperties(content)); 2099 } 2100 catch (AmetysRepositoryException e) 2101 { 2102 getLogger().error("Unable to get content property on zone item", e); 2103 } 2104 break; 2105 2106 case SERVICE: 2107 jsonObject.put("service", zoneItem.getServiceId()); 2108 break; 2109 default: 2110 break; 2111 } 2112 2113 return jsonObject; 2114 } 2115 2116 private void _updateContentsAfterCopy (Page createdPage) throws AmetysRepositoryException 2117 { 2118 for (Zone zone : createdPage.getZones()) 2119 { 2120 for (ZoneItem zoneItem : zone.getZoneItems()) 2121 { 2122 if (zoneItem.getType().equals(ZoneType.CONTENT)) 2123 { 2124 Content content = zoneItem.getContent(); 2125 2126 // Convert content language if necessary 2127 if (content instanceof ModifiableContent && content.getLanguage() != null && content.getLanguage() != createdPage.getSitemapName()) 2128 { 2129 ((ModifiableContent) content).setLanguage(createdPage.getSitemapName()); 2130 ((ModifiableContent) content).saveChanges(); 2131 } 2132 2133 // Create the first version 2134 if (content instanceof VersionableAmetysObject) 2135 { 2136 ((VersionableAmetysObject) content).checkpoint(); 2137 } 2138 } 2139 } 2140 } 2141 2142 // Browse child pages 2143 for (Page childPage : createdPage.getChildrenPages()) 2144 { 2145 _updateContentsAfterCopy (childPage); 2146 } 2147 } 2148 2149 private List<String> _getChildrenPageIds (Page page) 2150 { 2151 List<String> childIds = new ArrayList<>(); 2152 2153 for (Page childPage : page.getChildrenPages()) 2154 { 2155 childIds.add(childPage.getId()); 2156 childIds.addAll(_getChildrenPageIds(childPage)); 2157 } 2158 2159 return childIds; 2160 } 2161 2162 /** 2163 * Check each parent and return true if one of them is invisible 2164 * @param page page to check 2165 * @return true if at least one parent is invisible 2166 */ 2167 private boolean _isParentInvisible (Page page) 2168 { 2169 AmetysObject parent = page.getParent(); 2170 while (parent != null && parent instanceof Page) 2171 { 2172 boolean invisible = !((Page) parent).isVisible(); 2173 if (invisible) 2174 { 2175 return true; 2176 } 2177 parent = parent.getParent(); 2178 } 2179 return false; 2180 } 2181 2182 /* start of a group of methods for _isPreviewable */ 2183 /** 2184 * Determine if this page is previewable 2185 * @param page The page to look at 2186 * @return true if the page can be previewed 2187 */ 2188 private boolean _isPreviewable(Page page) 2189 { 2190 // Check for infinitive loop redirection 2191 ArrayList<String> pagesSequence = new ArrayList<>(); 2192 pagesSequence.add(page.getId()); 2193 if (_isInfiniteRedirection (page, pagesSequence)) 2194 { 2195 getLogger().error("An infinite loop redirection was detected for page '" + page.getPathInSitemap() + "'"); 2196 return false; 2197 } 2198 2199 if (page.getType() == PageType.LINK && LinkType.PAGE.equals(page.getURLType())) 2200 { 2201 return _isPageExist(page.getURL()) && _isPreviewable((Page) _resolver.resolveById(page.getURL())); 2202 } 2203 2204 if (page.getType() != PageType.NODE) 2205 { 2206 return true; 2207 } 2208 else 2209 { 2210 for (Page subPage : page.getChildrenPages()) 2211 { 2212 if (_isPreviewable(subPage)) 2213 { 2214 return true; 2215 } 2216 } 2217 } 2218 return false; 2219 } 2220 2221 private boolean _isPageExist (String id) 2222 { 2223 try 2224 { 2225 _resolver.resolveById(id); 2226 return true; 2227 } 2228 catch (UnknownAmetysObjectException e) 2229 { 2230 return false; 2231 } 2232 } 2233 2234 private boolean _isInfiniteRedirection (Page page, List<String> pagesSequence) 2235 { 2236 Page redirectPage = _getPageRedirection (page); 2237 if (redirectPage == null) 2238 { 2239 return false; 2240 } 2241 2242 if (pagesSequence.contains(redirectPage.getId())) 2243 { 2244 return true; 2245 } 2246 2247 pagesSequence.add(redirectPage.getId()); 2248 return _isInfiniteRedirection (redirectPage, pagesSequence); 2249 } 2250 2251 private Page _getPageRedirection (Page page) 2252 { 2253 if (PageType.LINK.equals(page.getType()) && LinkType.PAGE.equals(page.getURLType())) 2254 { 2255 try 2256 { 2257 String pageId = page.getURL(); 2258 return _resolver.resolveById(pageId); 2259 } 2260 catch (AmetysRepositoryException e) 2261 { 2262 return null; 2263 } 2264 } 2265 else if (PageType.NODE.equals(page.getType())) 2266 { 2267 AmetysObjectIterable<? extends Page> childPages = page.getChildrenPages(); 2268 Iterator<? extends Page> it = childPages.iterator(); 2269 if (it.hasNext()) 2270 { 2271 return it.next(); 2272 } 2273 } 2274 2275 return null; 2276 } 2277 /* end of a group of methods for _isPreviewable */ 2278}