001/* 002 * Copyright 2017 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.scc.impl; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Optional; 024import java.util.Set; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.commons.lang3.tuple.Pair; 029import org.slf4j.Logger; 030 031import org.ametys.cms.data.ContentSynchronizationResult; 032import org.ametys.cms.repository.Content; 033import org.ametys.cms.repository.ModifiableContent; 034import org.ametys.core.user.population.UserPopulationDAO; 035import org.ametys.odf.course.Course; 036import org.ametys.odf.course.ShareableCourseHelper; 037import org.ametys.odf.courselist.CourseList; 038import org.ametys.odf.coursepart.CoursePart; 039import org.ametys.odf.coursepart.CoursePartFactory; 040import org.ametys.odf.enumeration.OdfReferenceTableEntry; 041import org.ametys.odf.enumeration.OdfReferenceTableHelper; 042import org.ametys.plugins.odfsync.apogee.scc.AbstractApogeeSynchronizableContentsWithCatalogCollection; 043import org.ametys.plugins.repository.data.holder.values.SynchronizationResult; 044 045import com.opensymphony.workflow.WorkflowException; 046 047/** 048 * SCC for course contents. 049 */ 050public class CourseSynchronizableContentsCollection extends AbstractApogeeSynchronizableContentsWithCatalogCollection 051{ 052 /** SCC model id */ 053 public static final String MODEL_ID = "org.ametys.plugins.odfsync.apogee.scc.course"; 054 055 /** The ODF reference table helper */ 056 protected OdfReferenceTableHelper _odfRefTableHelper; 057 058 /** The shareable course helper */ 059 protected ShareableCourseHelper _shareableCourseHelper; 060 061 @Override 062 public void service(ServiceManager manager) throws ServiceException 063 { 064 super.service(manager); 065 _odfRefTableHelper = (OdfReferenceTableHelper) manager.lookup(OdfReferenceTableHelper.ROLE); 066 _shareableCourseHelper = (ShareableCourseHelper) manager.lookup(ShareableCourseHelper.ROLE); 067 } 068 069 @Override 070 protected List<Map<String, Object>> _search(Map<String, Object> searchParameters, Logger logger) 071 { 072 return _convertBigDecimal(_apogeeDAO.searchCourses(getDataSourceId(), getParameterValues(), searchParameters)); 073 } 074 075 @Override 076 protected String getMappingName() 077 { 078 return "course"; 079 } 080 081 @Override 082 protected Map<String, Object> getAdditionalAttributeValues(String idValue, Content content, Map<String, Object> additionalParameters, boolean create, Logger logger) 083 { 084 Map<String, Object> result = super.getAdditionalAttributeValues(idValue, content, additionalParameters, create, logger); 085 086 // Handle course parts children 087 List<ModifiableContent> courseParts = importCourseParts(content, logger); 088 if (!courseParts.isEmpty()) 089 { 090 result.put(Course.CHILD_COURSE_PARTS, courseParts.toArray(new ModifiableContent[courseParts.size()])); 091 } 092 093 return result; 094 } 095 096 @Override 097 protected Pair<String, Object> getParentAttribute(ModifiableContent parent) 098 { 099 if (parent instanceof CourseList) 100 { 101 return Pair.of(Course.PARENT_COURSE_LISTS, new ModifiableContent[] {parent}); 102 } 103 104 return super.getParentAttribute(parent); 105 } 106 107 @Override 108 protected Set<String> getNotSynchronizedRelatedContentIds(Content content, Map<String, Object> contentValues, Map<String, Object> additionalParameters, String lang, Logger logger) 109 { 110 Set<String> contentIds = super.getNotSynchronizedRelatedContentIds(content, contentValues, additionalParameters, lang, logger); 111 112 if (contentValues.containsKey(Course.CHILD_COURSE_PARTS)) 113 { 114 Content[] courseParts = (Content[]) contentValues.get(Course.CHILD_COURSE_PARTS); 115 Arrays.stream(courseParts) 116 .map(Content::getId) 117 .forEach(contentIds::add); 118 } 119 120 return contentIds; 121 } 122 123 @Override 124 public ContentSynchronizationResult additionalImportOperations(ModifiableContent content, Map<String, Object> additionalParameters, Logger logger) 125 { 126 ContentSynchronizationResult result = super.additionalImportOperations(content, additionalParameters, logger); 127 128 CourseList parentContent = getParentFromAdditionalParameters(additionalParameters) 129 .map(CourseList.class::cast) 130 .orElse(null); 131 132 SynchronizationResult additionalResult = new SynchronizationResult(); 133 boolean hasChanges = _shareableCourseHelper.initializeShareableFields((Course) content, parentContent, UserPopulationDAO.SYSTEM_USER_IDENTITY, true); 134 additionalResult.setHasChanged(hasChanges); 135 136 result.aggregateResult(additionalResult); 137 return result; 138 } 139 140 @Override 141 protected String getChildrenSCCModelId() 142 { 143 return CourseListSynchronizableContentsCollection.MODEL_ID; 144 } 145 146 @Override 147 protected String getChildrenAttributeName() 148 { 149 return Course.CHILD_COURSE_LISTS; 150 } 151 152 /** 153 * Creates the course parts of the current {@link Course}. 154 * @param course The current {@link Course} 155 * @param logger The logger 156 * @return The list of the imported course parts 157 */ 158 protected List<ModifiableContent> importCourseParts(Content course, Logger logger) 159 { 160 List<ModifiableContent> courseParts = new ArrayList<>(); 161 String prefixTitle = course.getTitle() + " - "; 162 163 Map<String, Object> searchParams = putIdParameter(course.getValue(getIdField())); 164 List<Map<String, Object>> coursePartsData = _apogeeDAO.getCourseParts(getDataSourceId(), getParameterValues(), searchParams); 165 166 for (Map<String, Object> coursePartData : coursePartsData) 167 { 168 String typeHeure = coursePartData.get("COD_TYP_HEU").toString(); 169 String nature = Optional.ofNullable(_odfRefTableHelper.getItemFromCode(OdfReferenceTableHelper.ENSEIGNEMENT_NATURE, typeHeure)) 170 .map(OdfReferenceTableEntry::getId) 171 .orElse(null); 172 if (nature == null) 173 { 174 logger.warn("The nature '{}' is unknown for the course '{}'.", typeHeure, course.getTitle()); 175 } 176 else 177 { 178 // Create the course part 179 String coursePartTitle = prefixTitle + typeHeure; 180 CoursePart coursePart = (CoursePart) createContentAction(CoursePartFactory.COURSE_PART_CONTENT_TYPE, "course-part", 1, course.getLanguage(), coursePartTitle, logger); 181 if (coursePart != null) 182 { 183 try 184 { 185 Map<String, Object> coursePartValues = new HashMap<>(); 186 coursePartValues.put("nature", nature); 187 coursePartValues.put("nbHours", coursePartData.get("NBR_HEU_ELP")); 188 coursePartValues.put("courseHolder", course.getId()); 189 190 _editContent(coursePart, Optional.empty(), coursePartValues, Map.of(), true, Set.of(), logger); 191 courseParts.add(coursePart); 192 } 193 catch (WorkflowException e) 194 { 195 _nbError++; 196 logger.warn("An error occurred while synchronizing course part {}", coursePart, e); 197 } 198 } 199 } 200 } 201 202 return courseParts; 203 } 204}