Salesforce – How to retrieve list of Chatter Files related to a record?

Files associated with a record can be stored in 2 ways: as an attachment (in the Notes & Attachments related list) as well as Salesforce Content (using Chatter Files).

Recently I had a task to create Visualforce pages, which put on the Page Layout as inline Visualforce showed the files posted by Chatter Files associated with the record. Adding files was carried out by the Chatter. Assigning Topics to an entry in Chatter allowed to filter files by this as a category.

The code is prepared as a component, so it can be used in many places.

Apex class:

public with sharing class ChatterFiles { 

    public List<FeedItem> files { get; set; }     
    public string category { get; set; }     
    public Id recordId { get 
                            {    return recordId;    }
                        set { 
                                recordId = value; 
                                SearchFiles();
                            }
                        }

    public class entry {
        public FeedItem item { get; set; }
        public List<string> topics { get; set; }
        public string categories { get; set; }
    }
    public List<entry> items { get; set; }     
            
    public ChatterFiles() {
        items = new List<entry>();
    }
        
    public void SearchFiles () {        
        items.clear();
        List<FeedItem> feedFiles = [ SELECT Id, CreatedById, CreatedDate, Body, CommentCount, ContentFileName, ContentDescription, 
                                         InsertedById, ParentId, RelatedRecordId, Title, Type
                                          FROM FeedItem 
                                         WHERE Type = 'ContentPost' AND ParentId = :this.recordId
                                         ORDER BY CreatedDate DESC
                                    ];
        
        Set<Id> feedIds = new Set<Id> (new Map<Id,SObject>(feedFiles).keySet());
        List<TopicAssignment> topicList = [ SELECT Topic.Name, TopicId, Id, EntityId FROM TopicAssignment WHERE EntityId IN :feedIds ORDER BY Topic.Name ASC];
        
        for(FeedItem f : feedFiles){           
               List<string> topics = new List<string>();
            entry line = new entry();
            boolean validCategory = false;
            line.item = f;
            line.categories = '';
            for(TopicAssignment t : topicList){
                if (t.EntityId == f.Id) {
                    topics.add(t.Topic.Name);
                    line.categories += t.Topic.Name + ', ';
                    if (this.category == t.Topic.Name) {
                        validCategory = true;
                    }
                }
            }
            if (line.categories.length()>4) {
                line.categories = line.categories.substring(0, line.categories.length()-2);                
            }
            line.topics = topics;

            // is selected Category and Feed contains valid category OR category is not selected              
            if ((String.isNotEmpty(this.category) && (validCategory)) || String.isEmpty(this.category)) {
                items.add(line);            
            }           
        }
    }
        
    public List<Selectoption> getTopicItems(){
        List<SelectOption> options = new List<SelectOption>();  
        options.add(new SelectOption('', '-- select --'); 
        
        List<FeedItem> filesForTopics = [ SELECT Id, CreatedById, CreatedDate, Body, CommentCount, ContentFileName, ContentDescription, 
                                          InsertedById, ParentId, RelatedRecordId, Title, Type
                                           FROM FeedItem 
                                          WHERE Type = 'ContentPost' AND ParentId = :this.recordId 
                                          ORDER BY CreatedDate DESC
                                         ];        
        
        Set<Id> topicIds = new Set<Id> (new Map<Id,SObject>(filesForTopics).keySet());
                         
        List<TopicAssignment> topicList = [ SELECT Topic.Name, TopicId, Id, EntityId FROM TopicAssignment WHERE EntityId IN :topicIds ORDER BY Topic.Name ASC];

        Set<Id> myset = new Set<Id>();
        List<TopicAssignment> result = new List<TopicAssignment>();
        for (TopicAssignment t : topicList) {
            if (!myset.contains(t.TopicId)) {
                myset.add(t.TopicId);
                options.add(new SelectOption(t.Topic.Name, t.Topic.Name)); 
            }
        }

        return options;
    }
    
    public PageReference GoToNewFile() {
        PageReference pageRef = new PageReference('/apex/ChatterFilesNew');        
        pageRef.setRedirect(true);
        return pageRef;
    }    
}

Component code

<apex:component controller="ChatterFiles">
    <apex:attribute name="textId" description="This is ID of the record" type="String" required="true" assignTo="{!recordId}" />

    <apex:pageBlock id="pageBlock">
        <apex:form >
        </apex:form>

        <apex:form >
            <div style="text-align: right">            
            Category: &nbsp;
            <apex:selectList value="{!category}" multiselect="false" id="category" size="1" style="margin: 10px 0;" >
                <apex:selectOptions value="{!TopicItems}" />
                <apex:actionSupport event="onchange" action="{!SearchFiles}" rerender="pageBlock" />
            </apex:selectList>
            </div>
            
            <div align="center" draggable="false" >
                <apex:outputLink value="/apex/ChatterFilesNew?parentId={!recordId}" target="_top" styleClass="btn" style="text-decoration: none; padding: 3px 5px; margin-bottom: 10px; display: inline-block; ">Create</apex:outputLink>
            </div>        
            
        </apex:form>
         
        <apex:pageBlockTable value="{!items}" var="list" id="files">
            <apex:column headerValue="Name" >
                 <apex:outputLink value="/{!list.item.Id}" target="_top">{!list.item.ContentFileName} </apex:outputLink>
            </apex:column>
            <apex:column headerValue="Description" >
                 <apex:outputText >{!list.item.Body} {!list.item.ContentDescription} </apex:outputText>
            </apex:column>
            <apex:column headerValue="Category" >
                 <apex:outputText value="{!list.categories}"/>
            </apex:column>
            <apex:column headerValue="Created Date" >
                 <apex:outputField value="{!list.item.CreatedDate}"/>
            </apex:column>
            <apex:column headerValue="Author" >
                 <apex:outputField value="{!list.item.CreatedById}"/>
            </apex:column>
            </apex:pageBlockTable>
    </apex:pageBlock> 
</apex:component>

VF page code with component. In the following example Resource__c is the name of the custom object:

<apex:page standardController="Resource__c">
    <c:ChatterFiles textId="{!Resource__c.Id}" />  
</apex:page>

Code for adding files

public with sharing class ChatterFilesNew {

    public ContentVersion file { get; set; }
    public string title { get; set; }
    public Id parentId { get; set; }
    public List topics { get; set; }
    public string newTopic { get; set; }
    
    public ChatterFilesNew() {
        file = new ContentVersion();
	    file.Origin = 'H';
		this.parentId = Apexpages.currentPage().getParameters().get('parentId');
    }

    public List getTopicItems(){
    	List options = new List();  
        //options.add(new SelectOption('', Label.ResSearchSelect));        
        List tps = [ SELECT Id, Name FROM Topic ORDER BY Name ASC ];
        for(Topic t : tps ){ 
  	        options.add(new SelectOption(t.Id, t.Name)); 
        }
        return options;
    }

    public PageReference save() {
        insert file;

	    FeedItem fi = new FeedItem(Body = this.title + '', ParentId = this.parentId, RelatedRecordId = file.id, Type = 'ContentPost');
	    insert fi;
	    
	    for (string t : topics) {
	    	TopicAssignment ta = new TopicAssignment();
			ta.TopicId = t;
			ta.EntityId = fi.Id;	
			insert ta;	    	
	    }	    
	    
	    if (String.isNotempty(this.newTopic)) {
	    		    	
			List strings = newTopic.split(',');
		    for (string s : strings) {
			    Topic tpc = new Topic(Name = s.trim());
			    insert tpc;
	
		    	TopicAssignment ta = new TopicAssignment();
				ta.TopicId = tpc.Id;
				ta.EntityId = fi.Id;
				insert ta;
		    }
	    }
        return new PageReference('/' + parentId);
    }    
	   
    public PageReference cancel() {
        return new PageReference('/' + parentId);
    }
    
}

Leave a Reply

Your email address will not be published. Required fields are marked *