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