001/* 002 * Copyright 2018 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.odfpilotage.helper; 017 018import java.time.LocalDate; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024import java.util.stream.Collectors; 025 026import org.apache.avalon.framework.component.Component; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.commons.lang3.ArrayUtils; 031 032import org.ametys.cms.CmsConstants; 033import org.ametys.cms.ObservationConstants; 034import org.ametys.cms.repository.Content; 035import org.ametys.cms.repository.ModifiableDefaultContent; 036import org.ametys.core.observation.Event; 037import org.ametys.core.observation.ObservationManager; 038import org.ametys.core.right.RightManager; 039import org.ametys.core.right.RightManager.RightResult; 040import org.ametys.core.user.CurrentUserProvider; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.odf.ODFHelper; 043import org.ametys.odf.ProgramItem; 044import org.ametys.odf.coursepart.CoursePart; 045import org.ametys.odf.program.Program; 046import org.ametys.plugins.repository.AmetysObjectResolver; 047import org.ametys.plugins.repository.data.holder.group.ModifiableModelAwareComposite; 048import org.ametys.runtime.model.ModelItem; 049import org.ametys.runtime.plugin.component.AbstractLogEnabled; 050 051/** 052 * Helper for ODF pilotage status 053 */ 054public class PilotageStatusHelper extends AbstractLogEnabled implements Component, Serviceable 055{ 056 /** The component role. */ 057 public static final String ROLE = PilotageStatusHelper.class.getName(); 058 059 /** The super right for mention validation state */ 060 public static final String MENTION_VALIDATION_SUPER_RIGHT_ID = "ODF_Pilotage_Mention_Validated_Super_Rights"; 061 062 /** The super right for orgunit validation state */ 063 public static final String ORGUNIT_VALIDATION_SUPER_RIGHT_ID = "ODF_Pilotage_OrgUnit_Validated_Super_Rights"; 064 065 /** The attribute name for the pilotage composite */ 066 private static final String __PILOTAGE_COMPOSITE = "pilotage"; 067 068 /** The attribute name for the pilotage status */ 069 private static final String __PILOTAGE_STATUS = "pilotage_status"; 070 071 /** The attribute name for the date of the mention validation */ 072 private static final String __MENTION_VALIDATION_DATE = "mention_validation_date"; 073 074 /** The attribute name for the author of the mention validation */ 075 private static final String __MENTION_VALIDATION_AUTHOR = "mention_validation_author"; 076 077 /** The attribute name for the comment of the mention validation */ 078 private static final String __MENTION_VALIDATION_COMMENT = "mention_validation_comment"; 079 080 /** The attribute name for the date of the orgUnit validation */ 081 private static final String __ORGUNIT_VALIDATION_DATE = "orgunit_validation_date"; 082 083 /** The attribute name for the author of the orgUnit validation */ 084 private static final String __ORGUNIT_VALIDATION_AUTHOR = "orgunit_validation_author"; 085 086 /** The attribute name for the comment of the orgUnit validation */ 087 private static final String __ORGUNIT_VALIDATION_COMMENT = "orgunit_validation_comment"; 088 089 /** The attribute name for the date of the CFVU validation */ 090 private static final String __CFVU_VALIDATION_DATE = "cfvu_validation_date"; 091 092 /** The attribute name for the author of the CFVU validation */ 093 private static final String __CFVU_VALIDATION_AUTHOR = "cfvu_validation_author"; 094 095 /** The attribute name for the comment of the CFVU validation */ 096 private static final String __CFVU_VALIDATION_COMMENT = "cfvu_validation_comment"; 097 098 /** The attribute name for the date of the CFVU MCC validation */ 099 private static final String __CFVU_MCC_VALIDATION_DATE = "cfvu_mcc_validation_date"; 100 101 /** The attribute name for the author of the CFVU MCC validation */ 102 private static final String __CFVU_MCC_VALIDATION_AUTHOR = "cfvu_mcc_validation_author"; 103 104 /** The attribute name for the comment of the CFVU MCC validation */ 105 private static final String __CFVU_MCC_VALIDATION_COMMENT = "cfvu_mcc_validation_comment"; 106 107 /** The odf helper */ 108 protected ODFHelper _odfHelper; 109 110 /** The Ametys object resolver */ 111 protected AmetysObjectResolver _resolver; 112 113 /** The right manager */ 114 protected RightManager _rightManager; 115 116 /** The current user provider */ 117 protected CurrentUserProvider _currentUserProvider; 118 119 /** The observation manager */ 120 protected ObservationManager _observationManager; 121 122 /** 123 * Enumeration for the pilotage status 124 */ 125 public enum PilotageStatus 126 { 127 /** State 0 : No status */ 128 NONE, 129 /** State 1 : Mention validated */ 130 MENTION_VALIDATED, 131 /** State 2 : OrgUnit validated */ 132 ORGUNIT_VALIDATED, 133 /** State 3 : CFVU validated */ 134 CFVU_VALIDATED, 135 /** State 4 : CFVU MCC validated */ 136 CFVU_MCC_VALIDATED 137 } 138 139 @Override 140 public void service(ServiceManager manager) throws ServiceException 141 { 142 _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE); 143 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 144 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 145 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 146 _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); 147 } 148 149 /** 150 * Get all program parent from the program item 151 * @param programItem the program item 152 * @return the set of program parent 153 */ 154 public Set<Program> getParentPrograms(ProgramItem programItem) 155 { 156 Set<Program> parentPrograms = new HashSet<>(); 157 if (programItem instanceof Program) 158 { 159 parentPrograms.add((Program) programItem); 160 return parentPrograms; 161 } 162 163 List<ProgramItem> parents = _odfHelper.getParentProgramItems(programItem); 164 for (ProgramItem parent : parents) 165 { 166 if (parent instanceof Program) 167 { 168 parentPrograms.add((Program) parent); 169 } 170 else 171 { 172 parentPrograms.addAll(getParentPrograms(parent)); 173 } 174 } 175 176 return parentPrograms; 177 } 178 179 /** 180 * Get all program parent with a pilotage status from the program item 181 * @param programItem the program item 182 * @return the set of program parent 183 */ 184 public Set<Program> getParentProgramsWithPilotageStatus(ProgramItem programItem) 185 { 186 Set<Program> parentPrograms = new HashSet<>(); 187 for (Program parent : getParentPrograms(programItem)) 188 { 189 PilotageStatus pilotageStatus = getPilotageStatus(parent); 190 if (!pilotageStatus.equals(PilotageStatus.NONE)) 191 { 192 parentPrograms.add(parent); 193 } 194 } 195 196 return parentPrograms; 197 } 198 199 /** 200 * Return true if the current user has the edit super right depend on the pilotage status of the program 201 * @param program the program 202 * @return true if the user has the super right 203 */ 204 public boolean hasEditSuperRight(Program program) 205 { 206 PilotageStatus pilotageStatus = getPilotageStatus(program); 207 208 UserIdentity user = _currentUserProvider.getUser(); 209 switch (pilotageStatus) 210 { 211 case NONE: 212 return true; 213 case MENTION_VALIDATED: 214 return _rightManager.hasRight(user, MENTION_VALIDATION_SUPER_RIGHT_ID, program).equals(RightResult.RIGHT_ALLOW); 215 case ORGUNIT_VALIDATED: 216 return _rightManager.hasRight(user, ORGUNIT_VALIDATION_SUPER_RIGHT_ID, program).equals(RightResult.RIGHT_ALLOW); 217 case CFVU_MCC_VALIDATED: 218 case CFVU_VALIDATED: 219 default: 220 return false; 221 } 222 } 223 224 /** 225 * Compare two programs depends on their pilotage status 226 * Pilotage status order : NONE lower than MENTION_VALIDATED lower than ORGUNIT_VALIDATED lower than CFVU_VALIDATED lower than CFVU_VALIDATED lower than CFVU_MCC_VALIDATED 227 * -1 if pilotage status of program 1 is lower than pilotage status of program 2 228 * 0 if they have the same pilotage status 229 * 1 if pilotage status of program 1 is higher than pilotage status of program 2 230 * -2 if we don't know 231 * @param program1 program 1 232 * @param program2 progam 2 233 * @return the int compare number 234 */ 235 public int comparePilotageStatus(Program program1, Program program2) 236 { 237 PilotageStatus pilotageStatus1 = getPilotageStatus(program1); 238 PilotageStatus pilotageStatus2 = getPilotageStatus(program2); 239 240 switch (pilotageStatus1) 241 { 242 case NONE: 243 return PilotageStatus.NONE.equals(pilotageStatus2) ? 0 : 1; 244 case MENTION_VALIDATED: 245 if (PilotageStatus.NONE.equals(pilotageStatus2)) 246 { 247 return -1; 248 } 249 else 250 { 251 return PilotageStatus.MENTION_VALIDATED.equals(pilotageStatus2) ? 0 : 1; 252 } 253 case ORGUNIT_VALIDATED: 254 if (PilotageStatus.NONE.equals(pilotageStatus2) || PilotageStatus.MENTION_VALIDATED.equals(pilotageStatus2)) 255 { 256 return -1; 257 } 258 else 259 { 260 return PilotageStatus.ORGUNIT_VALIDATED.equals(pilotageStatus2) ? 0 : 1; 261 } 262 case CFVU_VALIDATED: 263 if (PilotageStatus.CFVU_MCC_VALIDATED.equals(pilotageStatus2)) 264 { 265 return 1; 266 } 267 else 268 { 269 return PilotageStatus.CFVU_VALIDATED.equals(pilotageStatus2) ? 0 : -1; 270 } 271 case CFVU_MCC_VALIDATED: 272 return PilotageStatus.CFVU_MCC_VALIDATED.equals(pilotageStatus2) ? 0 : -1; 273 default: 274 break; 275 } 276 277 return -2; 278 } 279 280 /** 281 * Get parent program or it self from program item with the higher pilotage status. 282 * Program with pilotage status NONE are ignored, so can be null if there are no program with active pilotage status. 283 * @param coursePart the course part 284 * @return the program parent 285 */ 286 public Program getParentProgramWithHigherPilotageStatus(CoursePart coursePart) 287 { 288 return _getParentProgramWithHigherPilotageStatus( 289 coursePart.getCourses() 290 .stream() 291 .map(this::getParentProgramsWithPilotageStatus) 292 .flatMap(Set::stream) 293 .collect(Collectors.toSet()) 294 ); 295 } 296 297 /** 298 * Get parent program or it self from program item with the higher pilotage status. 299 * Program with pilotage status NONE are ignored, so can be null if there are no program with active pilotage status. 300 * @param programItem the program item 301 * @return the program parent 302 */ 303 public Program getParentProgramWithHigherPilotageStatus(ProgramItem programItem) 304 { 305 return _getParentProgramWithHigherPilotageStatus(getParentProgramsWithPilotageStatus(programItem)); 306 } 307 308 private Program _getParentProgramWithHigherPilotageStatus(Set<Program> parentProgramsWithPilotageStatus) 309 { 310 Program parentProgram = null; 311 for (Program program : parentProgramsWithPilotageStatus) 312 { 313 if (parentProgram == null || comparePilotageStatus(parentProgram, program) == 1) 314 { 315 parentProgram = program; 316 } 317 } 318 319 return parentProgram; 320 } 321 322 /** 323 * Get the pilotage information status for a client side element. 324 * The button is enabled if the pilotage status of root programs is NONE or if the current user has super edit right on root program of higher status 325 * @param contentId the content id 326 * @return the pilotage information 327 */ 328 public Map<String, Object> getPilotageButtonInfo(String contentId) 329 { 330 Map<String, Object> contentParams = new HashMap<>(); 331 Content content = _resolver.resolveById(contentId); 332 if (content instanceof ProgramItem) 333 { 334 ProgramItem programItem = (ProgramItem) content; 335 336 // Get parent program (or itself) with the higher pilotage status (program with no pilotage status are ignored) 337 Program parentProgramWithHigherPilotageStatus = getParentProgramWithHigherPilotageStatus(programItem); 338 boolean noParentProgramWithActivePilotageStatus = parentProgramWithHigherPilotageStatus == null; 339 340 contentParams.put("isEnabled", noParentProgramWithActivePilotageStatus || hasEditSuperRight(parentProgramWithHigherPilotageStatus)); 341 342 if (!noParentProgramWithActivePilotageStatus) 343 { 344 // Get parent programs (or itself) which have an active pilotage status (!= NONE) 345 Set<Program> parentPrograms = getParentProgramsWithPilotageStatus(programItem); 346 List<String> programTitles = parentPrograms.stream() 347 .map(p -> p.getTitle()) 348 .collect(Collectors.toList()); 349 350 contentParams.put("programTitles", programTitles); 351 } 352 } 353 else 354 { 355 contentParams.put("isEnabled", true); 356 } 357 358 return contentParams; 359 } 360 361 /** 362 * Get the pilotage status of the content 363 * @param content the content 364 * @return the pilotage status 365 */ 366 public PilotageStatus getPilotageStatus(Content content) 367 { 368 String pilotageStatusDataPath = __PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __PILOTAGE_STATUS; 369 String status = content.getValue(pilotageStatusDataPath, false, PilotageStatus.NONE.name()); 370 return PilotageStatus.valueOf(status); 371 } 372 373 /** 374 * Send a notification with the content modified event. 375 * @param content The content to notify on 376 */ 377 protected void _notifyPilotageWorkflowModification(Content content) 378 { 379 Map<String, Object> eventParams = new HashMap<>(); 380 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 381 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId()); 382 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_MODIFIED, _currentUserProvider.getUser(), eventParams)); 383 } 384 385 /** 386 * Set the validation attribute (date, login, comment) to the content 387 * @param content the content 388 * @param validationDate the validation date 389 * @param user the user 390 * @param comment the comment 391 * @param status the pilotage status 392 */ 393 public void setValidationAttribute(ModifiableDefaultContent content, LocalDate validationDate, UserIdentity user, String comment, PilotageStatus status) 394 { 395 boolean hasChanges = false; 396 switch (status) 397 { 398 case NONE : 399 // Do nothing 400 break; 401 case MENTION_VALIDATED : 402 hasChanges = setMentionValidationAttribute(content, validationDate, user, comment); 403 break; 404 case ORGUNIT_VALIDATED : 405 hasChanges = setOrgUnitValidationAttribute(content, validationDate, user, comment); 406 break; 407 case CFVU_VALIDATED : 408 hasChanges = setCFVUValidationAttribute(content, validationDate, user, comment); 409 break; 410 case CFVU_MCC_VALIDATED : 411 hasChanges = setCFVUMCCValidationAttribute(content, validationDate, user, comment); 412 break; 413 default : 414 getLogger().error("{} is an unknown pilotage status", status); 415 } 416 417 if (hasChanges) 418 { 419 _notifyPilotageWorkflowModification(content); 420 } 421 } 422 423 /** 424 * Remove the validation attribute from the content 425 * @param content the content 426 * @param status the pilotage status 427 */ 428 public void removePilotageStatus(ModifiableDefaultContent content, PilotageStatus status) 429 { 430 boolean hasChanges = false; 431 switch (status) 432 { 433 case NONE : 434 // Do nothing 435 break; 436 case MENTION_VALIDATED : 437 hasChanges = removeMentionValidationAttribute(content); 438 break; 439 case ORGUNIT_VALIDATED : 440 hasChanges = removeOrgUnitValidationAttribute(content); 441 break; 442 case CFVU_VALIDATED : 443 hasChanges = removeCFVUValidationAttribute(content); 444 break; 445 case CFVU_MCC_VALIDATED : 446 hasChanges = removeCFVUMCCValidationAttribute(content); 447 break; 448 default : 449 getLogger().error("{} is an unknown pilotage status", status); 450 } 451 452 if (hasChanges) 453 { 454 _notifyPilotageWorkflowModification(content); 455 } 456 } 457 458 /** 459 * Set the validation attribute for 'mention validated' state 460 * @param content the content 461 * @param validationDate the validation date 462 * @param user the user 463 * @param comment the comment 464 * @return <code>true</code> if the content has changed. 465 */ 466 public boolean setMentionValidationAttribute(ModifiableDefaultContent content, LocalDate validationDate, UserIdentity user, String comment) 467 { 468 ModifiableModelAwareComposite composite = content.getComposite(__PILOTAGE_COMPOSITE, true); 469 composite.setValue(__MENTION_VALIDATION_DATE, validationDate); 470 composite.setValue(__MENTION_VALIDATION_AUTHOR, user); 471 composite.setValue(__MENTION_VALIDATION_COMMENT, comment); 472 473 composite.setValue(__PILOTAGE_STATUS, PilotageStatus.MENTION_VALIDATED.name()); 474 475 return saveContent(content); 476 } 477 478 479 /** 480 * Remove validation attribute for 'mention validated' state 481 * @param content the content 482 * @return <code>true</code> if the content has changed. 483 */ 484 public boolean removeMentionValidationAttribute(ModifiableDefaultContent content) 485 { 486 // Remove the first step 487 return removePilotageWorkflow(content); 488 } 489 490 /** 491 * Set the validation attribute for 'orgunit validated' state 492 * @param content the content 493 * @param validationDate the validation date 494 * @param user the user 495 * @param comment the comment 496 * @return <code>true</code> if the content has changed. 497 */ 498 public boolean setOrgUnitValidationAttribute(ModifiableDefaultContent content, LocalDate validationDate, UserIdentity user, String comment) 499 { 500 ModifiableModelAwareComposite composite = content.getComposite(__PILOTAGE_COMPOSITE, true); 501 composite.setValue(__ORGUNIT_VALIDATION_DATE, validationDate); 502 composite.setValue(__ORGUNIT_VALIDATION_AUTHOR, user); 503 composite.setValue(__ORGUNIT_VALIDATION_COMMENT, comment); 504 505 composite.setValue(__PILOTAGE_STATUS, PilotageStatus.ORGUNIT_VALIDATED.name()); 506 507 return saveContent(content); 508 } 509 510 /** 511 * Remove validation attribute for 'orgunit validated' state 512 * @param content the content 513 * @return <code>true</code> if the content has changed. 514 */ 515 public boolean removeOrgUnitValidationAttribute(ModifiableDefaultContent content) 516 { 517 ModifiableModelAwareComposite compositeMetadata = content.getComposite(__PILOTAGE_COMPOSITE, true); 518 compositeMetadata.removeValue(__ORGUNIT_VALIDATION_DATE); 519 compositeMetadata.removeValue(__ORGUNIT_VALIDATION_AUTHOR); 520 compositeMetadata.removeValue(__ORGUNIT_VALIDATION_COMMENT); 521 522 compositeMetadata.setValue(__PILOTAGE_STATUS, PilotageStatus.MENTION_VALIDATED.name()); 523 524 return saveContent(content); 525 } 526 527 /** 528 * Set the validation attribute for 'CFVU validated' state 529 * @param content the content 530 * @param validationDate the validation date 531 * @param user the login 532 * @param comment the comment 533 * @return <code>true</code> if the content has changed. 534 */ 535 public boolean setCFVUValidationAttribute(ModifiableDefaultContent content, LocalDate validationDate, UserIdentity user, String comment) 536 { 537 ModifiableModelAwareComposite composite = content.getComposite(__PILOTAGE_COMPOSITE, true); 538 composite.setValue(__CFVU_VALIDATION_DATE, validationDate); 539 composite.setValue(__CFVU_VALIDATION_AUTHOR, user); 540 composite.setValue(__CFVU_VALIDATION_COMMENT, comment); 541 542 composite.setValue(__PILOTAGE_STATUS, PilotageStatus.CFVU_VALIDATED.name()); 543 544 return saveContent(content); 545 } 546 547 /** 548 * Remove validation attribute for 'CFVU validated' state 549 * @param content the content 550 * @return <code>true</code> if the content has changed. 551 */ 552 public boolean removeCFVUValidationAttribute(ModifiableDefaultContent content) 553 { 554 ModifiableModelAwareComposite composite = content.getComposite(__PILOTAGE_COMPOSITE, true); 555 composite.removeValue(__CFVU_VALIDATION_DATE); 556 composite.removeValue(__CFVU_VALIDATION_AUTHOR); 557 composite.removeValue(__CFVU_VALIDATION_COMMENT); 558 559 composite.setValue(__PILOTAGE_STATUS, PilotageStatus.ORGUNIT_VALIDATED.name()); 560 561 return saveContent(content); 562 } 563 564 /** 565 * Set the validation attribute for 'CFVU MCC validated' state 566 * @param content the content 567 * @param validationDate the validation date 568 * @param user the user 569 * @param comment the comment 570 * @return <code>true</code> if the content has changed. 571 */ 572 public boolean setCFVUMCCValidationAttribute(ModifiableDefaultContent content, LocalDate validationDate, UserIdentity user, String comment) 573 { 574 ModifiableModelAwareComposite composite = content.getComposite(__PILOTAGE_COMPOSITE, true); 575 composite.setValue(__CFVU_MCC_VALIDATION_DATE, validationDate); 576 composite.setValue(__CFVU_MCC_VALIDATION_AUTHOR, user); 577 composite.setValue(__CFVU_MCC_VALIDATION_COMMENT, comment); 578 579 composite.setValue(__PILOTAGE_STATUS, PilotageStatus.CFVU_MCC_VALIDATED.name()); 580 581 return saveContent(content); 582 } 583 584 /** 585 * Remove validation attribute for 'CFVU MCC validated' state 586 * @param content the content 587 * @return <code>true</code> if the content has changed. 588 */ 589 public boolean removeCFVUMCCValidationAttribute(ModifiableDefaultContent content) 590 { 591 ModifiableModelAwareComposite composite = content.getComposite(__PILOTAGE_COMPOSITE, true); 592 composite.removeValue(__CFVU_MCC_VALIDATION_DATE); 593 composite.removeValue(__CFVU_MCC_VALIDATION_AUTHOR); 594 composite.removeValue(__CFVU_MCC_VALIDATION_COMMENT); 595 596 composite.setValue(__PILOTAGE_STATUS, PilotageStatus.CFVU_VALIDATED.name()); 597 598 return saveContent(content); 599 } 600 601 /** 602 * Get mention validation date 603 * @param content the content 604 * @return the validation date 605 */ 606 public LocalDate getMentionValidationDate(Content content) 607 { 608 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __MENTION_VALIDATION_DATE); 609 } 610 611 /** 612 * Get mention validation comment 613 * @param content the content 614 * @return the validation comment 615 */ 616 public String getMentionValidationComment(Content content) 617 { 618 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __MENTION_VALIDATION_COMMENT); 619 } 620 621 /** 622 * Get mention validation author 623 * @param content the content 624 * @return the validation author 625 */ 626 public UserIdentity getMentionValidationAuthor(Content content) 627 { 628 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __MENTION_VALIDATION_AUTHOR); 629 } 630 631 /** 632 * Get orgUnit validation date 633 * @param content the content 634 * @return the validation date 635 */ 636 public LocalDate getOrgUnitValidationDate(Content content) 637 { 638 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __ORGUNIT_VALIDATION_DATE); 639 } 640 641 /** 642 * Get orgUnit validation comment 643 * @param content the content 644 * @return the validation comment 645 */ 646 public String getOrgUnitValidationComment(Content content) 647 { 648 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __ORGUNIT_VALIDATION_COMMENT); 649 } 650 651 /** 652 * Get orgUnit validation author 653 * @param content the content 654 * @return the validation author 655 */ 656 public UserIdentity getOrgUnitValidationAuthor(Content content) 657 { 658 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __ORGUNIT_VALIDATION_AUTHOR); 659 } 660 661 /** 662 * Get CFVU validation date 663 * @param content the content 664 * @return the validation date 665 */ 666 public LocalDate getCFVUValidationDate(Content content) 667 { 668 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __CFVU_VALIDATION_DATE); 669 } 670 671 /** 672 * Get CFVU validation comment 673 * @param content the content 674 * @return the validation comment 675 */ 676 public String getCFVUValidationComment(Content content) 677 { 678 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __CFVU_VALIDATION_COMMENT); 679 } 680 681 /** 682 * Get CFVU validation author 683 * @param content the content 684 * @return the validation author 685 */ 686 public UserIdentity getCFVUValidationAuthor(Content content) 687 { 688 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __CFVU_VALIDATION_AUTHOR); 689 } 690 691 /** 692 * Get CFVU MMC validation date 693 * @param content the content 694 * @return the validation date 695 */ 696 public LocalDate getCFVUMCCValidationDate(Content content) 697 { 698 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __CFVU_MCC_VALIDATION_DATE); 699 } 700 701 /** 702 * Get CFVU MCC validation comment 703 * @param content the content 704 * @return the validation comment 705 */ 706 public String getCFVUMCCValidationComment(Content content) 707 { 708 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __CFVU_MCC_VALIDATION_COMMENT); 709 } 710 711 /** 712 * Get CFVU MCC validation author 713 * @param content the content 714 * @return the validation author 715 */ 716 public UserIdentity getCFVUMCCValidationAuthor(Content content) 717 { 718 return content.getValue(__PILOTAGE_COMPOSITE + ModelItem.ITEM_PATH_SEPARATOR + __CFVU_MCC_VALIDATION_AUTHOR); 719 } 720 721 /** 722 * Remove the pilotage workflow metadata. 723 * @param content The content to clean 724 * @return <code>true</code> if the content has changed 725 */ 726 public boolean removePilotageWorkflow(ModifiableDefaultContent content) 727 { 728 content.removeValue(__PILOTAGE_COMPOSITE); 729 return saveContent(content); 730 } 731 732 /** 733 * Save the content if needed, add a version (checkpoint) and move the Live label if the last version was validated. 734 * @param content The content to save 735 * @return <code>true</code> if the content has changed 736 */ 737 protected boolean saveContent(ModifiableDefaultContent content) 738 { 739 if (content.needsSave()) 740 { 741 boolean currentVersionIsLive = ArrayUtils.contains(content.getLabels(), CmsConstants.LIVE_LABEL); 742 743 content.saveChanges(); 744 content.checkpoint(); 745 746 // Move the Live label if the last version was validated. 747 if (currentVersionIsLive) 748 { 749 content.addLabel(CmsConstants.LIVE_LABEL, true); 750 } 751 752 return true; 753 } 754 755 return false; 756 } 757}