Allowing Customer Community Plus users to download files from an Experience site


Today we'll check a solution to allow non-admin users to download files from an Experience site.

I have an experience site that has a custom component that should allow for users to download the file when clicking on it. Currently here's how the file download is handled, we can easily get this solution from a quick Googling + Stack Overflow cycle:

window.open(`/sfc/servlet.shepherd/document/download/${event.currentTarget.dataset.documentid}?operationContext=S1`);

This works flawlessly for admin users, however when other users, like Customer Community Plus users (which are the only others I have tested, to be fair), try to download the file, we get the following:

err-login

Googling for "To access this page, you have to log in to Services Catalog." combined with terms like "permissions" or "Customer Community Plus" doesn't really help either, so reading further down the Salesforce document rabit hole (and after checking out a teammate's code), I saw we can try using the concept of the Content Distribution object.

Let's try it out by checking if we have a content distribution created for our file and then leveraging that or creating a new one if needed.

@AuraEnabled
  public static string getFileDownloadURL(String documentId) {
    try {
      List<ContentDistribuion> conDist = [
        SELECT Id, DistributionPublicUrl
        FROM ContentDistribution
        WHERE ContentDocumentId = :documentId
      ];
      if (conDist.size() > 0) {
        return conDist[0].DistributionPublicUrl;
      } else {
        ContentVersion cv = [
          SELECT Id, Title
          FROM ContentVersion
          WHERE ContentDocumentId = :documentId
        ];
        ContentDistribution cd = new ContentDistribution();
        cd.Name = cv.Title + ' Distribution';
        cd.ContentVersionId = cv.Id;
        cd.PreferencesAllowViewInBrowser = true;
        cd.PreferencesNotifyOnVisit = false;
        cd.PreferencesPasswordRequired = false;
        cd.PreferencesLinkLatestVersion = true;
        insert cd;

        List<ContentDistribuion> conDist = [
          SELECT Id, DistributionPublicUrl
          FROM ContentDistribution
          WHERE ContentDocumentId = :documentId
        ];
        if (conDist.size() > 0) {
          return conDist[0].DistributionPublicUrl;
        } else {
          return '';
        }
      }
    } catch (Exception e) {
      throw new AuraHandledException(e.getMessage());
    }
  }

Now we just need to use the code in our component, remeber to import the method and the call it from our JS handler:

import getFileDownloadURL from '@salesforce/apex/myController.getFileDownloadURL';

const fileUrl = await getFileDownloadURL({ documentId: event.currentTarget.dataset.documentid });
window.open(fileUrl);

We can also use 'ContentDownloadUrl' instead of 'DistributionPublicUrl' on the Apex code. This will make the file be downloaded straight away, instead of opening it in a new tab with some Salesforce overlay.

That's it for today, see ya!

References: