ACS-306: ACS Repository: V1 Rest API for content direct access urls (#1046)

- added alfresco.content.directAccessUrl.expiryTime.seconds property to allow the configuration of the direct access url expiry time
   - changed getDirectAccessUrl method signature to allow the successful execution of the acl interceptor
   - moved get content data to it's own method so it can be easily reused
   - updated test
This commit is contained in:
Cristian Turlica
2020-06-17 09:11:32 +03:00
committed by GitHub
parent 3c318660a8
commit 4d98b56426
4 changed files with 69 additions and 43 deletions

View File

@@ -370,39 +370,8 @@ public class ContentServiceImpl extends ContentTransformServiceAdaptor implement
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private ContentReader getReader(NodeRef nodeRef, QName propertyQName, boolean fireContentReadPolicy) private ContentReader getReader(NodeRef nodeRef, QName propertyQName, boolean fireContentReadPolicy)
{ {
ContentData contentData = null; ContentData contentData = getContentData(nodeRef, propertyQName);
Serializable propValue = nodeService.getProperty(nodeRef, propertyQName);
if (propValue instanceof Collection)
{
Collection<Serializable> colPropValue = (Collection<Serializable>)propValue;
if (colPropValue.size() > 0)
{
propValue = colPropValue.iterator().next();
}
}
if (propValue instanceof ContentData)
{
contentData = (ContentData)propValue;
}
if (contentData == null)
{
PropertyDefinition contentPropDef = dictionaryService.getProperty(propertyQName);
// if no value or a value other content, and a property definition has been provided, ensure that it's CONTENT or ANY
if (contentPropDef != null &&
(!(contentPropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT) ||
contentPropDef.getDataType().getName().equals(DataTypeDefinition.ANY))))
{
throw new InvalidTypeException("The node property must be of type content: \n" +
" node: " + nodeRef + "\n" +
" property name: " + propertyQName + "\n" +
" property type: " + ((contentPropDef == null) ? "unknown" : contentPropDef.getDataType()),
propertyQName);
}
}
// check that the URL is available // check that the URL is available
if (contentData == null || contentData.getContentUrl() == null) if (contentData == null || contentData.getContentUrl() == null)
@@ -439,6 +408,43 @@ public class ContentServiceImpl extends ContentTransformServiceAdaptor implement
return reader; return reader;
} }
private ContentData getContentData(NodeRef nodeRef, QName propertyQName)
{
ContentData contentData = null;
Serializable propValue = nodeService.getProperty(nodeRef, propertyQName);
if (propValue instanceof Collection)
{
Collection<Serializable> colPropValue = (Collection<Serializable>)propValue;
if (colPropValue.size() > 0)
{
propValue = colPropValue.iterator().next();
}
}
if (propValue instanceof ContentData)
{
contentData = (ContentData)propValue;
}
if (contentData == null)
{
PropertyDefinition contentPropDef = dictionaryService.getProperty(propertyQName);
// if no value or a value other content, and a property definition has been provided, ensure that it's CONTENT or ANY
if (contentPropDef != null &&
(!(contentPropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT) ||
contentPropDef.getDataType().getName().equals(DataTypeDefinition.ANY))))
{
throw new InvalidTypeException("The node property must be of type content: \n" +
" node: " + nodeRef + "\n" +
" property name: " + propertyQName + "\n" +
" property type: " + ((contentPropDef == null) ? "unknown" : contentPropDef.getDataType()),
propertyQName);
}
}
return contentData;
}
public ContentWriter getWriter(NodeRef nodeRef, QName propertyQName, boolean update) public ContentWriter getWriter(NodeRef nodeRef, QName propertyQName, boolean update)
{ {
if (nodeRef == null) if (nodeRef == null)
@@ -503,11 +509,20 @@ public class ContentServiceImpl extends ContentTransformServiceAdaptor implement
} }
@Override @Override
public String getDirectAccessUrl(String contentUrl, int expiryTime) public String getDirectAccessUrl(NodeRef nodeRef, int expiryTime)
{ {
ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT);
// check that the URL is available
if (contentData == null || contentData.getContentUrl() == null)
{
// there is no URL - the interface specifies that this is not an error condition
return null;
}
if (store.isDirectAccessSupported()) if (store.isDirectAccessSupported())
{ {
return store.getDirectAccessUrl(contentUrl, expiryTime); return store.getDirectAccessUrl(contentData.getContentUrl(), expiryTime);
} }
return ""; return "";
} }

View File

@@ -154,12 +154,18 @@ public interface ContentService extends ContentTransformService
public ContentWriter getTempWriter(); public ContentWriter getTempWriter();
/** /**
* Gets a presigned URL to directly access a binary content. It is up to the content store * Gets a presigned URL to directly access a binary content. It is up to the
* if it can fulfil this request with an expiry time or not. * content store if it can fulfil this request with an expiry time (in
* milliseconds) or not.
* *
* @param contentUrl A content store URL * @param nodeRef
* @param expiryTime Expiration time in milliseconds * a reference to a node having a content property
* @return A direct access URL for a binary content or empty string if not supported * @param expiryTime
* the expiration time in milliseconds of the direct access url. This
* is the length of time in milliseconds that the link is valid for.
* @return A direct access URL for a binary content or returns null if there is
* no binary content for the node or empty string if not supported
*/ */
public String getDirectAccessUrl(String contentUrl, int expiryTime); @Auditable(parameters = {"nodeRef", "expiryTime"})
public String getDirectAccessUrl(NodeRef nodeRef, int expiryTime);
} }

View File

@@ -1327,4 +1327,8 @@ system.delete_not_exists.batchsize=100000
system.delete_not_exists.delete_batchsize=1000 system.delete_not_exists.delete_batchsize=1000
system.delete_not_exists.read_only=false system.delete_not_exists.read_only=false
system.delete_not_exists.timeout_seconds=-1 system.delete_not_exists.timeout_seconds=-1
system.prop_table_cleaner.algorithm=V2 system.prop_table_cleaner.algorithm=V2
# Configure the expiration time of the direct access url. This is the length of time in seconds that the link is valid for.
# Note: It is up to the actual ContentStore implementation if it can fulfil this request or not.
alfresco.content.directAccessUrl.expiryTime.seconds=28800

View File

@@ -189,7 +189,8 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
@Test @Test
public void testWhenGetDirectAccessUrlIsNotSupported() public void testWhenGetDirectAccessUrlIsNotSupported()
{ {
assertEquals("", contentService.getDirectAccessUrl("s3v2://1234421", 10)); NodeRef versionableNode = createNewVersionableNode();
assertEquals("", contentService.getDirectAccessUrl(versionableNode, 10));
assertFalse(contentStore.isDirectAccessSupported()); assertFalse(contentStore.isDirectAccessSupported());
} }