Blogs

Blogs

Crafting document download links in a velocity asset publisher ADT

This short post brings together the little pieces critical to crafting an ADT in velocity to provide direct download links to documents in your Documents and Media repository. You will find parts of this solution strewn across forums and blogs. 
 
In essence, you'll have to do two things:
1. Add the following property to your portal-ext.properties if you have not done so yet. If you've been using the serviceLocator to pull in various Liferay service APIs in your ADTs, then you've likely done this already.
velocity.engine.restricted.variables=
 
That just says no variables are restricted in your ADTs.
 
2. Craft the document's download URL. Your document download URL should looks like this:
/documents/<groupId>/<folderId>/<document-title>/<document-uuid>?version=<version>
For example:
/documents/10181/11405/College+Sample+Doc.docx/7a5680cf-8de5-4d65-b179-72ee5c9f5966?version=1.0
Here's the velocity markup to do the above. There are freemarker versions of this all over the place. 
 
In the above code, you may have noticed the call:
$fileEntry.getLatestFileVersion(false)
 
That boolearn parameter is named trusted, and basically, this is what the code looks like in the implementation (just in case you're curious).
 
public DLFileVersion getLatestFileVersion(boolean trusted) throws PortalException, SystemException {
  if (trusted) {
    return DLFileVersionLocalServiceUtil.getLatestFileVersion(getFileEntryId(),false);
  }
 else {
    return DLFileVersionServiceUtil.getLatestFileVersion(getFileEntryId());
  }
}
 
I think that means that if trusted is true, then the working copy (Draft) is heeded as the latest version. Otherwise it is not. (Call me out on that if I'm off the mark.)
 
Hope this saves someone out there a little time.
Followed the article for liferay 7 set-up on my machine. Looks like set($dlFileEntryLocalService = $serviceLocator.findService("com.liferay.portlet.documentlibrary.service.DLFileEntryLocalService")) is not fetching/loading the service.
In brief , uploaded files using "Document and Media" portlet and viewing in "Asset Publisher" portlet. Created vm file (https://github.com/javeedchida/temperateprogrammer/blob/master/velocity-document-download-links/adt-document-downloads.vm) and applied to "Asset Publisher" portlet.

Click on entries results in location not found http://localhost:8080/documents/$fileEntry.getGroupId()/$fileEntry.getFolderId()/$httpUtil.encodeURL($htmlUtil.unescape($fileEntry.getTitle()))/$fileEntry.getUuid()?version=$version.getVersion()
RESOLVED "serviceLocator" access issue in ADT.
On Liferay 7, changed/remove "Restricted Variable" value to empty or some X from "serviceLocator".

To do so, go to "Control Panel"-->"Configuration"-->"System Settings"-->"Foundation" tab-->"Velocity Engine" (Edit).
Like you say, parts of your solution can be found on the forums etc.
But they have one thing in common: they all require serviceLocator/staticUtil to be exposed to velocity/freemarker.
We see this as a security issue, so I am not happy with it.
In the end however, it turns out to be a lot easier than messing around with DLEntry's, file versions, etc.:
On the AssetRenderer-interface, there's a method getURLDownload(ThemeDisplay), which exactly does what we want:

https://docs.liferay.com/portal/6.2/javadocs-all/com/liferay/portlet/asset/model/AssetRenderer.html#getURLDownload(com.liferay.portal.theme.ThemeDisplay)

So you can just use it like this (freemarker):
<div>
<#list entries as entry>
<div>
<a href="${entry.getAssetRenderer().getURLDownload(themeDisplay)}" target="_blank">${entry.getTitle()}</a>
</div>
</#list>
</div>

Hope this helps...