001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.odfsync.apogee.ws.structure; 017 018import java.rmi.RemoteException; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.stream.Collectors; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.avalon.framework.service.Serviceable; 026import org.apache.commons.lang3.StringUtils; 027 028import org.ametys.cms.contenttype.AttributeDefinition; 029import org.ametys.cms.data.ContentValue; 030import org.ametys.cms.data.type.ModelItemTypeConstants; 031import org.ametys.cms.repository.Content; 032import org.ametys.core.util.I18nUtils; 033import org.ametys.odf.course.Course; 034import org.ametys.odf.courselist.CourseList; 035import org.ametys.odf.enumeration.OdfReferenceTableHelper; 036import org.ametys.odf.orgunit.OrgUnit; 037import org.ametys.odf.program.AbstractProgram; 038import org.ametys.odf.program.Container; 039import org.ametys.odf.program.SubProgram; 040import org.ametys.plugins.odfsync.apogee.ws.ApogeeExportReport; 041import org.ametys.plugins.odfsync.apogee.ws.ApogeeExportReport.ExportStatus; 042import org.ametys.plugins.odfsync.apogee.ws.ApogeeWS; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.runtime.i18n.I18nizableText; 045import org.ametys.runtime.model.ModelItem; 046import org.ametys.runtime.plugin.component.AbstractLogEnabled; 047 048import gouv.education.apogee.commun.client.ws.creationse.CreationSEMetierServiceInterface; 049 050/** 051 * The abstract class to handle an export in Apogee 052 */ 053public abstract class AbstractApogeeStructure extends AbstractLogEnabled implements ApogeeExportStructure, Serviceable 054{ 055 /** The attribute name for the code Apogee */ 056 public static final String CODE_APOGEE_ATTRIBUTE_NAME = "codeApogee"; 057 058 /** The false attribute name for the version Apogee */ 059 public static final String VERSION_APOGEE_ATTRIBUTE_NAME = "versionApogee"; 060 061 /** The separator between the code and the version */ 062 public static final String CODE_APOGEE_SEPARATOR = "-"; 063 064 /** The i18n utils */ 065 protected I18nUtils _i18nUtils; 066 067 /** The apogee WS */ 068 protected ApogeeWS _apogeeWS; 069 070 /** The Ametys object resolver */ 071 protected AmetysObjectResolver _resolver; 072 073 /** The ODF reference table helper */ 074 protected OdfReferenceTableHelper _odfRefTableHelper; 075 076 public void service(ServiceManager manager) throws ServiceException 077 { 078 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 079 _apogeeWS = (ApogeeWS) manager.lookup(ApogeeWS.ROLE); 080 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 081 _odfRefTableHelper = (OdfReferenceTableHelper) manager.lookup(OdfReferenceTableHelper.ROLE); 082 } 083 084 /** 085 * Mandatory data to export a content in a DIP in Apogee 086 * @param content the content to export 087 * @return the list of mandatory data 088 */ 089 public List<String> getDIPMandatoryData(Content content) 090 { 091 List<String> mandatoryData = new ArrayList<>(); 092 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 093 mandatoryData.add(AbstractProgram.EDUCATION_KIND); 094 mandatoryData.add("cycleApogee"); 095 mandatoryData.add(AbstractProgram.DEGREE); 096 097 return mandatoryData; 098 } 099 100 /** 101 * Mandatory data to export a content in a VDI in Apogee 102 * @param content the content to export 103 * @return the list of mandatory data 104 */ 105 public List<String> getVDIMandatoryData(Content content) 106 { 107 // The orgunit Apogee Code is mandatory too 108 109 List<String> mandatoryData = new ArrayList<>(); 110 mandatoryData.add(VERSION_APOGEE_ATTRIBUTE_NAME); 111 mandatoryData.add("start-date-recruitment"); 112 mandatoryData.add("end-date-recruitment"); 113 mandatoryData.add("start-date-validation"); 114 mandatoryData.add("end-date-validation"); 115 116 return mandatoryData; 117 } 118 119 /** 120 * Mandatory data to export a content in a ETP in Apogee 121 * @param content the content to export 122 * @return the list of mandatory data 123 */ 124 public List<String> getETPMandatoryData(Content content) 125 { 126 // The orgunit Apogee Code is mandatory too 127 128 List<String> mandatoryData = new ArrayList<>(); 129 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 130 mandatoryData.add("cycleApogee"); 131 132 return mandatoryData; 133 } 134 135 /** 136 * Mandatory data to export a content in a VET in Apogee 137 * @param content the content to export 138 * @return the list of mandatory data 139 */ 140 public List<String> getVETMandatoryData(Content content) 141 { 142 // The orgunit Apogee Code is mandatory too 143 144 List<String> mandatoryData = new ArrayList<>(); 145 mandatoryData.add(VERSION_APOGEE_ATTRIBUTE_NAME); 146 mandatoryData.add("duration-apogee"); 147 mandatoryData.add("inscription-types"); 148 mandatoryData.add("cips"); 149 150 return mandatoryData; 151 } 152 153 /** 154 * Mandatory data to export a content in a LSE in Apogee 155 * @param content the content to export 156 * @return the list of mandatory data 157 */ 158 public List<String> getLSEMandatoryData(Content content) 159 { 160 List<String> mandatoryData = new ArrayList<>(); 161 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 162 mandatoryData.add("choiceType"); 163 164 String choiceTypeAmetys = content.getValue("choiceType"); 165 if (choiceTypeAmetys.equals("CHOICE")) 166 { 167 mandatoryData.add("min"); 168 } 169 170 return mandatoryData; 171 } 172 173 /** 174 * Mandatory data to export a content in a ELP in Apogee 175 * @param content the content to export 176 * @return the list of mandatory data 177 */ 178 public List<String> getELPMandatoryData(Content content) 179 { 180 // The orgunit Apogee Code is mandatory too 181 182 List<String> mandatoryData = new ArrayList<>(); 183 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 184 mandatoryData.add("cips"); 185 mandatoryData.add("orgUnit"); 186 if (content instanceof Container) 187 { 188 mandatoryData.add("nature"); 189 } 190 else if (content instanceof Course) 191 { 192 mandatoryData.add("courseType"); 193 } 194 195 return mandatoryData; 196 } 197 198 /** 199 * Mandatory data to export an orgunit for a DIP in Apogee 200 * @return the list of mandatory data 201 */ 202 public List<String> getOrgUnitMandatoryDataForDIP() 203 { 204 List<String> mandatoryData = new ArrayList<>(); 205 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 206 207 return mandatoryData; 208 } 209 210 /** 211 * Mandatory data to export an orgunit for a ETP in Apogee 212 * @return the list of mandatory data 213 */ 214 public List<String> getOrgUnitMandatoryDataForETP() 215 { 216 List<String> mandatoryData = new ArrayList<>(); 217 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 218 mandatoryData.add("codeCGE"); 219 220 return mandatoryData; 221 } 222 223 /** 224 * Mandatory data to export an orgunit for a ELP in Apogee 225 * @return the list of mandatory data 226 */ 227 public List<String> getOrgUnitMandatoryDataForELP() 228 { 229 List<String> mandatoryData = new ArrayList<>(); 230 mandatoryData.add(CODE_APOGEE_ATTRIBUTE_NAME); 231 232 return mandatoryData; 233 } 234 235 /** 236 * Get the code of the container nature 237 * @param container the container 238 * @param report the Apogee export report 239 * @return the code of the nature 240 */ 241 public String getContainerNatureCode(Container container, ApogeeExportReport report) 242 { 243 String nature = container.getNature(); 244 if (StringUtils.isNotBlank(nature)) 245 { 246 return _odfRefTableHelper.getItemCode(nature); 247 } 248 249 // The structure is not handled by this export because the container has no type 250 report.setExportStatus(ExportStatus.CONTENT_STRUCTURE_INVALID); 251 252 return null; 253 } 254 255 /** 256 * True if the container has for nature "annee" 257 * @param container the container 258 * @param report the Apogee export report 259 * @return true if it's a year container 260 */ 261 public boolean isYearContainer(Container container, ApogeeExportReport report) 262 { 263 String containerNatureCode = getContainerNatureCode(container, report); 264 return containerNatureCode != null ? "annee".equals(containerNatureCode) : false; 265 } 266 267 /** 268 * True if the container has for nature "semestre" 269 * @param container the container 270 * @param report the Apogee export report 271 * @return true if it's a semester container 272 */ 273 public boolean isSemesterContainer(Container container, ApogeeExportReport report) 274 { 275 String containerNatureCode = getContainerNatureCode(container, report); 276 return containerNatureCode != null ? "semestre".equals(containerNatureCode) : false; 277 } 278 279 /** 280 * Get the code Apogee of the content 281 * @param content the content 282 * @return the code Apogee 283 */ 284 public String getCodeApogee(Content content) 285 { 286 String codeApogee = content.getValue(CODE_APOGEE_ATTRIBUTE_NAME); 287 if (StringUtils.isNotBlank(codeApogee) && codeApogee.contains(CODE_APOGEE_SEPARATOR)) 288 { 289 return StringUtils.substringBefore(codeApogee, CODE_APOGEE_SEPARATOR); 290 } 291 else 292 { 293 return codeApogee; 294 } 295 } 296 297 /** 298 * Get the version, Apogee of the content 299 * @param content the content 300 * @return the version Apogee 301 */ 302 public Long getVersionApogee(Content content) 303 { 304 String codeApogee = content.getValue(CODE_APOGEE_ATTRIBUTE_NAME); 305 if (StringUtils.isNotBlank(codeApogee) && codeApogee.contains(CODE_APOGEE_SEPARATOR)) 306 { 307 return Long.parseLong(StringUtils.substringAfterLast(codeApogee, CODE_APOGEE_SEPARATOR)); 308 } 309 else 310 { 311 return null; 312 } 313 } 314 315 /** 316 * Check if the subProgram has the good data and structure to be export in Apogee 317 * @param subProgram the subProgram to check 318 * @param report the Apogee export report 319 */ 320 public abstract void checkSubProgram(SubProgram subProgram, ApogeeExportReport report); 321 322 /** 323 * Check if the container as year has the good data and structure to be export in Apogee 324 * @param container the container to check 325 * @param report the Apogee export report 326 */ 327 public abstract void checkContainerAsYear(Container container, ApogeeExportReport report); 328 329 /** 330 * Check if the container as semester has the good data and structure to be export in Apogee 331 * @param container the container to check 332 * @param report the Apogee export report 333 */ 334 public abstract void checkContainerAsSemester(Container container, ApogeeExportReport report); 335 336 /** 337 * Check if the course list has the good data and structure to be export in Apogee 338 * @param courseList the course list to check 339 * @param report the Apogee export report 340 */ 341 public void checkCourseList(CourseList courseList, ApogeeExportReport report) 342 { 343 // Check mandatory data for course list 344 checkMandatoryDataForContent(courseList, getLSEMandatoryData(courseList), report); 345 346 // Check the course list structure 347 for (Course course : courseList.getCourses()) 348 { 349 checkCourse(course, report); 350 } 351 } 352 353 /** 354 * Check if the course has the good data and structure to be export in Apogee 355 * @param course the course to check 356 * @param report the Apogee export report 357 */ 358 public void checkCourse(Course course, ApogeeExportReport report) 359 { 360 // Check mandatory data for course 361 checkMandatoryDataForContent(course, getELPMandatoryData(course), report); 362 363 // Check mandatory data for course orgUnits 364 checkMandatoryDataForOrgunits(course, course.getOrgUnits(), getOrgUnitMandatoryDataForELP(), report); 365 366 // Check the course structure 367 for (CourseList courseList : course.getCourseLists()) 368 { 369 checkCourseList(courseList, report); 370 } 371 } 372 373 374 /** 375 * Check if the content has a value for all mandatory data 376 * @param content the content to check 377 * @param mandatoryData the list of mandatory data path 378 * @param report the Apogee export report 379 */ 380 public void checkMandatoryDataForContent(Content content, List<String> mandatoryData, ApogeeExportReport report) 381 { 382 for (String dataPath : mandatoryData) 383 { 384 if (VERSION_APOGEE_ATTRIBUTE_NAME.equals(dataPath)) 385 { 386 _checkVersionApogee(content, report); 387 } 388 else if (content.hasValue(dataPath)) 389 { 390 if (org.ametys.runtime.model.type.ModelItemTypeConstants.STRING_TYPE_ID.equals(content.getType(dataPath).getId())) 391 { 392 _checkSimpleData(content, dataPath, report); 393 } 394 else if (ModelItemTypeConstants.CONTENT_ELEMENT_TYPE_ID.equals(content.getType(dataPath).getId())) 395 { 396 _checkTableRef(content, dataPath, report); 397 } 398 } 399 else 400 { 401 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 402 ModelItem modelItem = content.getDefinition(dataPath); 403 report.addMandatoryDataPath(content, modelItem); 404 } 405 } 406 } 407 408 /** 409 * Check if the content has a value for the simple data 410 * @param content the content to check 411 * @param dataPath the data path 412 * @param report the Apogee export report 413 */ 414 protected void _checkSimpleData(Content content, String dataPath, ApogeeExportReport report) 415 { 416 if (content.isMultiple(dataPath)) 417 { 418 String[] values = content.getValue(dataPath); 419 if (values.length == 0 || StringUtils.isBlank(values[0])) 420 { 421 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 422 ModelItem modelItem = content.getDefinition(dataPath); 423 report.addMandatoryDataPath(content, modelItem); 424 } 425 } 426 else 427 { 428 String value = content.getValue(dataPath); 429 if (StringUtils.isBlank(value)) 430 { 431 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 432 ModelItem modelItem = content.getDefinition(dataPath); 433 report.addMandatoryDataPath(content, modelItem); 434 } 435 } 436 } 437 438 /** 439 * Check if the content has a value for the simple table ref data 440 * @param content the content to check 441 * @param dataPath the data path 442 * @param report the Apogee export report 443 */ 444 protected void _checkTableRef(Content content, String dataPath, ApogeeExportReport report) 445 { 446 // We handle only simple table ref 447 if (!content.isMultiple(dataPath)) 448 { 449 ContentValue value = content.getValue(dataPath); 450 Content refContent = value.getContent(); 451 if (!value.hasValue(CODE_APOGEE_ATTRIBUTE_NAME) || StringUtils.isBlank(refContent.getValue(CODE_APOGEE_ATTRIBUTE_NAME))) 452 { 453 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 454 ModelItem modelItem = refContent.getDefinition(CODE_APOGEE_ATTRIBUTE_NAME); 455 report.addMandatoryDataPath(refContent, modelItem); 456 } 457 } 458 } 459 460 /** 461 * Check if the version Apogee exist in the Apogee code 462 * @param content the content 463 * @param report the Apogee export report 464 */ 465 protected void _checkVersionApogee(Content content, ApogeeExportReport report) 466 { 467 if (!content.hasValue(CODE_APOGEE_ATTRIBUTE_NAME) || StringUtils.isBlank(content.getValue(CODE_APOGEE_ATTRIBUTE_NAME))) 468 { 469 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 470 AttributeDefinition<String> attributeDefinition = new AttributeDefinition<>(); 471 attributeDefinition.setLabel(new I18nizableText("plugin.odf-sync", "PLUGINS_ODF_MANDATORY_APOGEE_VERSION_MESSAGE")); 472 report.addMandatoryDataPath(content, attributeDefinition); 473 } 474 else 475 { 476 String codeApogee = content.getValue(CODE_APOGEE_ATTRIBUTE_NAME); 477 if (!codeApogee.contains("-") || StringUtils.isBlank(StringUtils.substringAfterLast(codeApogee, "-"))) 478 { 479 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 480 AttributeDefinition<String> attributeDefinition = new AttributeDefinition<>(); 481 attributeDefinition.setLabel(new I18nizableText("plugin.odf-sync", "PLUGINS_ODF_MANDATORY_APOGEE_VERSION_MESSAGE")); 482 report.addMandatoryDataPath(content, attributeDefinition); 483 } 484 } 485 } 486 487 /** 488 * Check if the orgUnits has a value for all mandatory data 489 * @param content the content to check 490 * @param orgUnits the list of orgUnit to check 491 * @param mandatoryData the list of mandatory data path 492 * @param report the Apogee export report 493 */ 494 public void checkMandatoryDataForOrgunits(Content content, List<String> orgUnits, List<String> mandatoryData, ApogeeExportReport report) 495 { 496 if (orgUnits.size() == 0) 497 { 498 // No orgUnits, course data is invalid 499 report.setExportStatus(ExportStatus.CONTENT_DATA_INVALID); 500 ModelItem modelItem = content.getDefinition("orgUnit"); 501 report.addMandatoryDataPath(content, modelItem); 502 } 503 else 504 { 505 for (String orgUnitId : orgUnits) 506 { 507 OrgUnit orgUnit = _resolver.resolveById(orgUnitId); 508 checkMandatoryDataForContent(orgUnit, mandatoryData, report); 509 } 510 } 511 } 512 513 /** 514 * Create a course list in Apogee 515 * @param courseList the course list to create 516 * @param parentApogee the parent in Apogee 517 * @param creationService the service to create element in Apogee 518 * @param report the Apogee export report 519 * @throws RemoteException if an export error occurred 520 */ 521 protected void _createCourseList(CourseList courseList, Content parentApogee, CreationSEMetierServiceInterface creationService, ApogeeExportReport report) throws RemoteException 522 { 523 // Create ELPs before the list 524 for (Course course : courseList.getCourses()) 525 { 526 _createCourse(course, courseList, creationService, report); 527 } 528 529 String codELP = getCodeApogee(parentApogee); 530 String codLSE = getCodeApogee(courseList); 531 532 _apogeeWS.createLSE(courseList, null, codLSE, creationService); 533 534 Long nbELP = null; 535 Double ectsMin = 0D; 536 Double ectsMax = 0D; 537 String choiceTypeAmetys = courseList.getValue("choiceType"); 538 if (choiceTypeAmetys.equals("CHOICE")) 539 { 540 nbELP = courseList.getValue("min"); 541 542 List<Double> ectsList = courseList.getCourses() 543 .stream() 544 .map(Course::getEcts) 545 .sorted() 546 .collect(Collectors.toList()); 547 548 for (int i = 0; i < nbELP; i++) 549 { 550 ectsMin += ectsList.get(0); 551 } 552 553 ectsMin = (Math.floor(ectsMin) == 0D) ? 1D : Math.floor(ectsMin); 554 555 for (int i = 1; i <= nbELP; i++) 556 { 557 ectsMax += ectsList.get(ectsList.size() - i); 558 } 559 560 ectsMax = (Math.ceil(ectsMax) == 0D || ectsMin > ectsMax) ? 1D : Math.ceil(ectsMax); 561 } 562 563 _apogeeWS.createLinkETPELPLSE(null, null, codLSE, codELP, nbELP, ectsMin, ectsMax, creationService); 564 } 565 566 /** 567 * Create a course in Apogee 568 * @param course the course to create 569 * @param parentApogee the parent in Apogee 570 * @param creationService the service to create element in Apogee 571 * @param report the Apogee export report 572 * @throws RemoteException if an export error occurred 573 */ 574 protected void _createCourse(Course course, Content parentApogee, CreationSEMetierServiceInterface creationService, ApogeeExportReport report) throws RemoteException 575 { 576 String codELP = getCodeApogee(course); 577 _apogeeWS.createELP(course, null, codELP, creationService); 578 579 for (CourseList courseList : course.getCourseLists()) 580 { 581 _createCourseList(courseList, course, creationService, report); 582 } 583 } 584}