mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
Merge pull request #2065 from canpan14/feature/2064-request-direct-access-url-file-name-option
File name param for direct access url requests
This commit is contained in:
commit
b66f9f604b
@ -102,18 +102,30 @@ public interface DeletedNodes
|
||||
CollectionWithPagingInfo<Rendition> getRenditions(String archivedId, Parameters parameters);
|
||||
|
||||
/**
|
||||
* Gets a presigned URL to directly access content.
|
||||
* Gets a presigned URL to directly access content.
|
||||
*
|
||||
* @param archivedId The node id for which to obtain the direct access {@code URL}
|
||||
* @param renditionId The rendition id for which to obtain the direct access {@code URL}
|
||||
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
*/
|
||||
* @param archivedId The node id for which to obtain the direct access {@code URL}
|
||||
* @param renditionId The rendition id for which to obtain the direct access {@code URL}
|
||||
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
*/
|
||||
default DirectAccessUrl requestContentDirectUrl(String archivedId, String renditionId, boolean attachment)
|
||||
{
|
||||
return requestContentDirectUrl(archivedId, renditionId, attachment, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param archivedId The node id for which to obtain the direct access {@code URL}
|
||||
* @param renditionId The rendition id for which to obtain the direct access {@code URL}
|
||||
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
|
||||
* @param validFor The time at which the direct access {@code URL} will expire.
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
*/
|
||||
default DirectAccessUrl requestContentDirectUrl(String archivedId, String renditionId, boolean attachment, Long validFor)
|
||||
{
|
||||
return requestContentDirectUrl(archivedId, renditionId, attachment, validFor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a presigned URL to directly access content.
|
||||
*
|
||||
@ -121,8 +133,9 @@ public interface DeletedNodes
|
||||
* @param renditionId The rendition id for which to obtain the direct access {@code URL}
|
||||
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
|
||||
* @param validFor The time at which the direct access {@code URL} will expire.
|
||||
* @param fileName Optional overide for file name
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
*/
|
||||
DirectAccessUrl requestContentDirectUrl(String archivedId, String renditionId, boolean attachment, Long validFor);
|
||||
DirectAccessUrl requestContentDirectUrl(String archivedId, String renditionId, boolean attachment, Long validFor, String fileName);
|
||||
|
||||
}
|
||||
|
@ -63,4 +63,10 @@ public class DirectAccessUrlHelper
|
||||
}
|
||||
return attachment;
|
||||
}
|
||||
|
||||
|
||||
public String getFileName(DirectAccessUrlRequest directAccessUrlRequest)
|
||||
{
|
||||
return directAccessUrlRequest != null ? directAccessUrlRequest.getFileName() : null;
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,20 @@ public interface Nodes
|
||||
* @param validFor The time at which the direct access {@code URL} will expire.
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
*/
|
||||
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor);
|
||||
default DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor)
|
||||
{
|
||||
return requestContentDirectUrl(nodeRef, attachment, validFor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a presigned URL to directly access content.
|
||||
* @param nodeRef The node reference for which to obtain the direct access {@code URL}
|
||||
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
|
||||
* @param validFor The time at which the direct access {@code URL} will expire.
|
||||
* @param fileName Optional name for the file when downloaded
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
*/
|
||||
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor, String fileName);
|
||||
|
||||
/**
|
||||
* Convert from node properties (map of QName to Serializable) retrieved from
|
||||
|
@ -251,7 +251,6 @@ public interface Renditions
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a presigned URL to directly access content.
|
||||
* @param nodeRef the node reference for which to obtain the direct access {@code URL}
|
||||
* @param versionId the version id (aka version label)
|
||||
* @param renditionId the rendition id
|
||||
@ -259,6 +258,21 @@ public interface Renditions
|
||||
* @param validFor the time at which the direct access {@code URL} will expire
|
||||
* @return a direct access {@code URL} object for the content.
|
||||
*/
|
||||
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, String versionId, String renditionId, boolean attachment, Long validFor);
|
||||
default DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, String versionId, String renditionId, boolean attachment, Long validFor)
|
||||
{
|
||||
return requestContentDirectUrl(nodeRef, versionId, renditionId, attachment, validFor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a presigned URL to directly access content.
|
||||
* @param nodeRef the node reference for which to obtain the direct access {@code URL}
|
||||
* @param versionId the version id (aka version label)
|
||||
* @param renditionId the rendition id
|
||||
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}
|
||||
* @param validFor the time at which the direct access {@code URL} will expire
|
||||
* @param fileName optional name for the file when downloaded
|
||||
* @return a direct access {@code URL} object for the content.
|
||||
*/
|
||||
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, String versionId, String renditionId, boolean attachment, Long validFor, String fileName);
|
||||
}
|
||||
|
||||
|
@ -250,18 +250,18 @@ public class DeletedNodesImpl implements DeletedNodes, RecognizedParamsExtractor
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public DirectAccessUrl requestContentDirectUrl(String originalNodeId, String renditionId, boolean attachment, Long validFor)
|
||||
public DirectAccessUrl requestContentDirectUrl(String originalNodeId, String renditionId, boolean attachment, Long validFor, String fileName)
|
||||
{
|
||||
//First check the node is valid and has been archived.
|
||||
NodeRef validatedNodeRef = nodes.validateNode(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, originalNodeId);
|
||||
|
||||
if (renditionId != null)
|
||||
{
|
||||
return renditions.requestContentDirectUrl(validatedNodeRef, null, renditionId, attachment, validFor);
|
||||
return renditions.requestContentDirectUrl(validatedNodeRef, null, renditionId, attachment, validFor, fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nodes.requestContentDirectUrl(validatedNodeRef, attachment, validFor);
|
||||
return nodes.requestContentDirectUrl(validatedNodeRef, attachment, validFor, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3443,9 +3443,9 @@ public class NodesImpl implements Nodes
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor)
|
||||
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor, String fileName)
|
||||
{
|
||||
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(nodeRef, ContentModel.PROP_CONTENT, attachment, validFor);
|
||||
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(nodeRef, ContentModel.PROP_CONTENT, attachment, validFor, fileName);
|
||||
if (directAccessUrl == null)
|
||||
{
|
||||
throw new DisabledServiceException("Direct access url isn't available.");
|
||||
|
@ -512,7 +512,7 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, String versionId, String renditionId, boolean attachment, Long validFor)
|
||||
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, String versionId, String renditionId, boolean attachment, Long validFor, String fileName)
|
||||
{
|
||||
final NodeRef validatedNodeRef = validateNode(nodeRef.getStoreRef(), nodeRef.getId(), versionId, null);
|
||||
NodeRef renditionNodeRef = getRenditionByName(validatedNodeRef, renditionId, null);
|
||||
@ -522,7 +522,7 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
|
||||
throw new NotFoundException("The rendition with id: " + renditionId + " was not found.");
|
||||
}
|
||||
|
||||
return nodes.requestContentDirectUrl(renditionNodeRef, attachment, validFor);
|
||||
return nodes.requestContentDirectUrl(renditionNodeRef, attachment, validFor, fileName);
|
||||
}
|
||||
|
||||
private BinaryResource getContentImpl(NodeRef nodeRef, String renditionId, Parameters parameters)
|
||||
|
@ -33,6 +33,7 @@ package org.alfresco.rest.api.model;
|
||||
public class DirectAccessUrlRequest
|
||||
{
|
||||
private Boolean attachment;
|
||||
private String fileName;
|
||||
|
||||
public Boolean isAttachment()
|
||||
{
|
||||
@ -43,4 +44,14 @@ public class DirectAccessUrlRequest
|
||||
{
|
||||
this.attachment = attachment;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
}
|
||||
}
|
||||
|
@ -137,12 +137,13 @@ public class NodeRenditionsRelation implements RelationshipResourceAction.Read<R
|
||||
{
|
||||
boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest);
|
||||
Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec();
|
||||
String fileName = directAccessUrlHelper.getFileName(directAccessUrlRequest);
|
||||
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId);
|
||||
|
||||
DirectAccessUrl directAccessUrl;
|
||||
try
|
||||
{
|
||||
directAccessUrl = renditions.requestContentDirectUrl(nodeRef, null, renditionId, attachment, validFor);
|
||||
directAccessUrl = renditions.requestContentDirectUrl(nodeRef, null, renditionId, attachment, validFor, fileName);
|
||||
}
|
||||
catch (DirectAccessUrlDisabledException ex)
|
||||
{
|
||||
|
@ -149,13 +149,14 @@ public class NodeVersionRenditionsRelation implements RelationshipResourceAction
|
||||
{
|
||||
boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest);
|
||||
Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec();
|
||||
String fileName = directAccessUrlHelper.getFileName(directAccessUrlRequest);
|
||||
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId);
|
||||
String renditionId = parameters.getRelationship2Id();
|
||||
|
||||
DirectAccessUrl directAccessUrl;
|
||||
try
|
||||
{
|
||||
directAccessUrl = renditions.requestContentDirectUrl(nodeRef, versionId, renditionId, attachment, validFor);
|
||||
directAccessUrl = renditions.requestContentDirectUrl(nodeRef, versionId, renditionId, attachment, validFor, fileName);
|
||||
}
|
||||
catch (DirectAccessUrlDisabledException ex)
|
||||
{
|
||||
|
@ -311,6 +311,7 @@ public class NodeVersionsRelation extends AbstractNodeRelation implements
|
||||
{
|
||||
boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest);
|
||||
Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec();
|
||||
String fileName = directAccessUrlHelper.getFileName(directAccessUrlRequest);
|
||||
Version version = findVersion(nodeId, versionId);
|
||||
if (version != null)
|
||||
{
|
||||
@ -319,7 +320,7 @@ public class NodeVersionsRelation extends AbstractNodeRelation implements
|
||||
DirectAccessUrl directAccessUrl;
|
||||
try
|
||||
{
|
||||
directAccessUrl = nodes.requestContentDirectUrl(versionNodeRef, attachment, validFor);
|
||||
directAccessUrl = nodes.requestContentDirectUrl(versionNodeRef, attachment, validFor, fileName);
|
||||
}
|
||||
catch (DirectAccessUrlDisabledException ex)
|
||||
{
|
||||
|
@ -211,12 +211,13 @@ public class NodesEntityResource implements
|
||||
{
|
||||
boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest);
|
||||
Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec();
|
||||
String fileName = directAccessUrlHelper.getFileName(directAccessUrlRequest);
|
||||
NodeRef nodeRef = nodes.validateNode(nodeId);
|
||||
|
||||
DirectAccessUrl directAccessUrl;
|
||||
try
|
||||
{
|
||||
directAccessUrl = nodes.requestContentDirectUrl(nodeRef, attachment, validFor);
|
||||
directAccessUrl = nodes.requestContentDirectUrl(nodeRef, attachment, validFor, fileName);
|
||||
}
|
||||
catch (DirectAccessUrlDisabledException ex)
|
||||
{
|
||||
|
@ -109,10 +109,11 @@ public class TrashcanEntityResource implements
|
||||
{
|
||||
boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest);
|
||||
Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec();
|
||||
String fileName = directAccessUrlHelper.getFileName(directAccessUrlRequest);
|
||||
DirectAccessUrl directAccessUrl;
|
||||
try
|
||||
{
|
||||
directAccessUrl = deletedNodes.requestContentDirectUrl(originalNodeId, null, attachment, validFor);
|
||||
directAccessUrl = deletedNodes.requestContentDirectUrl(originalNodeId, null, attachment, validFor, fileName);
|
||||
}
|
||||
catch (DirectAccessUrlDisabledException ex)
|
||||
{
|
||||
|
@ -98,10 +98,11 @@ public class TrashcanRenditionsRelation
|
||||
{
|
||||
boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest);
|
||||
Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec();
|
||||
String fileName = directAccessUrlHelper.getFileName(directAccessUrlRequest);
|
||||
DirectAccessUrl directAccessUrl;
|
||||
try
|
||||
{
|
||||
directAccessUrl = deletedNodes.requestContentDirectUrl(originalNodeId, renditionId, attachment, validFor);
|
||||
directAccessUrl = deletedNodes.requestContentDirectUrl(originalNodeId, renditionId, attachment, validFor, fileName);
|
||||
}
|
||||
catch (DirectAccessUrlDisabledException ex)
|
||||
{
|
||||
|
@ -65,6 +65,7 @@ import org.alfresco.service.cmr.usage.ContentQuotaException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
@ -627,7 +628,7 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, QName propertyQName, boolean attachment, Long validFor)
|
||||
public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, QName propertyQName, boolean attachment, Long validFor, String fileNameOverride)
|
||||
{
|
||||
if (!systemWideDirectUrlConfig.isEnabled())
|
||||
{
|
||||
@ -643,7 +644,7 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
|
||||
String contentUrl = contentData.getContentUrl();
|
||||
String contentMimetype = contentData.getMimetype();
|
||||
String fileName = getFileName(nodeRef);
|
||||
String fileName = StringUtils.isEmpty(fileNameOverride) ? getFileName(nodeRef) : fileNameOverride;
|
||||
|
||||
validFor = adjustValidFor(validFor);
|
||||
attachment = adjustAttachment(nodeRef, contentMimetype, attachment);
|
||||
|
@ -245,7 +245,25 @@ public interface ContentService
|
||||
* @throws UnsupportedOperationException if the store is unable to provide the information.
|
||||
*/
|
||||
@Auditable(parameters = {"nodeRef", "propertyQName", "validFor"})
|
||||
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, QName propertyQName, boolean attachment, Long validFor);
|
||||
default DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, QName propertyQName, boolean attachment, Long validFor)
|
||||
{
|
||||
return requestContentDirectUrl(nodeRef, propertyQName, attachment, validFor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a presigned URL to directly access the content. It is up to the actual store
|
||||
* implementation if it can fulfil this request with an expiry time or not.
|
||||
*
|
||||
* @param nodeRef Node ref for which to obtain the direct access {@code URL}.
|
||||
* @param propertyQName the name of the property, which must be of type <b>content</b>
|
||||
* @param attachment {@code true} if an attachment URL is requested, {@code false} for an embedded {@code URL}.
|
||||
* @param validFor The time at which the direct access {@code URL} will expire.
|
||||
* @param fileName Optional name for the file when downloaded
|
||||
* @return A direct access {@code URL} object for the content.
|
||||
* @throws UnsupportedOperationException if the store is unable to provide the information.
|
||||
*/
|
||||
@Auditable(parameters = {"nodeRef", "propertyQName", "validFor"})
|
||||
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, QName propertyQName, boolean attachment, Long validFor, String fileName);
|
||||
|
||||
/**
|
||||
* Gets a key-value (String-String) collection of storage headers/properties with their respective values for a specific node reference.
|
||||
|
@ -72,7 +72,8 @@ public class ContentServiceImplUnitTest
|
||||
|
||||
private static final NodeRef NODE_REF = new NodeRef("content://Node/Ref");
|
||||
public static final String SOME_CONTENT_URL = "someContentUrl";
|
||||
private static final NodeRef NODE_REF_2 = new NodeRef("content://Node/Ref2");;
|
||||
private static final NodeRef NODE_REF_2 = new NodeRef("content://Node/Ref2");
|
||||
public static final String SOME_FILE_NAME = "someFilename";
|
||||
|
||||
private static final String X_AMZ_HEADER_1 = "x-amz-header1";
|
||||
private static final String VALUE_1 = "value1";
|
||||
@ -103,7 +104,7 @@ public class ContentServiceImplUnitTest
|
||||
when(mockNodeService.getProperty(NODE_REF, ContentModel.PROP_CONTENT)).thenReturn(mockContentData);
|
||||
when(mockContentData.getContentUrl()).thenReturn(SOME_CONTENT_URL);
|
||||
when(mockContentData.getMimetype()).thenReturn("someMimetype");
|
||||
when(mockNodeService.getProperty(NODE_REF, ContentModel.PROP_NAME)).thenReturn("someFilename");
|
||||
when(mockNodeService.getProperty(NODE_REF, ContentModel.PROP_NAME)).thenReturn(SOME_FILE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -162,6 +163,40 @@ public class ContentServiceImplUnitTest
|
||||
verify(mockContentStore, times(1)).requestContentDirectUrl(anyString(), eq(true), anyString(), anyString(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestContentDirectUrl_StoreRequestContentDirectUrlIsCalledWithFileNameOverride()
|
||||
{
|
||||
final String fileNameOverride = "fileNameOverride.txt";
|
||||
setupSystemWideDirectAccessConfig(ENABLED);
|
||||
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(ENABLED);
|
||||
|
||||
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(NODE_REF, PROP_CONTENT_QNAME, true, 20L, fileNameOverride);
|
||||
assertNull(directAccessUrl);
|
||||
verify(mockContentStore, times(1)).requestContentDirectUrl(anyString(), eq(true), eq(fileNameOverride), anyString(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestContentDirectUrl_StoreRequestContentDirectUrlIsCalledWithNodeNamePropertyWhenFileNameOverrideIsNull()
|
||||
{
|
||||
setupSystemWideDirectAccessConfig(ENABLED);
|
||||
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(ENABLED);
|
||||
|
||||
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(NODE_REF, PROP_CONTENT_QNAME, true, 20L, null);
|
||||
assertNull(directAccessUrl);
|
||||
verify(mockContentStore, times(1)).requestContentDirectUrl(anyString(), eq(true), eq(SOME_FILE_NAME), anyString(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestContentDirectUrl_StoreRequestContentDirectUrlIsCalledWithNodeNamePropertyWhenFileNameOverrideIsEmpty()
|
||||
{
|
||||
setupSystemWideDirectAccessConfig(ENABLED);
|
||||
when(mockContentStore.isContentDirectUrlEnabled()).thenReturn(ENABLED);
|
||||
|
||||
DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(NODE_REF, PROP_CONTENT_QNAME, true, 20L, "");
|
||||
assertNull(directAccessUrl);
|
||||
verify(mockContentStore, times(1)).requestContentDirectUrl(anyString(), eq(true), eq(SOME_FILE_NAME), anyString(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnStoragePropertiesWhenTheyExist()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user