001/* 002 * Copyright 2020 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.workspaces.workflow; 017 018import java.io.ByteArrayInputStream; 019import java.io.IOException; 020import java.nio.charset.StandardCharsets; 021import java.time.ZonedDateTime; 022import java.util.Map; 023 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.commons.lang3.StringUtils; 027 028import org.ametys.cms.data.RichText; 029import org.ametys.cms.data.type.AbstractRichTextElementType; 030import org.ametys.cms.repository.ModifiableContent; 031import org.ametys.cms.repository.WorkflowAwareContent; 032import org.ametys.cms.workflow.AbstractContentWorkflowComponent; 033import org.ametys.core.util.I18nUtils; 034import org.ametys.plugins.repository.version.VersionableAmetysObject; 035import org.ametys.plugins.workflow.EnhancedFunction; 036import org.ametys.runtime.i18n.I18nizableText; 037import org.ametys.runtime.model.type.ModelItemType; 038 039import com.opensymphony.module.propertyset.PropertySet; 040import com.opensymphony.workflow.WorkflowException; 041 042/** 043 * This workflow function initialize the rich-text's content with a configured default value 044 * 045 */ 046public class InitContentFunction extends AbstractContentWorkflowComponent implements EnhancedFunction 047{ 048 private static final String __RICHTEXT_ATTRIBUTE_KEY = "attribute"; 049 private static final String __RICHTEXT_VALUE_KEY = "value"; 050 private static final String __RICHTEXT_IS_I18N_KEY = "isI18n"; 051 private static final String __RICHTEXT_I18N_CATALOG_KEY = "i18nCatalogue"; 052 private static final String __RICHTEXT_ACTIVATE_COMMENTS_KEY = "activateComments"; 053 054 /** I18n Utils */ 055 protected I18nUtils _i18nUtils; 056 057 @Override 058 public void service(ServiceManager manager) throws ServiceException 059 { 060 super.service(manager); 061 _i18nUtils = (I18nUtils) manager.lookup(org.ametys.core.util.I18nUtils.ROLE); 062 } 063 064 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 065 { 066 _logger.info("Performing content initialisation"); 067 068 try 069 { 070 WorkflowAwareContent content = getContent(transientVars); 071 072 String attributePath = (String) args.get(__RICHTEXT_ATTRIBUTE_KEY); 073 if (StringUtils.isEmpty(attributePath)) 074 { 075 attributePath = "content"; 076 } 077 078 boolean isI18N = "true".equals(args.get(__RICHTEXT_IS_I18N_KEY)); 079 String i18nCatalogue = (String) args.get(__RICHTEXT_I18N_CATALOG_KEY); 080 if (StringUtils.isEmpty(i18nCatalogue)) 081 { 082 // Use application as default catalogue 083 i18nCatalogue = "application"; 084 } 085 086 String value = (String) args.get(__RICHTEXT_VALUE_KEY); 087 if (StringUtils.isBlank(value)) 088 { 089 _logger.warn(String.format("Missing 'value' argument for workflow function %s, the content '%s' will not be initialized with default value", InitContentFunction.class.getName(), content.getId())); 090 return; 091 } 092 093 if (!(content instanceof ModifiableContent)) 094 { 095 _logger.warn(String.format("Content '%s' is not a modifiable content. It will not be initialized with default value", content.getId())); 096 return; 097 } 098 099 String defaultValue = ""; 100 if (isI18N) 101 { 102 I18nizableText text = new I18nizableText(i18nCatalogue, value); 103 defaultValue = _i18nUtils.translate(text, content.getLanguage()); 104 } 105 else 106 { 107 defaultValue = value; 108 } 109 110 if (content.hasDefinition(attributePath)) 111 { 112 ModelItemType type = content.getDefinition(attributePath).getType(); 113 if (type instanceof AbstractRichTextElementType) 114 { 115 _setRichText((ModifiableContent) content, attributePath, defaultValue); 116 } 117 else 118 { 119 _setText((ModifiableContent) content, attributePath, defaultValue); 120 } 121 } 122 123 boolean activeComments = "true".equals(args.get(__RICHTEXT_ACTIVATE_COMMENTS_KEY)); 124 if (activeComments && content.hasDefinition("comment")) 125 { 126 ((ModifiableContent) content).setValue("comment", true); 127 } 128 129 // save changes 130 content.saveChanges(); 131 132 if (content instanceof VersionableAmetysObject) 133 { 134 // create version 135 ((VersionableAmetysObject) content).checkpoint(); 136 } 137 } 138 catch (IOException e) 139 { 140 throw new WorkflowException("Unable to set the rich text in the content", e); 141 } 142 } 143 144 private void _setText(ModifiableContent content, String attributePath, String value) 145 { 146 content.setValue(attributePath, value); 147 } 148 149 private void _setRichText(ModifiableContent content, String attributePath, String value) throws IOException 150 { 151 RichText richText = new RichText(); 152 153 String docbook = _textToDocbook(value); 154 ByteArrayInputStream is = new ByteArrayInputStream(docbook.getBytes(StandardCharsets.UTF_8)); 155 156 richText.setInputStream(is); 157 richText.setEncoding("UTF-8"); 158 richText.setMimeType("text/xml"); 159 richText.setLastModificationDate(ZonedDateTime.now()); 160 161 content.setValue(attributePath, richText); 162 } 163 164 private String _textToDocbook (String value) 165 { 166 StringBuilder sb = new StringBuilder(); 167 168 sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 169 sb.append("<article version=\"5.0\" xmlns=\"http://docbook.org/ns/docbook\">"); 170 171 sb.append("<para>"); 172 sb.append(value.replaceAll("&", "&").replaceAll("<", "<").replaceAll("\r?\n", "<phrase role=\"linebreak\"/>")); 173 sb.append("</para>"); 174 175 sb.append("</article>"); 176 177 return sb.toString(); 178 } 179 180 @Override 181 public FunctionType getFunctionExecType() 182 { 183 return FunctionType.PRE; 184 } 185 186 @Override 187 public I18nizableText getLabel() 188 { 189 return new I18nizableText("plugin.workspaces", "PLUGINS_WORKSPACES_INIT_CONTENT_FUNCTION_LABEL"); 190 } 191}