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.odf.ose.export.impl.odf; 017 018import java.util.List; 019import java.util.Optional; 020import java.util.Set; 021 022import org.apache.avalon.framework.component.Component; 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.repository.Content; 029import org.ametys.cms.repository.ContentQueryHelper; 030import org.ametys.cms.repository.ContentTypeExpression; 031import org.ametys.cms.repository.LanguageExpression; 032import org.ametys.odf.ProgramItem; 033import org.ametys.odf.enumeration.OdfReferenceTableEntry; 034import org.ametys.odf.enumeration.OdfReferenceTableHelper; 035import org.ametys.odf.orgunit.OrgUnit; 036import org.ametys.odf.ose.db.ParameterizableQuery; 037import org.ametys.odf.ose.export.OSEConstants; 038import org.ametys.odf.ose.export.impl.odf.db.EtapeHelper; 039import org.ametys.odf.ose.export.utils.ElementRetriever; 040import org.ametys.odf.program.Container; 041import org.ametys.odf.program.ContainerFactory; 042import org.ametys.plugins.repository.AmetysObjectIterable; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.plugins.repository.EmptyIterable; 045import org.ametys.plugins.repository.query.expression.AndExpression; 046import org.ametys.plugins.repository.query.expression.BooleanExpression; 047import org.ametys.plugins.repository.query.expression.Expression; 048import org.ametys.plugins.repository.query.expression.Expression.Operator; 049import org.ametys.plugins.repository.query.expression.NotExpression; 050import org.ametys.plugins.repository.query.expression.StringExpression; 051import org.ametys.runtime.config.Config; 052import org.ametys.runtime.model.ModelHelper; 053import org.ametys.runtime.plugin.component.AbstractLogEnabled; 054 055/** 056 * Exporter of steps 057 */ 058public class StepExporter extends AbstractLogEnabled implements Component, Serviceable 059{ 060 /** Avalon Role */ 061 public static final String ROLE = StepExporter.class.getName(); 062 063 /** The ODF enumeration helper */ 064 protected OdfReferenceTableHelper _refTableHelper; 065 /** The Ametys object resolver */ 066 protected AmetysObjectResolver _resolver; 067 /** The retriever of elements from ODF */ 068 protected ElementRetriever _elementRetriever; 069 070 @Override 071 public void service(ServiceManager manager) throws ServiceException 072 { 073 _refTableHelper = (OdfReferenceTableHelper) manager.lookup(OdfReferenceTableHelper.ROLE); 074 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 075 _elementRetriever = (ElementRetriever) manager.lookup(ElementRetriever.ROLE); 076 } 077 078 /** 079 * Get all the {@link Container} that are steps (nature is "annee") and are exportable (attribute "noOseExport" is not <code>true</code>) 080 * @param ametysCatalog The Ametys catalog 081 * @return The list of exportable steps 082 */ 083 public AmetysObjectIterable<Container> getStepsToExport(String ametysCatalog) 084 { 085 // Add values for steps (container with nature equals to year) 086 return Optional.ofNullable(_refTableHelper.getItemFromCode(OdfReferenceTableHelper.CONTAINER_NATURE, "annee")) 087 .map(OdfReferenceTableEntry::getId) 088 .map(anneeId -> _matchingStepsExpression(anneeId, ametysCatalog)) 089 .map(ContentQueryHelper::getContentXPathQuery) 090 .map(_resolver::<Container>query) 091 .orElseGet(EmptyIterable::new); 092 } 093 094 private Expression _matchingStepsExpression(String anneeId, String ametysCatalog) 095 { 096 Expression contentTypeExpr = new ContentTypeExpression(Operator.EQ, ContainerFactory.CONTAINER_CONTENT_TYPE); 097 String lang = Config.getInstance().getValue("odf.programs.lang"); 098 Expression langExpr = new LanguageExpression(Operator.EQ, lang); 099 Expression catalogExpr = new StringExpression(ProgramItem.CATALOG, Operator.EQ, ametysCatalog); 100 Expression natureExpr = new StringExpression(Container.NATURE, Operator.EQ, anneeId); 101 Expression doExportExpression = new NotExpression(new BooleanExpression(OSEConstants.NO_OSE_EXPORT_ATTRIBUTE_NAME, true)); 102 103 return new AndExpression(contentTypeExpr, langExpr, catalogExpr, natureExpr, doExportExpression); 104 } 105 106 /** 107 * Get queries to export the given step. 108 * @param step The step to export 109 * @param oseCatalog The OSE catalog 110 * @return A {@link List} of {@link ParameterizableQuery} to export the {@link Container}, it can be empty if there is a problem (see logs) 111 */ 112 public List<ParameterizableQuery> getQueries(Container step, Long oseCatalog) 113 { 114 // Degree : Remonter aux formations parentes et prendre les degrees, s'il n'y en a qu'une prendre son code, sinon erreur 115 Set<OdfReferenceTableEntry> degrees = _elementRetriever.retrieveDegree(step); 116 117 // Structure : Remonter parent par parent pour obtenir le ou les structures rattachées (sur abstractProgram) 118 Set<OrgUnit> orgUnits = _elementRetriever.retrieveOrgUnits(step); 119 120 if (degrees.size() != 1 || orgUnits.size() != 1) 121 { 122 LogUtils.stepImpossibilityDegreesOrOrgunits(getLogger(), step, degrees, orgUnits); 123 return List.of(); 124 } 125 126 OdfReferenceTableEntry degree = _getFirstDegree(degrees); 127 String degreeCode = degree.getCode(); 128 String orgUnitCode = _getFirstOrgUnitCode(orgUnits); 129 Optional<String> functionalDomain = _getFunctionalDomain(degree); 130 131 if (functionalDomain.isEmpty()) 132 { 133 LogUtils.stepImpossibilityFunctDomain(getLogger(), step); 134 return List.of(); 135 } 136 137 return _getQueries(step, oseCatalog, degreeCode, orgUnitCode, functionalDomain.get()); 138 } 139 140 private Optional<String> _getFunctionalDomain(OdfReferenceTableEntry degree) 141 { 142 Expression expr = new AndExpression( 143 new ContentTypeExpression(Operator.EQ, "odf-enumeration.DegreeCategory"), 144 new StringExpression("degrees", Operator.EQ, degree.getId()) 145 ); 146 147 String xpathQuery = ContentQueryHelper.getContentXPathQuery(expr); 148 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 149 150 return contents 151 .stream() 152 .findFirst() 153 .map(c -> c.<String>getValue("functionalDomain")); 154 } 155 156 private OdfReferenceTableEntry _getFirstDegree(Set<OdfReferenceTableEntry> degrees) 157 { 158 return degrees.stream() 159 .findFirst() 160 .get(); 161 } 162 163 private String _getFirstOrgUnitCode(Set<OrgUnit> orgUnits) 164 { 165 return orgUnits.stream() 166 .findFirst() 167 .map(OrgUnit::getUAICode) 168 .get(); 169 } 170 171 private List<ParameterizableQuery> _getQueries(Container container, Long oseCatalog, String degree, String orgUnit, String functionalDomain) 172 { 173 String title = container.getTitle(); 174 if (ModelHelper.hasModelItem("etpCode", container.getModel())) 175 { 176 String apogee = container.getValue("etpCode"); 177 if (StringUtils.isNotEmpty(apogee)) 178 { 179 title += " (" + apogee + ")"; 180 } 181 } 182 String code = container.getCode(); 183 184 return EtapeHelper.insertInto(code, title, oseCatalog, degree, orgUnit, functionalDomain); 185 } 186} 187