001/*
002 *  Copyright 2018 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.workflow;
017
018import java.util.List;
019import java.util.Map;
020import java.util.Optional;
021import java.util.function.Function;
022
023import org.apache.commons.lang3.StringUtils;
024
025import org.ametys.cms.repository.ContentQueryHelper;
026import org.ametys.cms.repository.ContentTypeExpression;
027import org.ametys.cms.repository.ModifiableContent;
028import org.ametys.cms.repository.ModifiableDefaultContent;
029import org.ametys.cms.workflow.CreateContentFunction;
030import org.ametys.odf.ProgramItem;
031import org.ametys.odf.course.CourseFactory;
032import org.ametys.odf.coursepart.CoursePart;
033import org.ametys.odf.coursepart.CoursePartFactory;
034import org.ametys.plugins.repository.AmetysObjectIterable;
035import org.ametys.plugins.repository.query.expression.AndExpression;
036import org.ametys.plugins.repository.query.expression.Expression;
037import org.ametys.plugins.repository.query.expression.Expression.Operator;
038import org.ametys.plugins.repository.query.expression.StringExpression;
039
040import com.opensymphony.workflow.WorkflowException;
041
042/**
043 * OSWorkflow function for creating a {@link CoursePart} content
044 */
045public class CreateCoursePartFunction extends AbstractCreateODFContentFunction
046{
047    /** Content name prefix for programs */
048    public static final String CONTENT_NAME_PREFIX = "coursepart-";
049    
050    /** Constant for storing the catalog name to use into the transient variables map. */
051    public static final String COURSE_HOLDER_KEY = AbstractCreateODFContentFunction.class.getName() + "$courseHolder";
052
053    @SuppressWarnings("unchecked")
054    @Override
055    protected void _populateAdditionalData(Map transientVars, ModifiableContent content) throws WorkflowException
056    {
057        super._populateAdditionalData(transientVars, content);
058        
059        Optional<String> catalogName = Optional.ofNullable(transientVars.get(CONTENT_CATALOG_KEY))
060                .map(String.class::cast)
061                .filter(StringUtils::isNotEmpty);
062
063        // Used to get the catalog if the course part item is created by java code, like for the csv import.
064        if (!catalogName.isPresent())
065        {
066            catalogName = Optional.ofNullable(transientVars.get(CreateContentFunction.INITIAL_VALUE_SUPPLIER))
067                    .map(Function.class::cast)
068                    .map(function -> function.apply(List.of(ProgramItem.CATALOG)))
069                    .map(String.class::cast)
070                    .filter(StringUtils::isNotEmpty);
071        }
072
073        if (catalogName.isPresent() && StringUtils.isNotEmpty(catalogName.get()) && content instanceof CoursePart)
074        {
075            ((CoursePart) content).setCatalog(catalogName.get());
076        }
077
078        Optional<String> courseHolder = Optional.ofNullable(transientVars.get(COURSE_HOLDER_KEY))
079                .map(String.class::cast)
080                .filter(StringUtils::isNotEmpty);
081
082        // Used to get the courseHolder if the course part item is created by java code, like for the csv import.
083        if (!courseHolder.isPresent())
084        {
085            courseHolder = Optional.ofNullable(transientVars.get(CreateContentFunction.INITIAL_VALUE_SUPPLIER))
086                    .map(Function.class::cast)
087                    .map(function -> function.apply(List.of(CoursePart.PARENT_COURSES, ProgramItem.CODE)))
088                    .map(String.class::cast)
089                    .map(code -> 
090                    {
091                        Expression idExpression = new StringExpression(ProgramItem.CODE, Operator.EQ, code);
092                        
093                        Expression expression = new AndExpression(
094                                new ContentTypeExpression(Operator.EQ, CourseFactory.COURSE_CONTENT_TYPE),
095                                idExpression);
096
097                        String xPathQuery = ContentQueryHelper.getContentXPathQuery(expression);
098                        AmetysObjectIterable<ModifiableDefaultContent> matchingContents = _resolver.query(xPathQuery);
099                        if (matchingContents.getSize() == 1)
100                        {
101                            ModifiableDefaultContent course = matchingContents.iterator().next();
102                            return course.getId();
103                        }
104                        return null;
105                    })
106                    .filter(StringUtils::isNotEmpty);
107        }
108
109        // Used to get the courseHolder if the course part item is created by java code, like for the csv import.
110        if (!courseHolder.isPresent())
111        {
112            courseHolder = Optional.ofNullable(transientVars.get(CreateContentFunction.PARENT_CONTEXT_VALUE))
113                    .map(String.class::cast)
114                    .filter(StringUtils::isNotEmpty);
115        }
116
117        if (courseHolder.isPresent() && StringUtils.isNotEmpty(courseHolder.get()) && content instanceof CoursePart)
118        {
119            content.setValue(CoursePart.COURSE_HOLDER, courseHolder.get());
120        }
121        
122        String code = content.getValue(CoursePart.CODE);
123        if (StringUtils.isEmpty(code))
124        {
125            content.setValue(CoursePart.CODE, org.ametys.core.util.StringUtils.generateKey().toUpperCase());
126        }
127    }
128    
129    @Override
130    protected String _getContentNamePrefix()
131    {
132        return CONTENT_NAME_PREFIX;
133    }
134    
135    @Override
136    protected String _getNodeType()
137    {
138        return CoursePartFactory.COURSE_PART_NODETYPE;
139    }
140}