Nov 202014

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 & Attachements 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.

inline-vf-chatter-files

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);
    }
    
}

Code for VF page





	 
		
		
			
							
					
										
				
				
				
					
					 
				

	           
					
					
						
					
				

				
					
					 
							
			

			
				
				
			
		
	
	

Tagged with , , , , , , 2 comments
2 Responses to Salesforce – How to retrieve list of Chatter Files related to a record
  1. Antonius Meliat

    Many thanks for your Salesforce ? How to “how to retrieve list of Chatter Files related to a record”. The GoToNewFiles method points to ‘/apex/ChatterFilesNew’. Can you provide the code for this as well. I’ve come this far following your how-to and I’m stuck here. Many thanks in advance for your help

  2. Grzegorz Skaruz

    @Antonius I’ve send you the code and I’ve updated the post.

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.