I've been trying to create a VF page for a customer community where the customer user can view all the Files on their own Account as a simple list. Internal users are adding these Files as Chatter posts with the access set to include the community. It seems like it should be simple, but the wonky (or wonky-appearing) access control is making my code really ugly.
The problem is that if I query ContentVersion or ContentDocument, I only get the Files that are shared to the current user directly, via Group-membership, or globally shared. But they really have access to the File if it is shared to the Community and posted on their Account.
Whereas, if I query FeedItem, I get all the FeedItems on the Account, whether the user can really see them or not (which seems like a bug in access control, but that's another story/question). If I provide the user with that list, they can get a load of links that will go through to permissions errors.
What I've ended up doing is getting the FeedItems and then using getContent() to find out whether or not the current user can see them. But it seems horrible.
Is there a better way?
VF:
<apex:pageMessages id="messages" />
<apex:pageBlock title="Files">
<apex:pageBlockTable value="{!feedItems}" var="thisFeedItem">
<apex:column headerValue="Name">
<apex:outputLink value="/{!thisFeedItem.RelatedRecordId}">{!thisFeedItem.ContentFileName}</apex:outputLink>
</apex:column>
<apex:column headerValue="Size (KB)" value="{!TEXT(ROUND(thisFeedItem.ContentSize/1024.0,0))} " />
<apex:column headerValue="Created Date" value="{!thisFeedItem.CreatedDate} " />
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
Controller:
public class ClientPortalFilesController {
public List<FeedItem> feedItems {get; set;}
public ClientPortalFilesController() {
User thisUser = [SELECT Id, AccountId FROM User WHERE Id = :UserInfo.getUserId()];
Id accountId;
if(thisUser.AccountId == null) {
List<Account> accs = [SELECT id FROM Account WHERE Name = 'ACME'];
if(!accs.isEmpty()) {
accountId = accs[0].id;
}
} else {
accountId = thisUser.AccountId;
}
feedItems = [SELECT Id, ContentFileName, RelatedRecordId, CreatedDate, ContentSize
FROM FeedItem
WHERE ParentId = :accountId
ORDER BY CreatedDate DESC
LIMIT 100
];
Set<Id> contentVersionIds = new Set<Id>();
List<FeedItem> accessibleFeedItems = new List<FeedItem>();
for(FeedItem fi : feedItems) {
try {
(new PageReference('/' + fi.RelatedRecordId)).getContent();
accessibleFeedItems.add(fi);
} catch(Exception e) {
System.debug('Failed to read ' + fi.ContentFileName);
// OK, not accessible, don't care much
}
}
feedItems = accessibleFeedItems;
}
}