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