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.plugins.survey.repository; 017 018import java.util.ArrayList; 019import java.util.Date; 020import java.util.GregorianCalendar; 021import java.util.List; 022import java.util.stream.Collectors; 023 024import javax.jcr.Node; 025import javax.jcr.PathNotFoundException; 026import javax.jcr.RepositoryException; 027 028import org.ametys.cms.indexing.solr.SolrAclCacheUninfluentialObject; 029import org.ametys.plugins.repository.AmetysObject; 030import org.ametys.plugins.repository.AmetysObjectIterable; 031import org.ametys.plugins.repository.AmetysRepositoryException; 032import org.ametys.plugins.repository.ChainedAmetysObjectIterable; 033import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 034import org.ametys.plugins.repository.RepositoryConstants; 035import org.ametys.web.repository.SiteAwareAmetysObject; 036import org.ametys.web.repository.site.Site; 037 038/** 039 * {@link AmetysObject} representing a survey 040 */ 041@SolrAclCacheUninfluentialObject 042public class Survey extends AbstractSurveyElement<SurveyFactory> implements SiteAwareAmetysObject 043{ 044 /** Constants for title metadata. */ 045 private static final String __PROPERTY_TITLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":title"; 046 /** Constants for header metadata. */ 047 private static final String __PROPERTY_LABEL = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":label"; 048 /** Constants for description metadata. */ 049 private static final String __PROPERTY_DESC = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":description"; 050 /** Constants for description metadata. */ 051 private static final String __PROPERTY_ENDING_MSG = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":endingMessage"; 052 /** Constants for private metadata. */ 053 private static final String __PROPERTY_VALIDATED = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":validated"; 054 /** Constants for private metadata. */ 055 private static final String __PROPERTY_VALIDATION_DATE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":validationDate"; 056 /** Constants for start date metadata. */ 057 private static final String __PROPERTY_START_DATE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":startDate"; 058 /** Constants for end date metadata. */ 059 private static final String __PROPERTY_END_DATE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":endDate"; 060 /** Constants for private metadata. */ 061 private static final String __PROPERTY_REDIRECTION = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":redirection"; 062 063 /** 064 * Creates a {@link Survey}. 065 * @param node the node backing this {@link AmetysObject}. 066 * @param parentPath the parent path in the Ametys hierarchy. 067 * @param factory the {@link SurveyFactory} which creates the AmetysObject. 068 */ 069 public Survey(Node node, String parentPath, SurveyFactory factory) 070 { 071 super(node, parentPath, factory); 072 } 073 074 /** 075 * Retrieves the title. 076 * @return the title. 077 * @throws AmetysRepositoryException if an error occurs. 078 */ 079 public String getTitle() throws AmetysRepositoryException 080 { 081 try 082 { 083 return getNode().getProperty(__PROPERTY_TITLE).getString(); 084 } 085 catch (PathNotFoundException e) 086 { 087 return null; 088 } 089 catch (RepositoryException e) 090 { 091 throw new AmetysRepositoryException("Unable to get title property", e); 092 } 093 } 094 095 /** 096 * Set the title. 097 * @param title the title. 098 * @throws AmetysRepositoryException if an error occurs. 099 */ 100 public void setTitle(String title) throws AmetysRepositoryException 101 { 102 try 103 { 104 getNode().setProperty(__PROPERTY_TITLE, title); 105 } 106 catch (RepositoryException e) 107 { 108 throw new AmetysRepositoryException("Unable to set title property", e); 109 } 110 } 111 112 /** 113 * Retrieves the survey label. 114 * @return the the survey label. 115 * @throws AmetysRepositoryException if an error occurs. 116 */ 117 public String getLabel() throws AmetysRepositoryException 118 { 119 try 120 { 121 return getNode().getProperty(__PROPERTY_LABEL).getString(); 122 } 123 catch (PathNotFoundException e) 124 { 125 return null; 126 } 127 catch (RepositoryException e) 128 { 129 throw new AmetysRepositoryException("Unable to get label property", e); 130 } 131 } 132 133 /** 134 * Set the survey label. 135 * @param label the survey label. 136 * @throws AmetysRepositoryException if an error occurs. 137 */ 138 public void setLabel(String label) throws AmetysRepositoryException 139 { 140 try 141 { 142 getNode().setProperty(__PROPERTY_LABEL, label); 143 } 144 catch (RepositoryException e) 145 { 146 throw new AmetysRepositoryException("Unable to set label property", e); 147 } 148 } 149 150 /** 151 * Retrieves the description. 152 * @return the description. 153 * @throws AmetysRepositoryException if an error occurs. 154 */ 155 public String getDescription() throws AmetysRepositoryException 156 { 157 try 158 { 159 return getNode().getProperty(__PROPERTY_DESC).getString(); 160 } 161 catch (PathNotFoundException e) 162 { 163 return null; 164 } 165 catch (RepositoryException e) 166 { 167 throw new AmetysRepositoryException("Unable to get description property", e); 168 } 169 } 170 171 /** 172 * Set the description. 173 * @param description the description. 174 * @throws AmetysRepositoryException if an error occurs. 175 */ 176 public void setDescription(String description) throws AmetysRepositoryException 177 { 178 try 179 { 180 getNode().setProperty(__PROPERTY_DESC, description); 181 } 182 catch (RepositoryException e) 183 { 184 throw new AmetysRepositoryException("Unable to set description property", e); 185 } 186 } 187 188 /** 189 * Retrieves the ending message. 190 * @return the ending message. 191 * @throws AmetysRepositoryException if an error occurs. 192 */ 193 public String getEndingMessage() throws AmetysRepositoryException 194 { 195 try 196 { 197 return getNode().getProperty(__PROPERTY_ENDING_MSG).getString(); 198 } 199 catch (PathNotFoundException e) 200 { 201 return null; 202 } 203 catch (RepositoryException e) 204 { 205 throw new AmetysRepositoryException("Unable to get ending message property", e); 206 } 207 } 208 209 /** 210 * Set the ending message. 211 * @param message the ending message. 212 * @throws AmetysRepositoryException if an error occurs. 213 */ 214 public void setEndingMessage(String message) throws AmetysRepositoryException 215 { 216 try 217 { 218 getNode().setProperty(__PROPERTY_ENDING_MSG, message); 219 } 220 catch (RepositoryException e) 221 { 222 throw new AmetysRepositoryException("Unable to set ending message property", e); 223 } 224 } 225 226 /** 227 * Determines if the survey is validated. 228 * @return true if the survey is validated. 229 * @throws AmetysRepositoryException if an error occurs. 230 */ 231 public boolean isValidated() throws AmetysRepositoryException 232 { 233 try 234 { 235 return getNode().getProperty(__PROPERTY_VALIDATED).getBoolean(); 236 } 237 catch (PathNotFoundException e) 238 { 239 return false; 240 } 241 catch (RepositoryException e) 242 { 243 throw new AmetysRepositoryException("Unable to get validated property", e); 244 } 245 } 246 247 /** 248 * Valid or invalid survey 249 * @param validated true to validate the survey 250 * @throws AmetysRepositoryException if an error occurs. 251 */ 252 public void setValidated(boolean validated) throws AmetysRepositoryException 253 { 254 try 255 { 256 getNode().setProperty(__PROPERTY_VALIDATED, validated); 257 } 258 catch (RepositoryException e) 259 { 260 throw new AmetysRepositoryException("Unable to validate survey", e); 261 } 262 } 263 264 /** 265 * Set the date of validation 266 * @param date The date of validation 267 * @throws AmetysRepositoryException if an error occurs. 268 */ 269 public void setValidationDate(Date date) throws AmetysRepositoryException 270 { 271 try 272 { 273 if (date != null) 274 { 275 GregorianCalendar calendar = new GregorianCalendar(); 276 calendar.setTime(date); 277 278 getNode().setProperty(__PROPERTY_VALIDATION_DATE, calendar); 279 } 280 else if (getNode().hasProperty(__PROPERTY_VALIDATION_DATE)) 281 { 282 getNode().getProperty(__PROPERTY_VALIDATION_DATE).remove(); 283 } 284 } 285 catch (RepositoryException e) 286 { 287 throw new AmetysRepositoryException("Unable to set date of validation", e); 288 } 289 } 290 291 /** 292 * Get the date of validation 293 * @return the date of validation 294 * @throws AmetysRepositoryException if an error occurs. 295 */ 296 public Date getValidationDate () throws AmetysRepositoryException 297 { 298 try 299 { 300 return getNode().getProperty(__PROPERTY_VALIDATION_DATE).getDate().getTime(); 301 } 302 catch (PathNotFoundException e) 303 { 304 return null; 305 } 306 catch (RepositoryException e) 307 { 308 throw new AmetysRepositoryException("Unable to get validation date property", e); 309 } 310 } 311 312 /** 313 * Set the start date 314 * @param date The start date 315 * @throws AmetysRepositoryException if an error occurs. 316 */ 317 public void setStartDate(Date date) throws AmetysRepositoryException 318 { 319 try 320 { 321 if (date != null) 322 { 323 GregorianCalendar calendar = new GregorianCalendar(); 324 calendar.setTime(date); 325 326 getNode().setProperty(__PROPERTY_START_DATE, calendar); 327 } 328 else if (getNode().hasProperty(__PROPERTY_START_DATE)) 329 { 330 getNode().getProperty(__PROPERTY_START_DATE).remove(); 331 } 332 } 333 catch (RepositoryException e) 334 { 335 throw new AmetysRepositoryException("Unable to set start date", e); 336 } 337 } 338 339 /** 340 * Get the start date 341 * @return the start date 342 * @throws AmetysRepositoryException if an error occurs. 343 */ 344 public Date getStartDate () throws AmetysRepositoryException 345 { 346 try 347 { 348 return getNode().getProperty(__PROPERTY_START_DATE).getDate().getTime(); 349 } 350 catch (PathNotFoundException e) 351 { 352 return null; 353 } 354 catch (RepositoryException e) 355 { 356 throw new AmetysRepositoryException("Unable to get start date property", e); 357 } 358 } 359 360 /** 361 * Set the end date 362 * @param date The end date 363 * @throws AmetysRepositoryException if an error occurs. 364 */ 365 public void setEndDate(Date date) throws AmetysRepositoryException 366 { 367 try 368 { 369 if (date != null) 370 { 371 GregorianCalendar calendar = new GregorianCalendar(); 372 calendar.setTime(date); 373 374 getNode().setProperty(__PROPERTY_END_DATE, calendar); 375 } 376 else if (getNode().hasProperty(__PROPERTY_END_DATE)) 377 { 378 getNode().getProperty(__PROPERTY_END_DATE).remove(); 379 } 380 } 381 catch (RepositoryException e) 382 { 383 throw new AmetysRepositoryException("Unable to set end date", e); 384 } 385 } 386 387 /** 388 * Get the end date 389 * @return the end date 390 * @throws AmetysRepositoryException if an error occurs. 391 */ 392 public Date getEndDate () throws AmetysRepositoryException 393 { 394 try 395 { 396 return getNode().getProperty(__PROPERTY_END_DATE).getDate().getTime(); 397 } 398 catch (PathNotFoundException e) 399 { 400 return null; 401 } 402 catch (RepositoryException e) 403 { 404 throw new AmetysRepositoryException("Unable to get end date property", e); 405 } 406 } 407 408 /** 409 * Retrieves the redirection. 410 * @return the page id of redirection or null. 411 * @throws AmetysRepositoryException if an error occurs. 412 */ 413 public String getRedirection() throws AmetysRepositoryException 414 { 415 try 416 { 417 return getNode().getProperty(__PROPERTY_REDIRECTION).getString(); 418 } 419 catch (PathNotFoundException e) 420 { 421 return null; 422 } 423 catch (RepositoryException e) 424 { 425 throw new AmetysRepositoryException("Unable to get redirection property", e); 426 } 427 } 428 429 /** 430 * Set the redirection. 431 * @param pageId the page id. Can be null to delete redirection 432 * @throws AmetysRepositoryException if an error occurs. 433 */ 434 public void setRedirection(String pageId) throws AmetysRepositoryException 435 { 436 try 437 { 438 if (pageId == null) 439 { 440 if (getNode().hasProperty(__PROPERTY_REDIRECTION)) 441 { 442 getNode().getProperty(__PROPERTY_REDIRECTION).remove(); 443 } 444 } 445 else 446 { 447 getNode().setProperty(__PROPERTY_REDIRECTION, pageId); 448 } 449 } 450 catch (RepositoryException e) 451 { 452 throw new AmetysRepositoryException("Unable to set redirection property", e); 453 } 454 } 455 456 /** 457 * Get the survey pages. 458 * @return the survey pages. 459 * @throws AmetysRepositoryException if an error occurs when retrieving the pages of the survey 460 */ 461 public List<SurveyPage> getPages() throws AmetysRepositoryException 462 { 463 return getChildren().stream() 464 .filter(child -> child instanceof SurveyPage) 465 .map(child -> (SurveyPage) child) 466 .collect(Collectors.toList()); 467 } 468 469 /** 470 * Get a question by its name. 471 * @param name the question name. 472 * @return the question. 473 * @throws AmetysRepositoryException if an error occurs when retrieving a question of a survey 474 */ 475 public SurveyQuestion getQuestion(String name) throws AmetysRepositoryException 476 { 477 for (SurveyPage page : getPages()) 478 { 479 if (page.hasChild(name)) 480 { 481 return page.getQuestion(name); 482 } 483 } 484 return null; 485 } 486 487 /** 488 * Get the survey questions. 489 * @return the survey questions. 490 * @throws AmetysRepositoryException if an error occurs when retrieving all the questions of a survey 491 */ 492 public AmetysObjectIterable<SurveyQuestion> getQuestions() throws AmetysRepositoryException 493 { 494 List<AmetysObjectIterable<SurveyQuestion>> questions = new ArrayList<>(); 495 496 for (SurveyPage page : getPages()) 497 { 498 questions.add(page.getQuestions()); 499 } 500 501 return new ChainedAmetysObjectIterable<>(questions); 502 } 503 504 @Override 505 public Site getSite() throws AmetysRepositoryException 506 { 507 return getParent().getParent().getParent().getParent().getParent(); 508 } 509 510 @Override 511 public String getSiteName() throws AmetysRepositoryException 512 { 513 return getSite().getName(); 514 } 515 516 /** 517 * Get the survey language. 518 * @return the survey language. 519 */ 520 public String getLanguage() 521 { 522 return getParent().getName(); 523 } 524 525 /** 526 * Returns a unique question name in the survey 527 * @param originalName The original name 528 * @return a unique question name 529 */ 530 public String findUniqueQuestionName (String originalName) 531 { 532 String name = originalName; 533 int index = 2; 534 while (_hasQuestionName(name)) 535 { 536 name = originalName + "-" + (index++); 537 } 538 return name; 539 } 540 541 private boolean _hasQuestionName (String name) 542 { 543 for (SurveyPage page : getPages()) 544 { 545 if (page.hasQuestion(name)) 546 { 547 return true; 548 } 549 } 550 return false; 551 } 552 553 @Override 554 public Survey copyTo(ModifiableTraversableAmetysObject parent, String name) throws AmetysRepositoryException 555 { 556 Survey survey = parent.createChild(name, "ametys:survey"); 557 558 survey.setTitle(getTitle()); 559 survey.setLabel(getLabel()); 560 561 String description = getDescription(); 562 if (description != null) 563 { 564 survey.setDescription(description); 565 } 566 567 String endingMessage = getEndingMessage(); 568 if (endingMessage != null) 569 { 570 survey.setEndingMessage(endingMessage); 571 } 572 573 copyPictureTo(survey); 574 575 survey.setValidated(false); 576 577 for (SurveyPage surveyPage : getPages()) 578 { 579 surveyPage.copyTo(survey, surveyPage.getName()); 580 } 581 582 // TODO Copy ACL ? 583 584 return survey; 585 } 586 587 @Override 588 public Survey copyTo(ModifiableTraversableAmetysObject parent, String name, List<String> restrictTo) throws AmetysRepositoryException 589 { 590 return copyTo(parent, name); 591 } 592}