001/*
002 * (C) Copyright 2011-2016 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Thierry Delprat
018 */
019package org.nuxeo.template.web;
020
021import java.util.ArrayList;
022import java.util.List;
023
024import javax.faces.model.SelectItem;
025
026import org.jboss.seam.ScopeType;
027import org.jboss.seam.annotations.Factory;
028import org.jboss.seam.annotations.In;
029import org.jboss.seam.annotations.Name;
030import org.jboss.seam.annotations.Observer;
031import org.jboss.seam.annotations.Scope;
032import org.jboss.seam.annotations.intercept.BypassInterceptors;
033import org.jboss.seam.faces.FacesMessages;
034import org.jboss.seam.international.StatusMessage;
035import org.nuxeo.ecm.core.api.Blob;
036import org.nuxeo.ecm.core.api.DocumentModel;
037import org.nuxeo.ecm.core.api.IdRef;
038import org.nuxeo.ecm.core.api.NuxeoException;
039import org.nuxeo.ecm.core.api.PropertyException;
040import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
041import org.nuxeo.ecm.core.api.security.SecurityConstants;
042import org.nuxeo.ecm.platform.ui.web.api.WebActions;
043import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils;
044import org.nuxeo.ecm.webapp.contentbrowser.DocumentActions;
045import org.nuxeo.ecm.webapp.helpers.EventManager;
046import org.nuxeo.ecm.webapp.helpers.EventNames;
047import org.nuxeo.ecm.webapp.helpers.ResourcesAccessor;
048import org.nuxeo.runtime.api.Framework;
049import org.nuxeo.template.api.TemplateInput;
050import org.nuxeo.template.api.TemplateProcessorService;
051import org.nuxeo.template.api.adapters.TemplateBasedDocument;
052import org.nuxeo.template.api.adapters.TemplateSourceDocument;
053
054@Name("templateBasedActions")
055@Scope(ScopeType.CONVERSATION)
056public class TemplateBasedActionBean extends BaseTemplateAction {
057
058    private static final long serialVersionUID = 1L;
059
060    @In(create = true)
061    protected transient DocumentActions documentActions;
062
063    @In(create = true)
064    protected transient WebActions webActions;
065
066    @In(create = true, required = false)
067    protected FacesMessages facesMessages;
068
069    @In(create = true)
070    protected ResourcesAccessor resourcesAccessor;
071
072    protected List<TemplateInput> templateInputs;
073
074    protected String templateIdToAssociate;
075
076    protected String editableTemplateName;
077
078    public String createTemplate() {
079        DocumentModel changeableDocument = navigationContext.getChangeableDocument();
080        TemplateSourceDocument sourceTemplate = changeableDocument.getAdapter(TemplateSourceDocument.class);
081        if (sourceTemplate != null && sourceTemplate.getTemplateBlob() != null) {
082            try {
083                sourceTemplate.initTemplate(false);
084                if (sourceTemplate.hasEditableParams()) {
085                    templateInputs = sourceTemplate.getParams();
086                    return "editTemplateRelatedData";
087                }
088            } catch (PropertyException e) {
089                log.error("Error during parameter automatic initialization", e);
090                facesMessages.add(StatusMessage.Severity.ERROR,
091                        resourcesAccessor.getMessages().get("label.template.err.parameterInit"));
092            }
093        }
094        return documentActions.saveDocument(changeableDocument);
095    }
096
097    public List<TemplateInput> getTemplateInputs() {
098        return templateInputs;
099    }
100
101    public void setTemplateInputs(List<TemplateInput> templateInputs) {
102        this.templateInputs = templateInputs;
103    }
104
105    public String saveDocument() {
106        DocumentModel changeableDocument = navigationContext.getChangeableDocument();
107
108        for (TemplateInput ti : templateInputs) {
109            log.info(ti.toString());
110        }
111        TemplateSourceDocument source = changeableDocument.getAdapter(TemplateSourceDocument.class);
112        if (source != null) {
113            source.saveParams(templateInputs, false);
114        }
115
116        return documentActions.saveDocument(changeableDocument);
117    }
118
119    @Observer(value = { EventNames.DOCUMENT_SELECTION_CHANGED, EventNames.NEW_DOCUMENT_CREATED,
120            EventNames.DOCUMENT_CHANGED }, create = false)
121    @BypassInterceptors
122    public void reset() {
123        templateInputs = null;
124        templateEditableInputs = null;
125        editableTemplateName = null;
126        templateIdToAssociate = null;
127    }
128
129    public List<TemplateInput> getTemplateEditableInputs() {
130        if (editableTemplateName == null) {
131            return new ArrayList<>();
132        }
133        if (templateEditableInputs == null) {
134            DocumentModel currentDocument = navigationContext.getCurrentDocument();
135
136            TemplateBasedDocument templateBasedDoc = currentDocument.getAdapter(TemplateBasedDocument.class);
137            templateEditableInputs = templateBasedDoc.getParams(editableTemplateName);
138        }
139        return templateEditableInputs;
140    }
141
142    public void setTemplateEditableInputs(List<TemplateInput> templateEditableInputs) {
143        this.templateEditableInputs = templateEditableInputs;
144    }
145
146    public String saveTemplateInputs() {
147
148        DocumentModel currentDocument = navigationContext.getCurrentDocument();
149
150        TemplateBasedDocument template = currentDocument.getAdapter(TemplateBasedDocument.class);
151        if (template != null) {
152            currentDocument = template.saveParams(editableTemplateName, templateEditableInputs, true);
153        }
154        reset();
155        navigationContext.invalidateCurrentDocument();
156        return navigationContext.navigateToDocument(currentDocument);
157    }
158
159    public void cancelTemplateInputsEdit() {
160        reset();
161    }
162
163    public TemplateInput getNewInput() {
164        if (newInput == null) {
165            newInput = new TemplateInput("newField");
166        }
167        return newInput;
168    }
169
170    public void setNewInput(TemplateInput newInput) {
171        this.newInput = newInput;
172    }
173
174    public String render(String templateName) {
175        DocumentModel currentDocument = navigationContext.getCurrentDocument();
176        TemplateBasedDocument doc = currentDocument.getAdapter(TemplateBasedDocument.class);
177        if (doc == null) {
178            return null;
179        }
180        try {
181            Blob rendition = doc.renderWithTemplate(templateName);
182            String filename = rendition.getFilename();
183            ComponentUtils.download(currentDocument, null, rendition, filename, "templateRendition");
184            return null;
185        } catch (NuxeoException e) {
186            log.error("Unable to render template ", e);
187            facesMessages.add(StatusMessage.Severity.ERROR,
188                    resourcesAccessor.getMessages().get("label.template.err.renderingFailed"));
189            return null;
190        }
191    }
192
193    public String renderAndStore(String templateName) {
194
195        DocumentModel currentDocument = navigationContext.getCurrentDocument();
196        TemplateBasedDocument doc = currentDocument.getAdapter(TemplateBasedDocument.class);
197        if (doc == null) {
198            return null;
199        }
200        doc.renderAndStoreAsAttachment(templateName, true);
201        documentManager.save();
202        return navigationContext.navigateToDocument(doc.getAdaptedDoc());
203    }
204
205    @Override
206    public boolean canResetParameters() {
207        DocumentModel currentDocument = navigationContext.getCurrentDocument();
208        if (!documentManager.hasPermission(currentDocument.getRef(), SecurityConstants.WRITE)) {
209            return false;
210        }
211        TemplateBasedDocument templateBased = currentDocument.getAdapter(TemplateBasedDocument.class);
212        if (templateBased != null) {
213            return true;
214        }
215        return false;
216    }
217
218    public void resetParameters(String templateName) {
219        DocumentModel currentDocument = navigationContext.getCurrentDocument();
220        TemplateBasedDocument templateBased = currentDocument.getAdapter(TemplateBasedDocument.class);
221        if (templateBased != null) {
222            templateBased.initializeFromTemplate(templateName, true);
223            templateEditableInputs = null;
224        }
225    }
226
227    public boolean canDetachTemplate(String templateName) {
228        DocumentModel currentDocument = navigationContext.getCurrentDocument();
229        if (!documentManager.hasPermission(currentDocument.getRef(), SecurityConstants.WRITE)) {
230            return false;
231        }
232        TemplateBasedDocument templateBased = currentDocument.getAdapter(TemplateBasedDocument.class);
233        if (templateBased != null) {
234            return true;
235        }
236        return false;
237    }
238
239    public String detachTemplate(String templateName) {
240        DocumentModel currentDocument = navigationContext.getCurrentDocument();
241        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
242        DocumentModel detachedDocument = tps.detachTemplateBasedDocument(currentDocument, templateName, true);
243        webActions.resetTabList();
244        // because of cacheKey issue
245        navigationContext.setCurrentDocument(null);
246        return navigationContext.navigateToDocument(detachedDocument);
247    }
248
249    public String getTemplateIdToAssociate() {
250        return templateIdToAssociate;
251    }
252
253    public void setTemplateIdToAssociate(String templateIdToAssociate) {
254        this.templateIdToAssociate = templateIdToAssociate;
255    }
256
257    public void associateDocumentToTemplate() {
258        if (templateIdToAssociate == null) {
259            // return null;
260            return;
261        }
262        DocumentModel currentDocument = navigationContext.getCurrentDocument();
263        DocumentModel sourceTemplate = documentManager.getDocument(new IdRef(templateIdToAssociate));
264        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
265        try {
266            currentDocument = tps.makeTemplateBasedDocument(currentDocument, sourceTemplate, true);
267        } catch (NuxeoException e) {
268            log.error("Unable to do template association", e);
269            facesMessages.add(StatusMessage.Severity.ERROR,
270                    resourcesAccessor.getMessages().get("label.template.err.associationFailed"),
271                    sourceTemplate.getName());
272        }
273        navigationContext.invalidateCurrentDocument();
274        EventManager.raiseEventsOnDocumentChange(currentDocument);
275        templateIdToAssociate = null;
276    }
277
278    public boolean canRenderAndStore() {
279        DocumentModel currentDocument = navigationContext.getCurrentDocument();
280        // check that templating is supported
281        TemplateBasedDocument template = currentDocument.getAdapter(TemplateBasedDocument.class);
282        if (template == null) {
283            return false;
284        }
285        // check that we can store the result
286        BlobHolder bh = currentDocument.getAdapter(BlobHolder.class);
287        if (bh == null) {
288            return false;
289        }
290        return true;
291    }
292
293    public String getEditableTemplateName() {
294        return editableTemplateName;
295    }
296
297    public void setEditableTemplateName(String editableTemplateName) {
298        if (editableTemplateName == null || !editableTemplateName.equals(this.editableTemplateName)) {
299            this.editableTemplateName = editableTemplateName;
300            templateEditableInputs = null;
301        }
302    }
303
304    public List<TemplateSourceDocument> getBindableTemplatesForDocument() {
305        DocumentModel currentDocument = navigationContext.getCurrentDocument();
306        String targetType = currentDocument.getType();
307        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
308        List<DocumentModel> templates = tps.getAvailableTemplateDocs(documentManager, targetType);
309
310        List<TemplateSourceDocument> result = new ArrayList<>();
311        TemplateBasedDocument currentTBD = currentDocument.getAdapter(TemplateBasedDocument.class);
312        List<String> alreadyBoundTemplateNames = new ArrayList<>();
313        if (currentTBD != null) {
314            alreadyBoundTemplateNames = currentTBD.getTemplateNames();
315        }
316        for (DocumentModel doc : templates) {
317            TemplateSourceDocument source = doc.getAdapter(TemplateSourceDocument.class);
318            if (!alreadyBoundTemplateNames.contains(source.getName())) {
319                result.add(source);
320            }
321        }
322        return result;
323
324    }
325
326    public List<SelectItem> getBindableTemplatesForDocumentAsSelectItems() {
327
328        List<SelectItem> items = new ArrayList<>();
329        List<TemplateSourceDocument> sources = getBindableTemplatesForDocument();
330        for (TemplateSourceDocument sd : sources) {
331            DocumentModel doc = sd.getAdaptedDoc();
332            String label = doc.getTitle();
333            if (doc.isVersion()) {
334                label = label + " (V " + doc.getVersionLabel() + ")";
335            }
336            items.add(new SelectItem(doc.getId(), label));
337        }
338
339        return items;
340    }
341
342    public boolean canBindNewTemplate() {
343        DocumentModel currentDocument = navigationContext.getCurrentDocument();
344        if (!currentDocument.getCoreSession().hasPermission(currentDocument.getRef(), SecurityConstants.WRITE)) {
345            return false;
346        }
347        if (getBindableTemplatesForDocument().size() == 0) {
348            return false;
349        }
350        return true;
351    }
352
353    @Factory(value = "currentTemplateBasedDocument", scope = ScopeType.EVENT)
354    public TemplateBasedDocument getCurrentDocumentAsTemplateBasedDocument() {
355        return navigationContext.getCurrentDocument().getAdapter(TemplateBasedDocument.class);
356    }
357
358    @Factory(value = "associatedRenderableTemplates", scope = ScopeType.EVENT)
359    public List<TemplateSourceDocument> getRenderableTemplates() {
360        List<TemplateSourceDocument> result = new ArrayList<>();
361        TemplateBasedDocument template = getCurrentDocumentAsTemplateBasedDocument();
362        if (template != null) {
363            List<TemplateSourceDocument> sources = template.getSourceTemplates();
364            for (TemplateSourceDocument source : sources) {
365                if (source.getTargetRenditionName() == null || source.getTargetRenditionName().isEmpty()) {
366                    result.add(source);
367                }
368            }
369        }
370        return result;
371    }
372}