001/* 002 * Copyright 2022 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 */ 016 017package org.ametys.plugins.odfsync.pegase.ws.structure; 018 019import java.io.IOException; 020import java.math.BigDecimal; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Optional; 026import java.util.Set; 027import java.util.regex.Pattern; 028import java.util.stream.Collectors; 029import java.util.stream.Stream; 030 031import org.apache.avalon.framework.activity.Initializable; 032import org.apache.avalon.framework.component.Component; 033import org.apache.avalon.framework.service.ServiceException; 034import org.apache.avalon.framework.service.ServiceManager; 035import org.apache.commons.lang3.StringUtils; 036 037import org.ametys.cms.data.ContentValue; 038import org.ametys.cms.data.RichText; 039import org.ametys.cms.data.RichTextHelper; 040import org.ametys.cms.repository.Content; 041import org.ametys.odf.ODFHelper; 042import org.ametys.odf.ProgramItem; 043import org.ametys.odf.course.Course; 044import org.ametys.odf.course.CourseFactory; 045import org.ametys.odf.courselist.CourseList; 046import org.ametys.odf.enumeration.OdfReferenceTableEntry; 047import org.ametys.odf.enumeration.OdfReferenceTableHelper; 048import org.ametys.odf.program.AbstractProgram; 049import org.ametys.odf.program.Container; 050import org.ametys.odf.program.Program; 051import org.ametys.odf.program.ProgramFactory; 052import org.ametys.odf.program.ProgramPart; 053import org.ametys.odf.program.SubProgram; 054import org.ametys.plugins.odfsync.export.AbstractExportStructure; 055import org.ametys.plugins.odfsync.export.ExportReport; 056import org.ametys.plugins.odfsync.export.ExportReport.ExportStatus; 057import org.ametys.plugins.odfsync.export.ExportReport.ProblemTypes; 058import org.ametys.plugins.odfsync.pegase.ws.PegaseApiManager; 059import org.ametys.plugins.odfsync.pegase.ws.PegaseExportException; 060import org.ametys.runtime.config.Config; 061import org.ametys.runtime.i18n.I18nizableText; 062import org.ametys.runtime.model.ElementDefinition; 063 064import fr.pcscol.pegase.cof.ApiException; 065import fr.pcscol.pegase.cof.model.Enfant; 066import fr.pcscol.pegase.cof.model.EnfantDetails; 067import fr.pcscol.pegase.cof.model.Formation; 068import fr.pcscol.pegase.cof.model.FormationRef; 069import fr.pcscol.pegase.cof.model.FormationTypeFormation; 070import fr.pcscol.pegase.cof.model.Groupement; 071import fr.pcscol.pegase.cof.model.ObjetFormation; 072import fr.pcscol.pegase.cof.model.ObjetFormationType; 073import fr.pcscol.pegase.cof.model.ObjetMaquette; 074import fr.pcscol.pegase.cof.model.Pageable; 075import fr.pcscol.pegase.cof.model.PagedObjetMaquette; 076import fr.pcscol.pegase.cof.model.Ref; 077import fr.pcscol.pegase.cof.model.ValeurNum; 078 079/** 080 * The structure to export the program in Pegase 081 */ 082public class PegaseProgramStructure extends AbstractExportStructure implements Component, Initializable 083{ 084 /** Role */ 085 public static final String ROLE = PegaseProgramStructure.class.getName(); 086 087 /** The attribute name for the code Pégase */ 088 public static final String CODE_PEGASE_ATTRIBUTE_NAME = "codePegase"; 089 090 /* Constants */ 091 private static final String __PEGASE_SYNC_CODE = "pegaseSyncCode"; 092 private static final Pattern __PROGRAM_CODE_PATTERN = Pattern.compile("^[A-Z0-9\\-]{3,25}(/[1-9][0-9]*)?$"); 093 private static final Pattern __DEFAULT_CODE_PATTERN = Pattern.compile("^[A-Z0-9\\-]{3,25}$"); 094 private static final String __CODE_FORMATION_DIPLOMANTE = "0"; 095 private static final Map<String, Set<String>> __MANDATORY_ATTRIBUTES_BY_CONTENT_TYPE = new HashMap<>(); 096 static 097 { 098 __MANDATORY_ATTRIBUTES_BY_CONTENT_TYPE.put( 099 ProgramFactory.PROGRAM_CONTENT_TYPE, 100 Set.of( 101 AbstractProgram.DOMAIN, 102 AbstractProgram.EDUCATION_KIND, 103 AbstractProgram.DEGREE, 104 AbstractProgram.LEVEL, 105 AbstractProgram.RNCP_LEVEL 106 ) 107 ); 108 __MANDATORY_ATTRIBUTES_BY_CONTENT_TYPE.put( 109 CourseFactory.COURSE_CONTENT_TYPE, 110 Set.of(Course.COURSE_TYPE) 111 ); 112 __MANDATORY_ATTRIBUTES_BY_CONTENT_TYPE.put( 113 OdfReferenceTableHelper.DEGREE, 114 Set.of( 115 "degreeNature", 116 "cursus" 117 ) 118 ); 119 } 120 121 /* Components */ 122 private PegaseApiManager _pegaseApiManager; 123 private ODFHelper _odfHelper; 124 private RichTextHelper _richTextHelper; 125 126 /* Pégase configuration */ 127 private boolean _isActive; 128 private String _structureCode; 129 private boolean _trustAmetys; 130 131 @Override 132 public void service(ServiceManager manager) throws ServiceException 133 { 134 super.service(manager); 135 136 _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE); 137 _richTextHelper = (RichTextHelper) manager.lookup(RichTextHelper.ROLE); 138 _pegaseApiManager = (PegaseApiManager) manager.lookup(PegaseApiManager.ROLE); 139 } 140 141 public void initialize() throws Exception 142 { 143 _isActive = Config.getInstance().getValue("pegase.activate", true, false); 144 if (_isActive) 145 { 146 _structureCode = Config.getInstance().getValue("pegase.structure.code"); 147 _trustAmetys = Config.getInstance().getValue("pegase.trust", true, false); 148 } 149 } 150 151 private String _getPegaseCodeOrCode(Content content) 152 { 153 String code = content.getValue(CODE_PEGASE_ATTRIBUTE_NAME); 154 if (StringUtils.isEmpty(code)) 155 { 156 code = content.getValue(OdfReferenceTableEntry.CODE); 157 } 158 return code; 159 } 160 161 private String _getPegaseCodeOrCodeOfAttribute(Content content, String attributeName) 162 { 163 return _getContentValue(content, attributeName) 164 .map(this::_getPegaseCodeOrCode) 165 .orElse(null); 166 } 167 168 private void _addMandatoryDataPathAndReport(Content content, String dataPath, ExportReport report) 169 { 170 I18nizableText invalidMessage = new I18nizableText( 171 "plugin.odf-sync", 172 "PLUGINS_ODF_SYNC_EXPORT_PEGASE_MANDATORY_FIELD", 173 Map.of("fieldName", content.getDefinition(dataPath).getLabel()) 174 ); 175 report.addInvalidDataPath(content, invalidMessage); 176 } 177 178 private Optional<Content> _getContentValue(Content content, String attributeName) 179 { 180 return Optional.of(attributeName) 181 .map(content::<ContentValue>getValue) 182 .flatMap(ContentValue::getContentIfExists); 183 } 184 185 private Stream<Content> _getContentValues(Content content, String attributeName) 186 { 187 return Optional.of(attributeName) 188 .map(content::<ContentValue[]>getValue) 189 .map(Stream::of) 190 .orElseGet(Stream::of) 191 .map(ContentValue::getContentIfExists) 192 .filter(Optional::isPresent) 193 .map(Optional::get); 194 } 195 196 /** 197 * Checks if the program has all the required fields, their Pegase correspondence and that the program has a valid structure 198 * @param program the program 199 * @param report the Pegase export report 200 */ 201 @Override 202 public void checkProgram(Program program, ExportReport report) 203 { 204 if (!_isActive) 205 { 206 throw new UnsupportedOperationException("Pégase is not active in the configuration, you cannot check the program for the export."); 207 } 208 209 try 210 { 211 _checkAttributes(program, report); 212 213 if (program.hasValue(__PEGASE_SYNC_CODE)) 214 { 215 String codeAndVersion = program.getValue(__PEGASE_SYNC_CODE); 216 Map<String, Object> dataCodeAndVersion = _getCodeAndVersion(codeAndVersion); 217 String code = (String) dataCodeAndVersion.get("code"); 218 String versionString = (String) dataCodeAndVersion.get("version"); 219 220 // If the code is not missing, check if it is valid 221 if (StringUtils.isNotBlank(versionString)) 222 { 223 BigDecimal version = new BigDecimal(versionString); 224 _checkProgramVersionCoherence(report, code, version); 225 } 226 } 227 228 // If the education kind has a Pegase correspondence and is of code "0" (diplomante) 229 if (__CODE_FORMATION_DIPLOMANTE.equals(_getPegaseCodeOrCodeOfAttribute(program, AbstractProgram.EDUCATION_KIND))) 230 { 231 _checkProgramDiplomanteField(program, report); 232 } 233 234 _checkChildren(program, report); 235 236 } 237 catch (IOException e) 238 { 239 report.updateStatus(ExportStatus.ERROR); 240 getLogger().error("Le jeton d'authentification à Pégase n'a pas pu être récupéré", e); 241 } 242 } 243 244 private void _checkAttributes(Content content, ExportReport report) 245 { 246 if (content instanceof ProgramItem) 247 { 248 if (!content.hasValue(__PEGASE_SYNC_CODE)) 249 { 250 _addMandatoryDataPathAndReport(content, __PEGASE_SYNC_CODE, report); 251 } 252 else if (content instanceof Program) 253 { 254 if (!_matches(__PROGRAM_CODE_PATTERN, content, __PEGASE_SYNC_CODE)) 255 { 256 report.addInvalidDataPath(content, new I18nizableText("plugin.odf-sync", "PLUGINS_ODF_SYNC_EXPORT_PEGASE_INVALID_CODE_PROGRAM")); 257 } 258 } 259 else if (!_matches(__DEFAULT_CODE_PATTERN, content, __PEGASE_SYNC_CODE)) 260 { 261 report.addInvalidDataPath(content, new I18nizableText("plugin.odf-sync", "PLUGINS_ODF_SYNC_EXPORT_PEGASE_INVALID_CODE_DEFAULT")); 262 } 263 } 264 265 String contentType = content.getTypes()[0]; 266 Set<String> mandatoryAttributes = __MANDATORY_ATTRIBUTES_BY_CONTENT_TYPE.getOrDefault(contentType, Set.of()); 267 for (String attribute : mandatoryAttributes) 268 { 269 if (!content.hasValue(attribute)) 270 { 271 _addMandatoryDataPathAndReport(content, attribute, report); 272 } 273 } 274 } 275 276 private boolean _matches(Pattern regex, Content content, String attributeName) 277 { 278 return regex.matcher(content.getValue(attributeName)).matches(); 279 } 280 281 private void _checkProgramVersionCoherence(ExportReport report, String code, BigDecimal version) throws IOException 282 { 283 // If the Program already exist in this version 284 ObjetMaquette objetMaquette = _getObjetMaquetteIfAlreadyExists(code, version); 285 286 Long versionLong = version.longValue(); 287 if (objetMaquette != null) 288 { 289 // If it is not of type "FORMATION" or if it is not editable 290 if (!objetMaquette.getType().getCode().equals("FORMATION") || !objetMaquette.getModifiable()) 291 { 292 report.setStatus(ExportStatus.NON_EDITABLE_PROGRAM_ALREADY_EXISTS); 293 } 294 } 295 296 // If nothing was found for this code and version, and the version is not null 297 else 298 { 299 // Get the element for this code without requesting a specific version 300 objetMaquette = _getObjetMaquetteIfAlreadyExists(code); 301 302 // If something was found and it's a Program 303 if (objetMaquette != null && objetMaquette.getType().getCode().equals("FORMATION")) 304 { 305 // Check if the version is compatible (versionFound == versionRequested or versionFound == versionRequested - 1) 306 Long versionFound = Long.valueOf(objetMaquette.getDetail().getFormation().getVersion()); 307 if (versionLong != versionFound && versionLong != (versionFound + 1)) 308 { 309 report.setStatus(ExportStatus.PROGRAM_IMPOSSIBLE_VERSION); 310 } 311 } 312 313 // If something was found but it is not a Program 314 else if (objetMaquette != null && !objetMaquette.getType().getCode().equals("FORMATION")) 315 { 316 report.setStatus(ExportStatus.NON_EDITABLE_PROGRAM_ALREADY_EXISTS); 317 } 318 319 // If nothing was found, check if the version requested is one 320 else if (versionLong != 1) 321 { 322 report.setStatus(ExportStatus.PROGRAM_IMPOSSIBLE_VERSION); 323 } 324 } 325 } 326 327 private void _checkProgramDiplomanteField(Program program, ExportReport report) 328 { 329 // dataDegree which contains degree, cursus and degreeNature 330 _getContentValue(program, AbstractProgram.DEGREE) 331 .ifPresent(degree -> _checkAttributes(degree, report)); 332 } 333 334 private void _checkChildren(ProgramItem programItem, ExportReport report) 335 { 336 for (ProgramItem child : _odfHelper.getChildProgramItems(programItem)) 337 { 338 _checkProgramItem(child, report); 339 } 340 } 341 342 private void _checkChildrenOfYear(Container container, ExportReport report) 343 { 344 container.getProgramPartChildren() 345 .stream() 346 .filter(Container.class::isInstance) 347 .map(Container.class::cast) 348 .filter(c -> "annee".equals(getContainerNatureCode(c))) 349 .forEach( 350 child -> 351 { 352 report.setStatus(ExportStatus.CONTENT_STRUCTURE_INVALID); 353 getLogger().error("L'élément {} (Année) ne peut avoir comme enfant une année : {}", container.getTitle(), child.getTitle()); 354 } 355 ); 356 } 357 358 private void _checkChildrenOfSemester(Container container, ExportReport report) 359 { 360 container.getProgramPartChildren() 361 .stream() 362 .filter(Container.class::isInstance) 363 .map(Container.class::cast) 364 .filter(c -> 365 { 366 String nature = getContainerNatureCode(c); 367 return "annee".equals(nature) || "semestre".equals(nature); 368 }) 369 .forEach( 370 child -> 371 { 372 report.setStatus(ExportStatus.CONTENT_STRUCTURE_INVALID); 373 getLogger().error("L'élément {} (Semestre) ne peut avoir comme enfant une année ou un semestre : {}", container.getTitle(), child.getTitle()); 374 } 375 ); 376 } 377 378 private void _checkChildrenOfSubProgram(SubProgram subProgram, ExportReport report) 379 { 380 for (ProgramItem child : _odfHelper.getChildProgramItems(subProgram)) 381 { 382 // If the child is a SubProgram, then it is not compatible with the parent : SubProgram 383 if (child instanceof SubProgram childSubProgram) 384 { 385 report.setStatus(ExportStatus.CONTENT_STRUCTURE_INVALID); 386 getLogger().error("L'élément {} (Parcours) ne peut avoir comme enfant un parcours : {}", subProgram.getTitle(), childSubProgram.getTitle()); 387 } 388 389 _checkProgramItem(child, report); 390 } 391 } 392 393 private void _checkProgramItem(ProgramItem programItem, ExportReport report) 394 { 395 _checkAttributes((Content) programItem, report); 396 397 if (programItem instanceof CourseList couresList) 398 { 399 // Check if the courseList has children, because a Pegase group has to have at least one child 400 if (!couresList.hasCourses()) 401 { 402 getLogger().error("L'élément {} n'a pas d'enfant alors qu'il aurait dû être exporté en tant que groupement", couresList.getTitle()); 403 report.setStatus(ExportStatus.CONTENT_STRUCTURE_INVALID); 404 } 405 } 406 else if (programItem instanceof Container container) 407 { 408 String childNatureCode = getContainerNatureCode(container); 409 410 if ("annee".equals(childNatureCode)) 411 { 412 _checkChildrenOfYear(container, report); 413 } 414 else if ("semestre".equals(childNatureCode)) 415 { 416 _checkChildrenOfSemester(container, report); 417 } 418 else 419 { 420 // Check if the container (without a nature) has children, because a Pegase group has to have at least one child 421 if (!container.hasProgramPartChildren()) 422 { 423 getLogger().error("L'élément {} n'a pas d'enfant alors qu'il aurait dû être exporté en tant que groupement", container.getTitle()); 424 report.setStatus(ExportStatus.CONTENT_STRUCTURE_INVALID); 425 } 426 } 427 } 428 429 else if (programItem instanceof SubProgram subProgram) 430 { 431 _checkChildrenOfSubProgram(subProgram, report); 432 } 433 434 for (ProgramItem child : _odfHelper.getChildProgramItems(programItem)) 435 { 436 _checkProgramItem(child, report); 437 } 438 } 439 440 private ObjetMaquette _getObjetMaquetteIfAlreadyExists(String code) throws IOException 441 { 442 return _getObjetMaquetteIfAlreadyExists(code, null); 443 } 444 445 /** 446 * Get the latest version of an objetMaquette if it exists 447 * @param code The code wanted 448 * @param version The version wanted 449 * @return The ObjetMaquette wanted or null if it was not found 450 * @throws IOException If an error occurs while retrieving the token 451 */ 452 private ObjetMaquette _getObjetMaquetteIfAlreadyExists(String code, BigDecimal version) throws IOException 453 { 454 Pageable pageable = new Pageable(); 455 pageable.setPage(0); 456 pageable.setTaille(10); 457 pageable.setTri(List.of("version,desc")); 458 459 PagedObjetMaquette pagedObjetMaquette; 460 try 461 { 462 // Get the objetMaquette for the code and the version 463 pagedObjetMaquette = _pegaseApiManager.getObjetsMaquetteApi().lireListeObjetsMaquette(_structureCode, null, null, null, code, null, null, null, null, null, null, version, null, null, null, null, null, null, pageable); 464 List<ObjetMaquette> objetsMaquette = pagedObjetMaquette.getItems(); 465 466 // If it was found, return it 467 if (objetsMaquette.size() >= 1) 468 { 469 return objetsMaquette.get(0); 470 } 471 } 472 catch (ApiException e) 473 { 474 getLogger().warn("Une erreur est survenue lors la recherche de l'élément de code de synchronization Pégase {} pour vérifier son existance préalable dans Pégase", code, e); 475 } 476 477 return null; 478 } 479 480 private Map<String, Object> _getCodeAndVersion(String codeAndVersion) 481 { 482 Map<String, Object> result = new HashMap<>(); 483 484 String code = codeAndVersion; 485 String version = null; 486 487 if (codeAndVersion.contains("/")) 488 { 489 String[] codeAndVersionTab = codeAndVersion.split("/"); 490 if (codeAndVersionTab.length == 2) 491 { 492 code = codeAndVersionTab[0]; 493 version = codeAndVersionTab[1]; 494 } 495 } 496 497 result.put("code", code); 498 result.put("version", version); 499 500 return result; 501 } 502 503 private boolean _isModifiable(ObjetMaquette objetMaquette, String code, ExportReport report) throws IOException 504 { 505 // If the object is not editable, return false 506 if (!objetMaquette.getModifiable()) 507 { 508 return false; 509 } 510 511 // The object is editable, now we check if it is linked to this Program 512 List<FormationRef> parentPrograms = objetMaquette.getFormationsParentes(); 513 if (parentPrograms != null && parentPrograms.size() >= 1) 514 { 515 FormationRef parentProgram = parentPrograms.get(0); 516 517 // If it is already linked to the Program, return true 518 if (report.getCodeParentProgram().equals(parentProgram.getCode()) && report.getVersionParentProgram() == parentProgram.getVersion()) 519 { 520 return true; 521 } 522 } 523 524 // If the object is "mutualise" or orphan in Pégase then it can be linked to the Program 525 if (objetMaquette.getMutualise() || _isOrphan(code)) 526 { 527 return true; 528 } 529 530 return false; 531 } 532 533 private boolean _isOrphan(String code) throws IOException 534 { 535 PagedObjetMaquette pagedObjetMaquette; 536 try 537 { 538 // Try to get the objetMaquette for the code wanted and that are isolated 539 pagedObjetMaquette = _pegaseApiManager.getObjetsMaquetteApi().lireListeObjetsMaquette(_structureCode, null, null, null, code, null, null, null, true, null, null, null, null, null, null, null, null, null, null); 540 541 List<ObjetMaquette> objetsMaquette = pagedObjetMaquette.getItems(); 542 543 return objetsMaquette.size() >= 1; 544 } 545 catch (ApiException e) 546 { 547 getLogger().info("L'élément de code de synchronisation Pégase {} n'a pas pu être trouvé dans Pégase, nous ne pouvons donc pas vérifier si l'élément est isolé.", e); 548 } 549 550 return false; 551 } 552 553 private Enfant _createPegaseChild(Content child, String pegaseId) 554 { 555 Enfant pegaseChild = new Enfant(); 556 557 pegaseChild.setDetails( 558 new EnfantDetails() 559 .libelle(child.getTitle()) 560 ); 561 562 pegaseChild.setRef( 563 new Ref() 564 .id(pegaseId) 565 .code(child.getValue(__PEGASE_SYNC_CODE)) 566 ); 567 568 return pegaseChild; 569 } 570 571 private Enfant _createChild(Content content, ExportReport report) 572 { 573 boolean success = true; 574 try 575 { 576 String childPegaseId = _createPegaseInstance(content, report); 577 return _createPegaseChild(content, childPegaseId); 578 } 579 catch (Exception ex) 580 { 581 success = false; 582 getLogger().error("Erreur lors de l'export de l'élément {}", content.getTitle(), ex); 583 return null; 584 } 585 finally 586 { 587 if (success) 588 { 589 report.addElementExported(content); 590 } 591 } 592 } 593 594 private String _createPegaseInstance(Content content, ExportReport report) throws PegaseExportException, IOException 595 { 596 // Conteneur : semestre, année -> OTT ou Groupement 597 if (content instanceof Container) 598 { 599 return _createOTTOrGroupFromContainer((Container) content, report); 600 } 601 602 // Parcours -> OO 603 if (content instanceof SubProgram) 604 { 605 return _createOOFromSubProgram((SubProgram) content, report); 606 } 607 608 // ELP -> OP 609 if (content instanceof Course) 610 { 611 return _createOPFromCourse((Course) content, report); 612 } 613 614 // liste d'ELP -> Groupement 615 if (content instanceof CourseList) 616 { 617 return _createGroupFromCourseList((CourseList) content, report); 618 } 619 620 return null; 621 } 622 623 private Map<String, Enfant> _createAllChildren(Map<String, Enfant> children, List<ProgramItem> programItem, ExportReport report) 624 { 625 for (ProgramItem childContent : programItem) 626 { 627 Enfant containerChild = _createChild((Content) childContent, report); 628 629 // If the child was created, add it to the list of children to attach 630 if (containerChild != null) 631 { 632 children.put(containerChild.getRef().getId(), containerChild); 633 } 634 } 635 636 return children; 637 } 638 639 private void _attachAllChildren(Content content, String pegaseId, Map<String, Enfant> children, ExportReport report) throws IOException 640 { 641 List<Enfant> childrenAlreadyAttached; 642 try 643 { 644 // Get the children already attached to the programItem 645 childrenAlreadyAttached = _pegaseApiManager.getObjetsMaquetteApi().lireEnfants(_structureCode, pegaseId); 646 647 // If there are children already attached and the option trustAmetys is checked 648 if (childrenAlreadyAttached != null && _trustAmetys) 649 { 650 // For every child already attached 651 for (Enfant child : childrenAlreadyAttached) 652 { 653 // Try to detach it 654 try 655 { 656 _pegaseApiManager.getObjetsMaquetteApi().detacherEnfant(_structureCode, pegaseId, child.getRef().getId()); 657 } 658 catch (ApiException e) 659 { 660 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR, content); 661 getLogger().warn("L'enfant de code Pégase {} de l'élément {} n'a pas pu être détaché dans Pégase", child.getRef().getCode(), content.getTitle(), e); 662 } 663 } 664 } 665 666 // If the option trustAmetys is not checked 667 else if (childrenAlreadyAttached != null) 668 { 669 // For every child already attached 670 for (Enfant childAlreadyAttached : childrenAlreadyAttached) 671 { 672 // Remove it from the list of children to attach 673 children.remove(childAlreadyAttached.getRef().getId()); 674 } 675 } 676 677 List<Enfant> childrenToAttach = List.copyOf(children.values()); 678 679 // If there are children that need to be attached 680 if (!childrenToAttach.isEmpty()) 681 { 682 // Try to attach them 683 try 684 { 685 _pegaseApiManager.getObjetsMaquetteApi().attacherEnfant(_structureCode, pegaseId, childrenToAttach); 686 } 687 catch (ApiException ex) 688 { 689 report.updateExportReport(ExportStatus.WARN, ProblemTypes.LINKS_MISSING, content); 690 691 String childrenFailedToAttach = ""; 692 693 for (Enfant child : childrenToAttach) 694 { 695 childrenFailedToAttach += child.getRef().getCode() + ","; 696 } 697 698 getLogger().warn("Une erreur est survenue lors de l'attachement des enfants ({}) à l'élément ({}) dans Pégase", childrenFailedToAttach, content.getTitle(), ex); 699 } 700 } 701 } 702 catch (ApiException e) 703 { 704 report.updateExportReport(ExportStatus.WARN, ProblemTypes.API_ERROR, content); 705 706 getLogger().warn("Les liens avec les enfants de l'élément {} n'ont pas pu être traités car les enfants depuis Pégase n'ont pas pu être récupérés.", content.getTitle(), e); 707 } 708 } 709 710 private void _attachAllChildrenGroupementCase(Content content, String pegaseId, Map<String, Enfant> children, ExportReport report) throws IOException 711 { 712 // If the list of children that need to be attached is empty, throw an Exception 713 if (children.isEmpty()) 714 { 715 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.GROUPEMENT_WITHOUT_CHILDREN, content); 716 717 getLogger().warn("Aucuns des enfants de la liste d'elp ou le conteneur {}, devant être exporté en groupement, n'ont pu être exportés, les enfants de ce groupement resterons donc inchangés ", content.getTitle()); 718 } 719 else 720 { 721 List<Enfant> childenAlreadyAttached; 722 try 723 { 724 // Get the children already attached 725 childenAlreadyAttached = _pegaseApiManager.getObjetsMaquetteApi().lireEnfants(_structureCode, pegaseId); 726 List<String> childrenAttachedInTheEnd = List.copyOf(children.keySet()); 727 728 // If there are children already attached 729 if (childenAlreadyAttached != null) 730 { 731 // For every child already attached 732 for (Enfant childAlreadyAttached : childenAlreadyAttached) 733 { 734 // Remove it from the list of children to attach 735 children.remove(childAlreadyAttached.getRef().getId()); 736 } 737 } 738 739 List<Enfant> childrenToAttach = List.copyOf(children.values()); 740 741 // If there are children to attach, try to attach them 742 if (!childrenToAttach.isEmpty()) 743 { 744 try 745 { 746 _pegaseApiManager.getObjetsMaquetteApi().attacherEnfant(_structureCode, pegaseId, childrenToAttach); 747 } 748 catch (ApiException ex) 749 { 750 report.updateExportReport(ExportStatus.WARN, ProblemTypes.LINKS_MISSING, content); 751 752 if (getLogger().isWarnEnabled()) 753 { 754 getLogger().warn("Une erreur est survenue lors de l'attachement des enfants ({}) à l'élément ({}) dans Pégase", 755 childrenToAttach.stream() 756 .map(Enfant::getRef) 757 .map(Ref::getCode) 758 .distinct() 759 .collect(Collectors.joining(", ")), 760 content.getTitle(), 761 ex 762 ); 763 } 764 } 765 } 766 767 // If the option trustAmetys is checked, try to detach the other children (the children that were already attached to the content 768 if (_trustAmetys && childenAlreadyAttached != null) 769 { 770 // For every child that was already there 771 for (Enfant child : childenAlreadyAttached) 772 { 773 String childId = child.getRef().getId(); 774 775 // If it was not part of the children that needed to be attached, try to detach it 776 if (!childrenAttachedInTheEnd.contains(childId)) 777 { 778 try 779 { 780 _pegaseApiManager.getObjetsMaquetteApi().detacherEnfant(_structureCode, pegaseId, child.getRef().getId()); 781 } 782 catch (ApiException e) 783 { 784 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR, content); 785 786 getLogger().warn("L'enfant de code Pégase {} de l'élément {} n'a pas pu être détaché dans Pégase", child.getRef().getCode(), content.getTitle(), e); 787 } 788 } 789 } 790 } 791 } 792 catch (ApiException e) 793 { 794 report.updateExportReport(ExportStatus.WARN, ProblemTypes.LINKS_MISSING, content); 795 796 getLogger().warn("Les liens avec les enfants de l'élément ({}) n'ont pas pu être traités car les enfants depuis Pégase n'ont pas pu être récupérés.", content.getTitle(), e); 797 } 798 } 799 } 800 801 private ObjetFormation _createObjetFormation(Content content, String type, ExportReport report) throws PegaseExportException, IOException 802 { 803 // Create the ObjetFormation 804 ObjetFormation objetFormation = new ObjetFormation(); 805 806 String code = content.getValue(__PEGASE_SYNC_CODE); 807 String label = content.getTitle(); 808 809 objetFormation.setCode(code); 810 811 objetFormation.setLibelle(StringUtils.truncate(label, 50)); // le libellé court doit faire moins de 50 caractères 812 objetFormation.setLibelleLong(StringUtils.truncate(label, 150)); // le libellé long doit faire moins de 150 caractères 813 814 ObjetFormationType ob = new ObjetFormationType(); 815 ob.setCode(type); 816 objetFormation.setType(ob); 817 818 objetFormation.setMutualise(true); 819 820 if (content.hasValue("ects")) 821 { 822 Double ects = null; 823 if (content instanceof AbstractProgram) 824 { 825 ects = _getContentValue(content, AbstractProgram.ECTS) 826 .map(c -> c.<String>getValue(OdfReferenceTableEntry.CODE)) 827 .map(Double::parseDouble) 828 .orElse(null); 829 } 830 else 831 { 832 ects = content.getValue("ects"); 833 } 834 835 if (ects != null) 836 { 837 objetFormation.putChampsAdditionnelsItem("ECTS", new ValeurNum().valeur(ects)); 838 } 839 } 840 841 Object desc = null; 842 if (content.hasValue("description")) 843 { 844 desc = content.getValue("description"); 845 } 846 else if (content.hasValue("presentation")) 847 { 848 desc = content.getValue("presentation"); 849 } 850 851 if (desc != null) 852 { 853 RichText descRichText = (RichText) desc; 854 String description = _richTextHelper.richTextToString(descRichText); 855 objetFormation.setDescription(StringUtils.truncate(description, 2000)); // la description doit faire moins de 2000 caractères 856 } 857 858 // Check if the object already exists 859 ObjetMaquette objetMaquette = _getObjetMaquetteIfAlreadyExists(code); 860 if (objetMaquette != null) 861 { 862 // If it already exist, check if it can be edited 863 if (_isModifiable(objetMaquette, code, report)) 864 { 865 String id = objetMaquette.getId(); 866 objetFormation.setId(id); 867 868 // Edit the already existing object 869 try 870 { 871 objetFormation = _pegaseApiManager.getObjetsFormationApi().modifierObjetFormation(_structureCode, id, objetFormation); 872 return objetFormation; 873 } 874 catch (ApiException e) 875 { 876 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.ELEMENT_NOT_EXPORTED); 877 878 throw new PegaseExportException("L'élément " + content.getTitle() + " n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 879 } 880 } 881 882 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.ELEMENT_ALREADY_EXIST); 883 884 throw new PegaseExportException("Erreur lors de l'export de " + label + "Un élément avec le code " + code + " existe déjà et n'est pas mutualisable ou modifiable"); 885 } 886 887 // If it did not already exist, create the object 888 try 889 { 890 objetFormation = _pegaseApiManager.getObjetsFormationApi().creerObjetFormation(_structureCode, objetFormation); 891 892 return objetFormation; 893 } 894 catch (ApiException e) 895 { 896 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.ELEMENT_NOT_EXPORTED); 897 898 throw new PegaseExportException("L'élément " + content.getTitle() + " n'a pas pu être exporté dû à un problème rencontré avec Pégase", e); 899 } 900 } 901 902 private Formation _createProgram(Program program, ExportReport report) throws PegaseExportException, IOException 903 { 904 Formation pegaseProgram = new Formation(); 905 906 String codeAndVersion = program.getValue(__PEGASE_SYNC_CODE); 907 908 Map<String, Object> dataCodeAndVersion = _getCodeAndVersion(codeAndVersion); 909 String code = (String) dataCodeAndVersion.get("code"); 910 BigDecimal version = new BigDecimal((String) dataCodeAndVersion.get("version")); 911 912 pegaseProgram.setCode(code); 913 914 pegaseProgram.setLibelle(StringUtils.truncate(program.getTitle(), 50)); // le libellé court doit faire moins de 50 caractères 915 pegaseProgram.setLibelleLong(StringUtils.truncate(program.getTitle(), 150)); // le libellé court doit faire moins de 150 caractères 916 917 _getContentValue(program, AbstractProgram.ECTS) 918 .map(c -> c.<String>getValue(OdfReferenceTableEntry.CODE)) 919 .map(Double::parseDouble) 920 .ifPresent(pegaseProgram::setEcts); 921 922 pegaseProgram.setTypeFormation(new FormationTypeFormation().code(_getPegaseCodeOrCodeOfAttribute(program, AbstractProgram.EDUCATION_KIND))); 923 924 // If the Program is of education kind "diplomante", add the additional fields 925 if (__CODE_FORMATION_DIPLOMANTE.equals(pegaseProgram.getTypeFormation().getCode())) 926 { 927 _fieldsIfDiplomante(program, pegaseProgram); 928 } 929 930 return _createOrEditProgram(code, version, pegaseProgram, report); 931 } 932 933 private void _fieldsIfDiplomante(Program program, Formation pegaseProgram) 934 { 935 Content degree = _getContentValue(program, AbstractProgram.DEGREE).orElse(null); 936 937 // Degree -> typeDiplome 938 pegaseProgram.setTypeDiplome(_getPegaseCodeOrCode(degree)); 939 940 // degreeNature -> natureDiplome 941 Optional.ofNullable(degree) 942 .map(d -> d.<String>getValue("degreeNature")) 943 .ifPresent(pegaseProgram::setNatureDiplome); 944 945 // Cursus 946 Optional.ofNullable(degree) 947 .map(d -> d.<String>getValue("cursus")) 948 .ifPresent(pegaseProgram::setCursus); 949 950 // educationLevel -> niveauFormation 951 pegaseProgram.setNiveauFormation(_getPegaseCodeOrCodeOfAttribute(program, AbstractProgram.LEVEL)); 952 953 // RncpLevel -> niveauDiplome 954 String rncpLevelValue = _getContentValues(program, AbstractProgram.RNCP_LEVEL) 955 .map(this::_getPegaseCodeOrCode) 956 .collect(Collectors.joining(",")); 957 pegaseProgram.setNiveauDiplome(rncpLevelValue); 958 959 // Domain 960 if (((ElementDefinition) program.getDefinition(AbstractProgram.DOMAIN)).isMultiple()) 961 { 962 _getContentValues(program, AbstractProgram.DOMAIN) 963 .findFirst() 964 .map(this::_getPegaseCodeOrCode) 965 .ifPresent(pegaseProgram::setDomaineFormation); 966 } 967 else 968 { 969 pegaseProgram.setDomaineFormation(_getPegaseCodeOrCodeOfAttribute(program, AbstractProgram.DOMAIN)); 970 } 971 972 // ProgramFields -> champFormation 973 String programFieldsValue = _getContentValues(program, AbstractProgram.PROGRAM_FIELD) 974 .map(this::_getPegaseCodeOrCode) 975 .collect(Collectors.joining(",")); 976 if (StringUtils.isNotBlank(programFieldsValue)) 977 { 978 pegaseProgram.setChampFormation(programFieldsValue); 979 } 980 981 pegaseProgram.setMention(_getPegaseCodeOrCodeOfAttribute(program, AbstractProgram.MENTION)); 982 } 983 984 private Formation _createOrEditProgram(String code, BigDecimal version, Formation pegaseProgram, ExportReport report) throws PegaseExportException, IOException 985 { 986 // Check if the Program already exist in this version 987 ObjetMaquette objetMaquette = _getObjetMaquetteIfAlreadyExists(code, version); 988 989 // If no version is requested 990 if (version == null) 991 { 992 // If no program with this code was found in Pegase, create a new Program 993 if (objetMaquette == null) 994 { 995 try 996 { 997 return _pegaseApiManager.getFormationsApi().creerFormation(_structureCode, pegaseProgram); 998 } 999 catch (ApiException e) 1000 { 1001 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR); 1002 1003 throw new PegaseExportException("La formation n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 1004 } 1005 } 1006 1007 // If a program was found, try to edit it 1008 String id = objetMaquette.getId(); 1009 pegaseProgram.setId(id); 1010 1011 try 1012 { 1013 return _pegaseApiManager.getFormationsApi().modifierFormation(_structureCode, id, pegaseProgram); 1014 } 1015 catch (ApiException e) 1016 { 1017 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR); 1018 1019 throw new PegaseExportException("La formation n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 1020 } 1021 } 1022 1023 // If a version was requested 1024 1025 // If a program already exist in this version, try to edit it 1026 if (objetMaquette != null) 1027 { 1028 try 1029 { 1030 String id = objetMaquette.getId(); 1031 1032 pegaseProgram.setId(id); 1033 1034 return _pegaseApiManager.getFormationsApi().modifierFormation(_structureCode, id, pegaseProgram); 1035 } 1036 catch (ApiException e) 1037 { 1038 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR); 1039 1040 throw new PegaseExportException("La formation n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 1041 } 1042 } 1043 1044 // If no program was found in Pegase with this code and version 1045 // Check if the program exist in another version 1046 objetMaquette = _getObjetMaquetteIfAlreadyExists(code); 1047 1048 // If the program exist in another version 1049 if (objetMaquette != null) 1050 { 1051 try 1052 { 1053 // Generate a new version of the Pegase Program 1054 Formation newVersionProgram = _pegaseApiManager.getFormationsApi().generer(_structureCode, objetMaquette.getId()); 1055 1056 String id = newVersionProgram.getId(); 1057 pegaseProgram.setId(id); 1058 1059 // Edit the new Program created 1060 return _pegaseApiManager.getFormationsApi().modifierFormation(_structureCode, id, pegaseProgram); 1061 } 1062 catch (ApiException e) 1063 { 1064 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR); 1065 1066 throw new PegaseExportException("La formation n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 1067 } 1068 } 1069 1070 // If no program was found for this code at all 1071 else 1072 { 1073 try 1074 { 1075 // Create the program in Pegase 1076 return _pegaseApiManager.getFormationsApi().creerFormation(_structureCode, pegaseProgram); 1077 } 1078 catch (ApiException e) 1079 { 1080 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR); 1081 1082 throw new PegaseExportException("La formation n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 1083 } 1084 } 1085 } 1086 1087 private String _createOTTOrGroupFromContainer(Container container, ExportReport report) throws PegaseExportException, IOException 1088 { 1089 String type = null; 1090 1091 String childNatureCode = getContainerNatureCode(container); 1092 boolean isYear = "annee".equals(childNatureCode); 1093 boolean isSemester = "semestre".equals(childNatureCode); 1094 1095 // If it is a container of nature : semester of year, export it as an OTT of type semester or year 1096 if (isYear || isSemester) 1097 { 1098 type = isYear ? "ANNEE" : "SEMESTRE"; 1099 1100 ObjetFormation objetFormationCreated = _createObjetFormation(container, type, report); 1101 String pegaseId = objetFormationCreated.getId(); 1102 1103 Map<String, Enfant> containerChildren = new HashMap<>(); 1104 1105 // Create the children 1106 containerChildren = _createAllChildren(containerChildren, _odfHelper.getChildProgramItems(container), report); 1107 1108 // Attach the children that were created 1109 _attachAllChildren(container, pegaseId, containerChildren, report); 1110 1111 return pegaseId; 1112 } 1113 1114 // If it is a container without a nature, export it as a group 1115 return _createGroupFromContainer(container, report); 1116 } 1117 1118 private String _createGroupFromContainer(Container container, ExportReport report) throws PegaseExportException, IOException 1119 { 1120 Map<String, Enfant> coursesChild = new HashMap<>(); 1121 Groupement pegaseGroup = _createGroupFromContent(container); 1122 1123 // Create the children 1124 coursesChild = _createAllChildren(coursesChild, _odfHelper.getChildProgramItems(container), report); 1125 1126 pegaseGroup.setEnfants(List.copyOf(coursesChild.keySet())); 1127 1128 // Create the group 1129 Groupement groupementCreated = _createGroup(pegaseGroup, report); 1130 String pegaseId = groupementCreated.getId(); 1131 1132 // Attach the children to the group 1133 _attachAllChildrenGroupementCase(container, pegaseId, coursesChild, report); 1134 1135 return pegaseId; 1136 } 1137 1138 private Groupement _createGroup(Groupement pegaseGroup, ExportReport report) throws PegaseExportException, IOException 1139 { 1140 String code = pegaseGroup.getCode(); 1141 ObjetMaquette objetMaquette = _getObjetMaquetteIfAlreadyExists(code); 1142 Groupement pegaseGroupCreated; 1143 1144 // Check if the object already exists 1145 if (objetMaquette != null) 1146 { 1147 // If it already exist, check if it can be edited 1148 if (_isModifiable(objetMaquette, code, report)) 1149 { 1150 String id = objetMaquette.getId(); 1151 pegaseGroup.setId(id); 1152 1153 // Edit the already existing object 1154 try 1155 { 1156 return _pegaseApiManager.getGroupementsApi().modifierGroupement(_structureCode, id, pegaseGroup); 1157 } 1158 catch (ApiException e) 1159 { 1160 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.ELEMENT_NOT_EXPORTED); 1161 1162 throw new PegaseExportException("Le groupement " + pegaseGroup.getLibelle() + " n'a pas pu être exportée car sa modification dans Pégase a posé un problème", e); 1163 } 1164 } 1165 1166 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.ELEMENT_ALREADY_EXIST); 1167 1168 throw new PegaseExportException("Un élément avec ce code existe déjà et n'est pas mutualisable ou modifiable"); 1169 } 1170 1171 // If it did not already exist, create the object 1172 try 1173 { 1174 pegaseGroupCreated = _pegaseApiManager.getGroupementsApi().creerGroupement(_structureCode, pegaseGroup); 1175 1176 if (pegaseGroupCreated != null) 1177 { 1178 return pegaseGroupCreated; 1179 } 1180 } 1181 catch (ApiException e) 1182 { 1183 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.ELEMENT_NOT_EXPORTED); 1184 1185 throw new PegaseExportException("Le groupement " + pegaseGroup.getLibelle() + " n'a pas pu être exporté dû à un problème rencontré avec Pégase", e); 1186 } 1187 1188 return null; 1189 } 1190 1191 private String _createOOFromSubProgram(SubProgram subProgram, ExportReport report) throws PegaseExportException, IOException 1192 { 1193 ObjetFormation objetFormationCreated = _createObjetFormation(subProgram, "PARCOURS-TYPE", report); 1194 String pegaseId = objetFormationCreated.getId(); 1195 1196 Map<String, Enfant> containerChildren = new HashMap<>(); 1197 1198 // Create the children 1199 containerChildren = _createAllChildren(containerChildren, _odfHelper.getChildProgramItems(subProgram), report); 1200 1201 // Attach the children 1202 _attachAllChildren(subProgram, pegaseId, containerChildren, report); 1203 1204 return pegaseId; 1205 } 1206 1207 private String _createOPFromCourse(Course course, ExportReport report) throws PegaseExportException, IOException 1208 { 1209 // Get the nature of the course 1210 String type = _getPegaseCodeOrCodeOfAttribute(course, Course.COURSE_TYPE); 1211 1212 // Create the course in Pegase 1213 ObjetFormation objetFormationCreated = _createObjetFormation(course, type, report); 1214 String pegaseId = objetFormationCreated.getId(); 1215 Map<String, Enfant> containerChildren = new HashMap<>(); 1216 1217 // Create the children 1218 containerChildren = _createAllChildren(containerChildren, _odfHelper.getChildProgramItems(course), report); 1219 1220 // Attach the children 1221 _attachAllChildren(course, pegaseId, containerChildren, report); 1222 1223 return pegaseId; 1224 } 1225 1226 private Groupement _createGroupFromContent(Content content) 1227 { 1228 Groupement pegaseGroup = new Groupement(); 1229 String code = content.getValue(__PEGASE_SYNC_CODE); 1230 1231 pegaseGroup.setStructure(_structureCode); 1232 pegaseGroup.setCode(code); 1233 pegaseGroup.setLibelle(StringUtils.truncate(content.getTitle(), 50)); // le libellé est limité à 50 caractères 1234 pegaseGroup.setPlageDeChoix(false); 1235 pegaseGroup.setMutualise(true); 1236 pegaseGroup.setEnfants(List.of()); 1237 1238 return pegaseGroup; 1239 } 1240 1241 private String _createGroupFromCourseList(CourseList courseList, ExportReport report) throws PegaseExportException, IOException 1242 { 1243 Map<String, Enfant> coursesChild = new HashMap<>(); 1244 Groupement pegaseGroup = _createGroupFromContent(courseList); 1245 1246 coursesChild = _createAllChildren(coursesChild, _odfHelper.getChildProgramItems(courseList), report); 1247 1248 pegaseGroup.setEnfants(List.copyOf(coursesChild.keySet())); 1249 1250 Groupement pegaseGroupCreated = _createGroup(pegaseGroup, report); 1251 1252 String pegaseId = pegaseGroupCreated.getId(); 1253 1254 _attachAllChildrenGroupementCase(courseList, pegaseId, coursesChild, report); 1255 1256 return pegaseId; 1257 } 1258 1259 /** 1260 * Create a program in Pegase 1261 * @param program the program to export 1262 * @param report the Pegase export report 1263 */ 1264 @Override 1265 public void createProgram(Program program, ExportReport report) 1266 { 1267 if (!_isActive) 1268 { 1269 throw new UnsupportedOperationException("Pégase is not active in the configuration, you cannot import or synchronize a program in Pégase."); 1270 } 1271 1272 int nbTotal = _getEveryElements(program).size(); 1273 1274 report.setNbTotal(nbTotal); 1275 1276 Formation pegaseProgramCreated; 1277 try 1278 { 1279 // Create the Program in Pegase 1280 pegaseProgramCreated = _createProgram(program, report); 1281 report.addElementExported(program); 1282 1283 // Get the Id of the created formation from Pegase that is going to be used to attach the children to the program 1284 String pegaseProgramId = pegaseProgramCreated.getId(); 1285 1286 String codeParentProgram = pegaseProgramCreated.getCode(); 1287 int versionParentProgram = 1; 1288 1289 if (codeParentProgram.contains("/")) 1290 { 1291 String[] codeAndVersionTab = codeParentProgram.split("/"); 1292 if (codeAndVersionTab.length == 2) 1293 { 1294 codeParentProgram = codeAndVersionTab[0]; 1295 versionParentProgram = Integer.parseInt(codeAndVersionTab[1]); 1296 } 1297 } 1298 1299 report.setCodeAndVersion(codeParentProgram, versionParentProgram); 1300 1301 // Get the children of the Ametys program 1302 List<ProgramPart> children = program.getProgramPartChildren(); 1303 Map<String, Enfant> childrenToLink = new HashMap<>(); 1304 1305 for (ProgramPart child : children) 1306 { 1307 // Create the pegase instance of the child 1308 Enfant enfant = _createChild((Content) child, report); 1309 1310 // Add the Enfant (created from the Pegase Id of the child) to the list of "Enfant" to link, if it is not already attached 1311 if (enfant != null) 1312 { 1313 childrenToLink.put(enfant.getRef().getId(), enfant); 1314 } 1315 } 1316 1317 _attachAllChildren(program, pegaseProgramId, childrenToLink, report); 1318 1319 } 1320 catch (IOException e) 1321 { 1322 report.updateExportReport(ExportStatus.ERROR, ProblemTypes.API_ERROR); 1323 getLogger().error("Le jeton d'authentification à Pégase n'a pas pu être récupéré", e); 1324 } 1325 catch (PegaseExportException e) 1326 { 1327 report.updateStatus(ExportStatus.ERROR); 1328 getLogger().error("Une erreur est survenue lors de l'export de la formation '{}' ({}) dans Pégase", program.getTitle(), program.getId(), e); 1329 } 1330 } 1331 1332 private Set<ProgramItem> _getEveryElements(ProgramItem program) 1333 { 1334 Set<ProgramItem> elementNotExported = new HashSet<>(); 1335 elementNotExported.add(program); 1336 1337 for (ProgramItem child : _odfHelper.getChildProgramItems(program)) 1338 { 1339 elementNotExported.addAll(_getEveryElements(child)); 1340 } 1341 1342 return elementNotExported; 1343 } 1344}