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