001/* 002 * Copyright 2021 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.forms.dao; 017 018import java.time.LocalDate; 019import java.time.ZonedDateTime; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Optional; 025import java.util.Set; 026import java.util.stream.Collectors; 027 028import javax.jcr.Node; 029import javax.jcr.Repository; 030import javax.jcr.RepositoryException; 031 032import org.apache.avalon.framework.component.Component; 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.core.observation.Event; 039import org.ametys.core.observation.ObservationManager; 040import org.ametys.core.right.RightManager; 041import org.ametys.core.right.RightManager.RightResult; 042import org.ametys.core.ui.Callable; 043import org.ametys.core.user.CurrentUserProvider; 044import org.ametys.core.user.UserIdentity; 045import org.ametys.core.util.DateUtils; 046import org.ametys.core.util.I18nUtils; 047import org.ametys.plugins.core.user.UserHelper; 048import org.ametys.plugins.forms.FormEvents; 049import org.ametys.plugins.forms.helper.ScheduleOpeningHelper; 050import org.ametys.plugins.forms.repository.CopyFormUpdater; 051import org.ametys.plugins.forms.repository.CopyFormUpdaterExtensionPoint; 052import org.ametys.plugins.forms.repository.Form; 053import org.ametys.plugins.forms.repository.FormDirectory; 054import org.ametys.plugins.forms.repository.FormEntry; 055import org.ametys.plugins.forms.repository.FormFactory; 056import org.ametys.plugins.forms.repository.FormQuestion; 057import org.ametys.plugins.repository.AmetysObject; 058import org.ametys.plugins.repository.AmetysObjectIterable; 059import org.ametys.plugins.repository.AmetysObjectResolver; 060import org.ametys.plugins.repository.ModifiableAmetysObject; 061import org.ametys.plugins.repository.UnknownAmetysObjectException; 062import org.ametys.plugins.repository.jcr.NameHelper; 063import org.ametys.plugins.repository.provider.AbstractRepository; 064import org.ametys.plugins.workflow.support.WorkflowHelper; 065import org.ametys.runtime.i18n.I18nizableText; 066import org.ametys.runtime.model.ElementDefinition; 067import org.ametys.runtime.plugin.component.AbstractLogEnabled; 068import org.ametys.web.parameters.view.ViewParametersManager; 069import org.ametys.web.repository.page.ModifiableZoneItem; 070import org.ametys.web.repository.page.Page; 071import org.ametys.web.repository.page.SitemapElement; 072import org.ametys.web.repository.page.ZoneDAO; 073import org.ametys.web.repository.page.ZoneItem; 074import org.ametys.web.repository.site.SiteManager; 075import org.ametys.web.service.Service; 076import org.ametys.web.service.ServiceExtensionPoint; 077 078/** 079 * The form DAO 080 */ 081public class FormDAO extends AbstractLogEnabled implements Serviceable, Component 082{ 083 /** The Avalon role */ 084 public static final String ROLE = FormDAO.class.getName(); 085 /** The right id to handle forms */ 086 public static final String HANDLE_FORMS_RIGHT_ID = "Plugins_Forms_Right_Handle"; 087 088 private static final String __FORM_NAME_PREFIX = "form-"; 089 090 /** The Ametys object resolver */ 091 protected AmetysObjectResolver _resolver; 092 /** The current user provider */ 093 protected CurrentUserProvider _userProvider; 094 /** I18n Utils */ 095 protected I18nUtils _i18nUtils; 096 /** The form directory DAO */ 097 protected FormDirectoryDAO _formDirectoryDAO; 098 /** The form page DAO */ 099 protected FormPageDAO _formPageDAO; 100 /** The form entry DAO */ 101 protected FormEntryDAO _formEntryDAO; 102 /** The user helper */ 103 protected UserHelper _userHelper; 104 /** The JCR repository. */ 105 protected Repository _repository; 106 /** The right manager */ 107 protected RightManager _rightManager; 108 /** The service extension point */ 109 protected ServiceExtensionPoint _serviceEP; 110 /** The zone DAO */ 111 protected ZoneDAO _zoneDAO; 112 /** The schedule opening helper */ 113 protected ScheduleOpeningHelper _scheduleOpeningHelper; 114 /** The workflow helper */ 115 protected WorkflowHelper _workflowHelper; 116 /** The site manager */ 117 protected SiteManager _siteManager; 118 /** Observer manager. */ 119 protected ObservationManager _observationManager; 120 /** The current user provider. */ 121 protected CurrentUserProvider _currentUserProvider; 122 123 /** The copy form updater extension point */ 124 protected CopyFormUpdaterExtensionPoint _copyFormEP; 125 126 public void service(ServiceManager manager) throws ServiceException 127 { 128 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 129 _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 130 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 131 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 132 _formDirectoryDAO = (FormDirectoryDAO) manager.lookup(FormDirectoryDAO.ROLE); 133 _formPageDAO = (FormPageDAO) manager.lookup(FormPageDAO.ROLE); 134 _formEntryDAO = (FormEntryDAO) manager.lookup(FormEntryDAO.ROLE); 135 _repository = (Repository) manager.lookup(AbstractRepository.ROLE); 136 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 137 _serviceEP = (ServiceExtensionPoint) manager.lookup(ServiceExtensionPoint.ROLE); 138 _zoneDAO = (ZoneDAO) manager.lookup(ZoneDAO.ROLE); 139 _scheduleOpeningHelper = (ScheduleOpeningHelper) manager.lookup(ScheduleOpeningHelper.ROLE); 140 _workflowHelper = (WorkflowHelper) manager.lookup(WorkflowHelper.ROLE); 141 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 142 _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); 143 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 144 _copyFormEP = (CopyFormUpdaterExtensionPoint) manager.lookup(CopyFormUpdaterExtensionPoint.ROLE); 145 } 146 147 /** 148 * Check if a user have read rights on a form 149 * @param userIdentity the user 150 * @param form the form 151 * @return true if the user have read rights on a form 152 */ 153 public boolean hasReadRightOnForm(UserIdentity userIdentity, Form form) 154 { 155 return _rightManager.hasReadAccess(userIdentity, form); 156 } 157 158 /** 159 * Check if a user have write rights on a form element 160 * @param userIdentity the user 161 * @param formElement the form element 162 * @return true if the user have write rights on a form element 163 */ 164 public boolean hasWriteRightOnForm(UserIdentity userIdentity, AmetysObject formElement) 165 { 166 return _rightManager.hasRight(userIdentity, HANDLE_FORMS_RIGHT_ID, formElement) == RightResult.RIGHT_ALLOW; 167 } 168 169 /** 170 * Check if a user have write rights on a form 171 * @param userIdentity the user 172 * @param form the form 173 * @return true if the user have write rights on a form 174 */ 175 public boolean hasRightAffectationRightOnForm(UserIdentity userIdentity, Form form) 176 { 177 return hasWriteRightOnForm(userIdentity, form) || _rightManager.hasRight(userIdentity, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW; 178 } 179 180 /** 181 * Check rights for a form element as ametys object 182 * @param formElement the form element as ametys object 183 */ 184 public void checkHandleFormRight(AmetysObject formElement) 185 { 186 UserIdentity user = _userProvider.getUser(); 187 if (!hasWriteRightOnForm(user, formElement)) 188 { 189 throw new IllegalAccessError("User '" + user + "' tried to handle forms without convenient right [" + HANDLE_FORMS_RIGHT_ID + "]"); 190 } 191 } 192 193 /** 194 * Get all forms from a site 195 * @param siteName the site name 196 * @return the list of form 197 */ 198 public List<Form> getForms(String siteName) 199 { 200 String xpathQuery = "//element(" + siteName + ", ametys:site)//element(*, ametys:form)"; 201 return _resolver.query(xpathQuery) 202 .stream() 203 .filter(Form.class::isInstance) 204 .map(Form.class::cast) 205 .collect(Collectors.toList()); 206 } 207 208 /** 209 * Get the form properties 210 * @param formId The form's id 211 * @param full <code>true</code> to get full information on form 212 * @param withRights <code>true</code> to have rights in the properties 213 * @return The form properties 214 */ 215 @Callable 216 public Map<String, Object> getFormProperties (String formId, boolean full, boolean withRights) 217 { 218 try 219 { 220 Form form = _resolver.resolveById(formId); 221 return getFormProperties(form, full, true); 222 } 223 catch (UnknownAmetysObjectException e) 224 { 225 getLogger().warn("Can't find form with id: {}. It probably has just been deleted", formId, e); 226 Map<String, Object> infos = new HashMap<>(); 227 infos.put("id", formId); 228 return infos; 229 } 230 } 231 232 /** 233 * Get the form properties 234 * @param form The form 235 * @param full <code>true</code> to get full information on form 236 * @param withRights <code>true</code> to have rights in the properties 237 * @return The form properties 238 */ 239 public Map<String, Object> getFormProperties (Form form, boolean full, boolean withRights) 240 { 241 Map<String, Object> infos = new HashMap<>(); 242 243 List<FormEntry> entries = form.getEntries(); 244 List<SitemapElement> pages = getFormPage(form.getId(), form.getSiteName()); 245 String workflowName = form.getWorkflowName(); 246 247 infos.put("type", "root"); 248 infos.put("isForm", true); 249 infos.put("author", _userHelper.user2json(form.getAuthor(), true)); 250 infos.put("contributor", _userHelper.user2json(form.getContributor())); 251 infos.put("lastModificationDate", DateUtils.zonedDateTimeToString(form.getLastModificationDate())); 252 infos.put("creationDate", DateUtils.zonedDateTimeToString(form.getCreationDate())); 253 infos.put("entriesAmount", entries.size()); 254 infos.put("lastEntry", _getLastSubmissionDate(entries)); 255 infos.put("workflowLabel", StringUtils.isNotBlank(workflowName) ? _workflowHelper.getWorkflowLabel(workflowName) : new I18nizableText("plugin.forms", "PLUGINS_FORMS_FORMS_EDITOR_WORKFLOW_NO_WORKFLOW")); 256 257 /** Use in the bus message */ 258 infos.put("id", form.getId()); 259 infos.put("name", form.getName()); 260 infos.put("title", form.getTitle()); 261 infos.put("fullPath", getFormFullPath(form.getId())); 262 infos.put("pages", _getPagesInfos(pages)); 263 infos.put("hasChildren", form.getPages().size() > 0); 264 infos.put("workflowName", workflowName); 265 266 infos.put("isConfigured", isFormConfigured(form)); 267 268 UserIdentity currentUser = _userProvider.getUser(); 269 if (withRights) 270 { 271 Set<String> userRights = _getUserRights(form); 272 infos.put("rights", userRights); 273 infos.put("canEditRight", userRights.contains(HANDLE_FORMS_RIGHT_ID) || _rightManager.hasRight(currentUser, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW); 274 } 275 else 276 { 277 boolean canWrite = hasWriteRightOnForm(currentUser, form); 278 infos.put("canWrite", canWrite); 279 infos.put("canEditRight", canWrite || _rightManager.hasRight(currentUser, "Runtime_Rights_Rights_Handle", "/cms") == RightResult.RIGHT_ALLOW); 280 infos.put("canRead", hasReadRightOnForm(currentUser, form)); 281 } 282 283 if (full) 284 { 285 infos.put("isPublished", !pages.isEmpty()); 286 infos.put("hasEntries", form.hasEntries()); 287 infos.put("nbEntries", form.getActiveEntries().size()); 288 289 FormDirectory formDirectoriesRoot = _formDirectoryDAO.getFormDirectoriesRootNode(form.getSiteName()); 290 String parentId = form.getParent().getId().equals(formDirectoriesRoot.getId()) ? FormDirectoryDAO.ROOT_FORM_DIRECTORY_ID : form.getParent().getId(); 291 infos.put("parentId", parentId); 292 293 infos.put("isLimitedToOneEntryByUser", form.isLimitedToOneEntryByUser()); 294 infos.put("isEntriesLimited", form.isEntriesLimited()); 295 Optional<Long> maxEntries = form.getMaxEntries(); 296 if (maxEntries.isPresent()) 297 { 298 infos.put("maxEntries", maxEntries.get()); 299 } 300 infos.put("isQueueEnabled", form.isQueueEnabled()); 301 Optional<Long> queueSize = form.getQueueSize(); 302 if (queueSize.isPresent()) 303 { 304 infos.put("queueSize", queueSize.get()); 305 } 306 307 LocalDate startDate = form.getStartDate(); 308 LocalDate endDate = form.getEndDate(); 309 if (startDate != null || endDate != null) 310 { 311 infos.put("scheduleStatus", _scheduleOpeningHelper.getStatus(form)); 312 if (startDate != null) 313 { 314 infos.put("startDate", DateUtils.localDateToString(startDate)); 315 } 316 if (endDate != null) 317 { 318 infos.put("endDate", DateUtils.localDateToString(endDate)); 319 } 320 } 321 322 infos.put("adminEmails", form.hasValue(Form.ADMIN_EMAIL_SUBJECT)); 323 infos.put("receiptAcknowledgement", form.hasValue(Form.RECEIPT_SENDER)); 324 infos.put("isAnonymous", _rightManager.hasAnonymousReadAccess(form)); 325 } 326 327 return infos; 328 } 329 330 /** 331 * Get the form title 332 * @param formId the form id 333 * @return the form title 334 */ 335 @Callable 336 public String getFormTitle(String formId) 337 { 338 Form form = _resolver.resolveById(formId); 339 return form.getTitle(); 340 } 341 342 /** 343 * Get the form full path 344 * @param formId the form id 345 * @return the form full path 346 */ 347 @Callable 348 public String getFormFullPath(String formId) 349 { 350 Form form = _resolver.resolveById(formId); 351 352 String separator = " > "; 353 String fullPath = form.getTitle(); 354 355 FormDirectory parent = form.getParent(); 356 if (!_formDirectoryDAO.isRoot(parent)) 357 { 358 fullPath = _formDirectoryDAO.getFormDirectoryPath(parent, separator) + separator + fullPath; 359 } 360 361 return fullPath; 362 } 363 364 /** 365 * Get user rights for the given form 366 * @param form the form 367 * @return the set of rights 368 */ 369 protected Set<String> _getUserRights (Form form) 370 { 371 UserIdentity user = _userProvider.getUser(); 372 return _rightManager.getUserRights(user, form); 373 } 374 375 /** 376 * Creates a {@link Form}. 377 * @param siteName The site name 378 * @param parentId The id of the parent. 379 * @param name name The desired name for the new {@link Form} 380 * @return The id of the created form 381 * @throws Exception if an error occurs during the form creation process 382 */ 383 @Callable 384 public Map<String, String> createForm (String siteName, String parentId, String name) throws Exception 385 { 386 Map<String, String> result = new HashMap<>(); 387 388 FormDirectory parentDirectory = _formDirectoryDAO.getFormDirectory(siteName, parentId); 389 _formDirectoryDAO.checkHandleFormDirectoriesRight(parentDirectory); 390 391 String uniqueName = _findUniqueName(parentDirectory, name); 392 Form form = parentDirectory.createChild(uniqueName, FormFactory.FORM_NODETYPE); 393 394 form.setTitle(name); 395 form.setAuthor(_userProvider.getUser()); 396 form.setCreationDate(ZonedDateTime.now()); 397 form.setLastModificationDate(ZonedDateTime.now()); 398 399 parentDirectory.saveChanges(); 400 String formId = form.getId(); 401 402 _formPageDAO.createPage(formId, _i18nUtils.translate(new I18nizableText("plugin.forms", "PLUGINS_FORMS_CREATE_PAGE_DEFAULT_NAME"))); 403 404 result.put("id", formId); 405 result.put("name", form.getTitle()); 406 407 return result; 408 } 409 410 private String _findUniqueName(FormDirectory parent, String name) 411 { 412 String legalName; 413 try 414 { 415 legalName = NameHelper.filterName(name); 416 } 417 catch (IllegalArgumentException e) 418 { 419 legalName = NameHelper.filterName(__FORM_NAME_PREFIX + name); 420 } 421 422 // Find unique name from legal name 423 String uniqueName = legalName; 424 int index = 2; 425 while (parent.hasChild(uniqueName)) 426 { 427 uniqueName = legalName + "-" + (index++); 428 } 429 430 return uniqueName; 431 } 432 433 /** 434 * Rename a {@link Form} 435 * @param id The id of the form 436 * @param newName The new name for the form 437 * @return A result map 438 */ 439 @Callable 440 public Map<String, String> renameForm (String id, String newName) 441 { 442 Map<String, String> results = new HashMap<>(); 443 444 Form form = _resolver.resolveById(id); 445 checkHandleFormRight(form); 446 447 String uniqueName = _findUniqueName(form.getParent(), newName); 448 Node node = form.getNode(); 449 try 450 { 451 form.setTitle(newName); 452 form.setContributor(_userProvider.getUser()); 453 form.setLastModificationDate(ZonedDateTime.now()); 454 455 node.getSession().move(node.getPath(), node.getParent().getPath() + '/' + uniqueName); 456 node.getSession().save(); 457 458 results.put("newName", form.getTitle()); 459 } 460 catch (RepositoryException e) 461 { 462 getLogger().warn("Form renaming failed.", e); 463 results.put("message", "cannot-rename"); 464 } 465 466 results.put("id", id); 467 return results; 468 } 469 470 /** 471 * Copies and pastes a form. 472 * @param formDirectoryId The id of the form directory target of the copy 473 * @param formId The id of the form to copy 474 * @return The results 475 */ 476 @Callable 477 public Map<String, String> copyForm(String formDirectoryId, String formId) 478 { 479 Map<String, String> result = new HashMap<>(); 480 481 Form originalForm = _resolver.resolveById(formId); 482 FormDirectory parentFormDirectory = _resolver.resolveById(formDirectoryId); 483 _formDirectoryDAO.checkHandleFormDirectoriesRight(parentFormDirectory); 484 485 String uniqueName = _findUniqueName(parentFormDirectory, originalForm.getTitle()); 486 487 Form cForm = originalForm.copyTo(parentFormDirectory, uniqueName); 488 originalForm.copyTo(cForm); 489 490 String copyTitle = _i18nUtils.translate(new I18nizableText("plugin.forms", "PLUGIN_FORMS_TREE_COPY_NAME_PREFIX")) + originalForm.getTitle(); 491 cForm.setTitle(copyTitle); 492 cForm.setAuthor(_userProvider.getUser()); 493 cForm.setCreationDate(ZonedDateTime.now()); 494 cForm.setLastModificationDate(ZonedDateTime.now()); 495 496 for (String epId : _copyFormEP.getExtensionsIds()) 497 { 498 CopyFormUpdater copyFormUpdater = _copyFormEP.getExtension(epId); 499 copyFormUpdater.updateForm(originalForm, cForm); 500 } 501 502 result.put("id", cForm.getId()); 503 504 return result; 505 } 506 507 /** 508 * Deletes a {@link Form}. 509 * @param id The id of the form to delete 510 * @return The id of the form 511 */ 512 @Callable 513 public Map<String, String> deleteForm (String id) 514 { 515 Map<String, String> result = new HashMap<>(); 516 517 Form form = _resolver.resolveById(id); 518 checkHandleFormRight(form); 519 520 List<SitemapElement> pages = getFormPage(form.getId(), form.getSiteName()); 521 if (!pages.isEmpty()) 522 { 523 throw new IllegalAccessError("Can't delete form ('" + form.getId() + "') which contains pages"); 524 } 525 526 ModifiableAmetysObject parent = form.getParent(); 527 form.remove(); 528 parent.saveChanges(); 529 530 result.put("id", id); 531 return result; 532 } 533 534 /** 535 * Moves a {@link Form} 536 * @param siteName name of the site 537 * @param id The id of the form 538 * @param newParentId The id of the new parent directory of the form. 539 * @return A result map 540 */ 541 @Callable 542 public Map<String, Object> moveForm(String siteName, String id, String newParentId) 543 { 544 Map<String, Object> results = new HashMap<>(); 545 Form form = _resolver.resolveById(id); 546 FormDirectory directory = _formDirectoryDAO.getFormDirectory(siteName, newParentId); 547 548 if (hasWriteRightOnForm(_userProvider.getUser(), form) && _formDirectoryDAO.hasWriteRightOnFormDirectory(_userProvider.getUser(), directory)) 549 { 550 _formDirectoryDAO.move(form, siteName, newParentId, results); 551 } 552 else 553 { 554 results.put("message", "not-allowed"); 555 } 556 557 results.put("id", form.getId()); 558 return results; 559 } 560 561 /** 562 * Change workflow of a {@link Form} 563 * @param formId The id of the form 564 * @param workflowName The name of new workflow 565 * @return A result map 566 */ 567 @Callable 568 public Map<String, String> setWorkflow (String formId, String workflowName) 569 { 570 Map<String, String> results = new HashMap<>(); 571 572 Form form = _resolver.resolveById(formId); 573 checkHandleFormRight(form); 574 575 form.setWorkflowName(workflowName); 576 form.setContributor(_userProvider.getUser()); 577 form.setLastModificationDate(ZonedDateTime.now()); 578 579 form.saveChanges(); 580 581 results.put("id", formId); 582 583 Map<String, Object> eventParams = new HashMap<>(); 584 eventParams.put("form", form); 585 _observationManager.notify(new Event(FormEvents.FORM_MODIFIED, _currentUserProvider.getUser(), eventParams)); 586 587 return results; 588 } 589 590 /** 591 * Get the submission date of the last entry to the form 592 * @param entries A list of form entry 593 * @return the date of the last submission 594 */ 595 protected ZonedDateTime _getLastSubmissionDate(List<FormEntry> entries) 596 { 597 ZonedDateTime lastSubmissionDate = null; 598 if (!entries.isEmpty()) 599 { 600 lastSubmissionDate = entries.get(0).getSubmitDate(); 601 for (FormEntry entry : entries) 602 { 603 ZonedDateTime submitDate = entry.getSubmitDate(); 604 if (lastSubmissionDate.isBefore(submitDate)) 605 { 606 lastSubmissionDate = submitDate; 607 } 608 } 609 } 610 return lastSubmissionDate; 611 } 612 613 /** 614 * Get all zone items which contains the form 615 * @param formId the form id 616 * @param siteName the site name 617 * @return the zone items 618 */ 619 public AmetysObjectIterable<ModifiableZoneItem> getFormZoneItems(String formId, String siteName) 620 { 621 String xpathQuery = "//element(" + siteName + ", ametys:site)//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.forms.service.Display' and ametys:service_parameters/@ametys:formId = '" + formId + "']"; 622 return _resolver.query(xpathQuery); 623 } 624 625 /** 626 * Get the locale to use for a given form 627 * @param form the form 628 * @return the locale to use, can be null if the form is not published on a page 629 */ 630 public String getFormLocale(Form form) 631 { 632 List<SitemapElement> zoneItems = getFormPage(form.getId(), form.getSiteName()); 633 634 return zoneItems.stream() 635 .findFirst() 636 .map(SitemapElement::getSitemapName) 637 .orElse(null); 638 } 639 640 /** 641 * Get all the page where the form is published 642 * @param formId the form id 643 * @param siteName the site name 644 * @return the list of page 645 */ 646 public List<SitemapElement> getFormPage(String formId, String siteName) 647 { 648 AmetysObjectIterable<ModifiableZoneItem> zoneItems = getFormZoneItems(formId, siteName); 649 650 return zoneItems.stream() 651 .map(z -> z.getZone().getSitemapElement()) 652 .collect(Collectors.toList()); 653 } 654 655 /** 656 * Get the page names 657 * @param pages the list of page 658 * @return the list of page name 659 */ 660 protected List<Map<String, Object>> _getPagesInfos(List<SitemapElement> pages) 661 { 662 List<Map<String, Object>> pagesInfos = new ArrayList<>(); 663 for (SitemapElement sitemapElement : pages) 664 { 665 Map<String, Object> info = new HashMap<>(); 666 info.put("id", sitemapElement.getId()); 667 info.put("title", sitemapElement.getTitle()); 668 info.put("isPage", sitemapElement instanceof Page); 669 670 pagesInfos.add(info); 671 } 672 673 return pagesInfos; 674 } 675 676 /** 677 * Get all the view available for the form display service 678 * @param formId the form identifier 679 * @param siteName the site name 680 * @param language the language 681 * @return the views as json 682 * @throws Exception if an error occurred 683 */ 684 @Callable 685 public List<Map<String, Object>> getFormDisplayViews(String formId, String siteName, String language) throws Exception 686 { 687 List<Map<String, Object>> jsonifiedViews = new ArrayList<>(); 688 689 Service service = _serviceEP.getExtension("org.ametys.forms.service.Display"); 690 ElementDefinition viewElementDefinition = (ElementDefinition) service.getParameters().getOrDefault(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME, null); 691 692 String xpathQuery = "//element(" + siteName + ", ametys:site)/ametys-internal:sitemaps/" + language 693 + "//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.forms.service.Display' and ametys:service_parameters/@ametys:formId = '" + formId + "']"; 694 AmetysObjectIterable<ModifiableZoneItem> zoneItems = _resolver.query(xpathQuery); 695 696 Optional<Object> existedServiceView = zoneItems.stream() 697 .map(ZoneItem::getServiceParameters) 698 .map(sp -> sp.getValue(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME)) 699 .findFirst(); 700 701 Map<String, I18nizableText> typedEntries = viewElementDefinition.getEnumerator().getTypedEntries(); 702 for (String id : typedEntries.keySet()) 703 { 704 Map<String, Object> viewAsJson = new HashMap<>(); 705 viewAsJson.put("id", id); 706 viewAsJson.put("label", typedEntries.get(id)); 707 708 Boolean isServiceView = existedServiceView.map(s -> s.equals(id)).orElse(false); 709 if (isServiceView || existedServiceView.isEmpty() && id.equals(viewElementDefinition.getDefaultValue())) 710 { 711 viewAsJson.put("isDefault", true); 712 } 713 714 jsonifiedViews.add(viewAsJson); 715 } 716 717 return jsonifiedViews; 718 } 719 720 /** 721 * <code>true</code> if the form is well configured 722 * @param form the form 723 * @return <code>true</code> if the form is well configured 724 */ 725 public boolean isFormConfigured(Form form) 726 { 727 List<FormQuestion> questions = form.getQuestions(); 728 return !questions.isEmpty() && !questions.stream().anyMatch(q -> !q.getType().isQuestionConfigured(q)); 729 } 730 731 /** 732 * Get the dashboard URI 733 * @param siteName the site name 734 * @return the dashboard URI 735 */ 736 public String getDashboardUri(String siteName) 737 { 738 String xpathQuery = "//element(" + siteName + ", ametys:site)//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.plugins.forms.workflow.service.dashboard']"; 739 AmetysObjectIterable<ModifiableZoneItem> zoneItems = _resolver.query(xpathQuery); 740 741 Optional<Page> dashboardPage = zoneItems.stream() 742 .map(z -> z.getZone().getSitemapElement()) 743 .filter(Page.class::isInstance) 744 .map(Page.class::cast) 745 .findAny(); 746 747 if (dashboardPage.isPresent()) 748 { 749 Page page = dashboardPage.get(); 750 String pagePath = page.getSitemap().getName() + "/" + page.getPathInSitemap() + ".html"; 751 752 String url = _siteManager.getSite(siteName).getUrl(); 753 return url + "/" + pagePath; 754 } 755 756 return StringUtils.EMPTY; 757 } 758 759 /** 760 * Get the admin dashboard URI 761 * @param siteName the site name 762 * @return the admin dashboard URI 763 */ 764 public String getAdminDashboardUri(String siteName) 765 { 766 String xpathQuery = "//element(" + siteName + ", ametys:site)//element(*, ametys:zoneItem)[@ametys-internal:service = 'org.ametys.plugins.forms.workflow.service.admin.dashboard']"; 767 AmetysObjectIterable<ModifiableZoneItem> zoneItems = _resolver.query(xpathQuery); 768 769 Optional<Page> dashboardPage = zoneItems.stream() 770 .map(z -> z.getZone().getSitemapElement()) 771 .filter(Page.class::isInstance) 772 .map(Page.class::cast) 773 .findAny(); 774 775 if (dashboardPage.isPresent()) 776 { 777 Page page = dashboardPage.get(); 778 String pagePath = page.getSitemap().getName() + "/" + page.getPathInSitemap() + ".html"; 779 780 String url = _siteManager.getSite(siteName).getUrl(); 781 return url + "/" + pagePath; 782 } 783 784 return StringUtils.EMPTY; 785 } 786}