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