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}