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("&", "&amp;").replaceAll("<", "&lt;").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}