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