diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml index a2d7488a76..7e41d59118 100644 --- a/config/alfresco/public-rest-context.xml +++ b/config/alfresco/public-rest-context.xml @@ -442,10 +442,24 @@ + + + + application/pdf + image/jpeg + image/gif + image/png + image/tiff + image/bmp + + + + + diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index 37e7ef4611..8d648f8228 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -102,6 +102,10 @@ import java.util.Set; /** * Centralises access to file/folder/node services and maps between representations. + * + * Note: + * This class was originally used for returning some basic node info when listing Favourites. + * It has now been re-purposed and extended to implement the new File Folder (RESTful) API. * * @author steveglover * @author janv @@ -140,6 +144,12 @@ public class NodesImpl implements Nodes private Set defaultIgnoreTypes; private Set ignoreTypeQNames; + private Set nonAttachContentTypes = Collections.EMPTY_SET; // pre-configured whitelist, eg. images & pdf + + public void setNonAttachContentTypes(Set nonAttachWhiteList) { + this.nonAttachContentTypes = nonAttachWhiteList; + } + public void init() { this.namespaceService = sr.getNamespaceService(); @@ -1154,14 +1164,36 @@ public class NodesImpl implements Nodes throw new InvalidArgumentException("NodeId of content is expected: "+nodeRef); } - ContentData cd = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + Map nodeProps = nodeService.getProperties(nodeRef); + ContentData cd = (ContentData)nodeProps.get(ContentModel.PROP_CONTENT); + String name = (String)nodeProps.get(ContentModel.PROP_NAME); + org.alfresco.rest.framework.resource.content.ContentInfo ci = null; if (cd != null) { ci = new org.alfresco.rest.framework.resource.content.ContentInfoImpl(cd.getMimetype(), cd.getEncoding(), cd.getSize(), cd.getLocale()); } - // TODO attachment header - update (or extend ?) REST fwk - return new NodeBinaryResource(nodeRef, ContentModel.PROP_CONTENT, ci); + // By default set attachment header (with filename) unless attachment=false *and* content type is pre-configured as non-attach + boolean attach = true; + String attachment = parameters.getParameter("attachment"); + if (attachment != null) + { + Boolean a = new Boolean(attachment); + if ((a != null) && (a == false)) + { + if (nonAttachContentTypes.contains(cd.getMimetype())) + { + attach = false; + } + else + { + logger.warn("Ignored attachment=false for "+fileNodeId+" since "+cd.getMimetype()+" is not in the whitelist for non-attach content types"); + } + } + } + String attachFileName = (attach ? name : null); + + return new NodeBinaryResource(nodeRef, ContentModel.PROP_CONTENT, ci, attachFileName); } @Override diff --git a/source/java/org/alfresco/rest/framework/resource/content/NodeBinaryResource.java b/source/java/org/alfresco/rest/framework/resource/content/NodeBinaryResource.java index 15730e8aef..d02c377234 100755 --- a/source/java/org/alfresco/rest/framework/resource/content/NodeBinaryResource.java +++ b/source/java/org/alfresco/rest/framework/resource/content/NodeBinaryResource.java @@ -32,13 +32,16 @@ public class NodeBinaryResource implements BinaryResource final NodeRef nodeRef; final QName propertyQName; final ContentInfo contentInfo; + final String attachFileName; - public NodeBinaryResource(NodeRef nodeRef, QName propertyQName, ContentInfo contentInfo) + public NodeBinaryResource(NodeRef nodeRef, QName propertyQName, ContentInfo contentInfo, String attachFileName) { super(); + this.nodeRef = nodeRef; this.propertyQName = propertyQName; this.contentInfo = contentInfo; + this.attachFileName = attachFileName; } public NodeRef getNodeRef() @@ -54,4 +57,8 @@ public class NodeBinaryResource implements BinaryResource public ContentInfo getContentInfo() { return this.contentInfo; } + + public String getAttachFileName() { + return this.attachFileName; + } } diff --git a/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java b/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java index 271f30d2b3..1613790812 100644 --- a/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java +++ b/source/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ package org.alfresco.rest.framework.webscripts; import java.io.IOException; @@ -23,6 +41,7 @@ import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; +import org.springframework.extensions.surf.util.URLEncoder; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; @@ -39,6 +58,7 @@ import org.springframework.http.HttpMethod; * 5) Renders the response * * @author Gethin James + * @author janv */ // TODO for requests that pass in input streams e.g. binary content for workflow, this is going to need a way to re-read the input stream a la // code in RepositoryContainer due to retrying transaction logic @@ -52,6 +72,8 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements private ContentStreamer streamer; protected ResourceWebScriptHelper helper; + public final static String HDR_NAME_CONTENT_DISPOSITION = "Content-Disposition"; + @SuppressWarnings("rawtypes") @Override public void execute(final Api api, final WebScriptRequest req, final WebScriptResponse res) throws IOException @@ -72,6 +94,17 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements { respons.put("toSerialize", result); respons.put("contentInfo", contentInfo); + + if (result instanceof NodeBinaryResource) + { + String attachFileName = ((NodeBinaryResource)result).getAttachFileName(); + if ((attachFileName != null) && (attachFileName.length() > 0)) + { + String headerValue = "attachment; filename=\"" + attachFileName + "\"; filename*=UTF-8''" + URLEncoder.encode(attachFileName); + res.setHeader(HDR_NAME_CONTENT_DISPOSITION, headerValue); + } + } + if (params.getStatus().getRedirect()) { res.setStatus(params.getStatus().getCode());