Class: Salesforce::ChatterFeed

Inherits:
Object
  • Object
show all
Defined in:
lib/salesforce/chatter_feed.rb

Overview

This is the abstract to the ‘XXXFeed’ table in Salesforce Chatter

Note: FeedPost cannot be directly queried. It must go through its parent. For example: SELECT Id, Type, FeedPost.Body FROM AccountFeed WHERE ParentId = AccountId ORDER BY CreatedDate DESC

SalesObject’s 3 digits code for the KeyPrefix:

ID   Prefix	Entity Type
001	Account
006	Opportunity
003	Contact
00Q	Lead
701	Campaign
00V	Campaign Member
00D	Organization
005	User
00E	Profile
00N	Custom Field Definition

0D5  FeedItem (post by everyone)
0F7  FeedPost (post made by this user)

See: eng.genius.com/blog/2009/05/17/salesforcecom-api-gotchas-2/

Constant Summary collapse

BASE_FRAG =

fields do

timestamps

end

"Id, CreatedDate, Type, CreatedBy.Name, CreatedBy.Id"
FEEDPOST_WITH_CONTENT_DATA_FRAG =
<<-HERE
FeedPost.Id, FeedPost.FeedItemId, FeedPost.ParentId, FeedPost.Type,
FeedPost.CreatedById, FeedPost.CreatedDate, FeedPost.SystemModStamp,
FeedPost.Title, FeedPost.Body, FeedPost.LinkUrl,
FeedPost.ContentData, FeedPost.ContentFileName, FeedPost.ContentDescription,
FeedPost.ContentType, FeedPost.ContentSize
HERE
FEEDPOST_WITHOUT_CONTENT_DATA_FRAG =
<<-HERE
FeedPost.Id, FeedPost.FeedItemId, FeedPost.ParentId, FeedPost.Type,
FeedPost.CreatedById, FeedPost.CreatedDate, FeedPost.SystemModStamp,
FeedPost.Title, FeedPost.Body, FeedPost.LinkUrl, FeedPost.ContentSize
HERE
CREATOR_FRAG =
"CreatedBy.FirstName, CreateBy.LastName, CreatedBy.Id"
FEED_TRACKED_CHANGE_FRAG =
<<-HERE
Select Id, FieldName, OldValue, NewValue From FeedTrackedChanges
  ORDER BY Id Desc
HERE
FEED_COMMENT_FRAG =
<<-HERE
Select Id, CommentBody, CreatedDate, CreatedBy.Id, CreatedBy.FirstName,
  CreatedBy.LastName FROM FeedComments ORDER BY CreatedDate
HERE

Instance Method Summary collapse

Constructor Details

#initializeChatterFeed

Returns a new instance of ChatterFeed.



25
26
27
28
29
30
31
# File 'lib/salesforce/chatter_feed.rb', line 25

def initialize
  #### define @logger
  # http://ruby-doc.org/core/classes/@logger.html
  # TODO use a log file, rather than Standout
  @logger = Logger.new(STDOUT)
  #@logger.level = @logger::WARN
end

Instance Method Details

#get_all_chatter_feeds_with_attachments(object_id, object_type, binding, directory_name, limit = 100, get_attachment = true, query_string = nil) ⇒ Object

  1. It returns the attached file.

  2. ‘object_id’ corresponds to the ‘parent_id’ column in the ‘XXXFeed’ table

  3. ‘object_type’ can be one of the followings

    Account, Asset, Campaign, Case, Lead, Contact, Contract, Opportunity,
    Product2, Solution, User
    **Note**: UserProfileFeed and NewsFeed are special cases.
      UserProfileFeed  -> select ... from UserProfileFeed with Userid='userid'
      NewsFeed -> select ... from NewsFeed where parentid = 'userid'
    
  4. ‘binding’ can be passed in directly or using the inherited binding from the ‘Salesforce::SfBase’ base class.

  5. ‘directory_name is the directory in ’public/tmp’ for saving the attachment

  6. ‘limit is the number of records to return

  7. ‘get_attachment’ is a boolean flag, true gets the attachment,

    false does not get the attachment
    
  8. query_string is used to search against the Salesforce. Note, if “object_id’ is specified, query_string is ignored.

  9. returns Ruby Array of matching records

  10. TODO add conditions, e.g.

    search -> where FeedPost.CreatedDate > 2007-08-06T03:23:00.000Z and FeedPost.Body like '%post%'
    pagination ->
    


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/salesforce/chatter_feed.rb', line 97

def get_all_chatter_feeds_with_attachments(object_id, object_type, binding, directory_name, limit=100, get_attachment=true, query_string=nil)
  begin
    #e.g. select Id, type, FeedPost.body from UserProfileFeed WITH UserId = '005A0000000S8aIIAS'
    if !object_id.nil?
      qstring = <<-HERE
      SELECT #{BASE_FRAG}, #{FEEDPOST_WITHOUT_CONTENT_DATA_FRAG},
      (#{FEED_TRACKED_CHANGE_FRAG}), (#{FEED_COMMENT_FRAG} LIMIT #{limit})
      FROM #{object_type}Feed where parentid = \'#{object_id}\'
      ORDER BY CreatedDate DESC limit #{limit}
      HERE
    elsif !query_string.nil?
      # this is more like a search....
      qstring = <<-HERE
      SELECT #{BASE_FRAG}, #{FEEDPOST_WITHOUT_CONTENT_DATA_FRAG},
      (#{FEED_TRACKED_CHANGE_FRAG}), (#{FEED_COMMENT_FRAG} LIMIT #{limit})
      FROM #{object_type}Feed where FeedPost.Body like \'%#{query_string}%\'
      ORDER BY CreatedDate DESC limit #{limit}
      HERE
    else
      qstring = <<-HERE
      SELECT #{BASE_FRAG}, #{FEEDPOST_WITHOUT_CONTENT_DATA_FRAG},
      (#{FEED_TRACKED_CHANGE_FRAG}), (#{FEED_COMMENT_FRAG} LIMIT #{limit})
      FROM #{object_type}Feed ORDER BY CreatedDate DESC limit #{limit}
      HERE
    end


    @logger.info('qstring: ' + qstring)
    # Note, if query FeedPost.ContentData, Salesforce only returns 1 entry at
    # a time, you will get a 'queryLocator', which can be used by calling
    # 'queryMore(queryLocator)'

    feed_results = Array.new

    results = binding.query(:queryString => qstring)
    if results.queryResponse.result.records.is_a?(Hash)
      # User has made only one feedpost
      feed = Hash.new
      feed = results.queryResponse.result.records
      if (!feed.FeedPost.nil?) && (feed.FeedPost.ContentSize.to_i > 0)
        feed = get_single_chatter_feed_with_attachment(feed.FeedPost.Id, feed[:type], binding, directory_name)
      end
      feed_results << feed
    elsif results.queryResponse.result.records.is_a?(Array)
      results.queryResponse.result.records.each do |an_feed_entry|
        if (an_feed_entry.is_a?(Hash))
          if (an_feed_entry[:Type] == "TrackedChange")
            # This is a TrackedChange Feed, the FeedPost Body is nil
            feed = Hash.new
            feed = an_feed_entry
            feed_results << feed
          elsif (!an_feed_entry.FeedPost.nil?) && (an_feed_entry.FeedPost.ContentSize.to_i > 0) && (get_attachment)
            # This signifies that:
            #   1. results.queryResponse.result.records.FeedPost.Type is of "ContentPost"
            #   2. results.queryResponse.result.records.FeedPost.type should be of "FeedPost"
            an_entry_with_attachment = get_single_chatter_feed_with_attachment(an_feed_entry.FeedPost.Id, an_feed_entry[:type], binding, directory_name)
            feed_results << an_entry_with_attachment
          else
            feed = Hash.new
            feed = an_feed_entry
            feed_results << feed
          end
        else
          @logger.info "Result #{object_id} has a results.queryResponse that is either not a valid Hash, or with nil FeedPost."
        end
      end
    end

    #if there are more entries, query it again and show it all
    while results.queryResponse.result.done.to_s.upcase != 'TRUE'
      results = binding.queryMore(:queryString => results.queryResponse.result.queryLocator)
      if results.queryResponse.result.records.is_a?(Hash)
        # User has made only one feedpost
        feed = Hash.new
        feed = results.queryResponse.result.records
        if (!feed.FeedPost.nil?) && (feed.FeedPost.ContentSize.to_i > 0)
          feed = get_single_chatter_feed_with_attachment(feed.FeedPost.Id, feed[:type], binding, directory_name)
        end
        feed_results << feed
      elsif results.queryResponse.result.records.is_a?(Array)
        results.queryResponse.result.records.each do |an_feed_entry|
          if (an_feed_entry.is_a?(Hash))
            if (an_feed_entry[:Type] == "TrackedChange")
              # This is a TrackedChange Feed, the FeedPost Body is nil
              feed = Hash.new
              feed = an_feed_entry
              feed_results << feed
              # check to see if it has attachments
            elsif  (!an_feed_entry.FeedPost.nil?) && (an_feed_entry.FeedPost.ContentSize.to_i > 0) && (get_attachment)
              # This signifies that:
              #   1. results.queryResponse.result.records.FeedPost.Type is of "ContentPost"
              #   2. results.queryResponse.result.records.FeedPost.type should be of "FeedPost"
              an_entry_with_attachment = get_single_chatter_feed_with_attachment(an_feed_entry.FeedPost.Id, an_feed_entry[:type], binding, directory_name)
              feed_results << an_entry_with_attachment
            else
              feed = Hash.new
              feed = an_feed_entry
              feed_results << feed
            end

          else
            @logger.info "Result #{object_id} has a results.queryResponse that is either an invalid Hash or a nil FeedPost."
          end
        end
      end
    end

    return feed_results
  rescue Exception => exception
    @logger.info 'get_all_feed_posts_with_attachments: ' + exception.message
    return feed_results
  end
end

#get_all_chatter_feeds_without_attachments(object_id, object_type, binding, directory_name, limit = 100) ⇒ Object

  1. It does not return the attached file.

  2. See get_all_feed_posts_with_attachments(object_id, object_type, binding, directory_name, limit=100, get_attachment=true, query_string=nil)

  3. returns Ruby Array of matching records



73
74
75
# File 'lib/salesforce/chatter_feed.rb', line 73

def get_all_chatter_feeds_without_attachments(object_id, object_type, binding, directory_name, limit=100)
  return get_all_chatter_feeds_with_attachments(object_id, object_type, binding, directory_name, limit, false, nil)
end

#get_single_chatter_feed_with_attachment(feedpost_id, feed_type, binding, directory_name, limit = 100) ⇒ Object

  1. Returns a single feed with attachment.

  2. ‘feedpost_id is the id corresponding to this feedpost

  3. ‘feed_type’ can be one of the followings

    Account, Asset, Campaign, Case, Lead, Contact, Contract, Opportunity,
    Product2, Solution, User
    **Note**: UserProfileFeed and NewsFeed are not included here, as they
    are special cases.
    
  4. ‘binding’ can be passed in directly or using the inherited binding from the

    'Salesforce::SfBase' base class.
    
  5. ‘directory_name is the directory in ’public/tmp’ for saving the attachment

  6. ‘limit’ is the number of feed comments to retrieve at a time



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/salesforce/chatter_feed.rb', line 222

def get_single_chatter_feed_with_attachment(feedpost_id, feed_type, binding, directory_name, limit=100)
  begin
    expanded_qstring = <<-HERE
    SELECT #{BASE_FRAG}, #{FEEDPOST_WITH_CONTENT_DATA_FRAG},
    (#{FEED_TRACKED_CHANGE_FRAG}), (#{FEED_COMMENT_FRAG} LIMIT #{limit})
    FROM #{feed_type} where FeedPost.Id= \'#{feedpost_id}\' ORDER BY CreatedDate DESC Limit 1
    HERE

    @logger.info('expanded_string: ' + expanded_qstring)
    deep_result = binding.query(:queryString => expanded_qstring)

    ######### queryMore does not work on FeedPost with Content.##########
    # locator = deep_result.queryResponse.result.queryLocator
    # while !locator.nil?
    #  query_again = binding.queryMore(:queryLocator => locator)
    #  locator = query_again.queryMoreResponse.result.queryLocator
    # end
    #####################################################################

    if !deep_result.Fault.nil?
      raise ChatterFeedError.new(@logger, deep_result.Fault.faultstring.to_s)
    end
    if !deep_result.queryResponse.result.records.FeedComments.nil? && deep_result.queryResponse.result.records.FeedComments[:size].to_i > 1
      # There are more than one feed comments. Therefore, search again without content-data.
      # This is done, because having ContentData in the query string, it will only return only the 1st record of the feed comments.
      qstring_without_content_data = <<-HERE
      SELECT #{BASE_FRAG},
      (#{FEED_TRACKED_CHANGE_FRAG}), (#{FEED_COMMENT_FRAG} LIMIT 20)
      FROM #{feed_type} where FeedPost.Id= \'#{feedpost_id}\' ORDER BY CreatedDate DESC Limit 1
      HERE
      result_without_content_data = binding.query(:queryString => qstring_without_content_data)
      list_of_feed_comments = result_without_content_data.queryResponse.result.records.FeedComments
      deep_result.queryResponse.result.records.FeedComments[:records] = list_of_feed_comments[:records]
    end

    filename = deep_result.queryResponse.result.records.FeedPost.ContentFileName
    filesize = deep_result.queryResponse.result.records.FeedPost.ContentSize
    filedata = deep_result.queryResponse.result.records.FeedPost.ContentData
    result_with_attachment = deep_result.queryResponse.result.records

    local_file_name = nil

    if filename.nil?
      # remote filename is nil, do not write the local file
      @logger.info("remote filename is nil, do not write the local file.")
    else
      # Downloaded files are put in the subdirectory matching each session-id in the /public/tmp directory.
      # creates dir, if it does not exists
      file_writer = Salesforce::FileWriter.new
      local_file_name = file_writer.do_write_file(filename, filesize, filedata, directory_name)
      result_with_attachment.FeedPost.store(:Attachment, local_file_name)
    end

    return result_with_attachment
  end
rescue Exception => exception
  @logger.info "Cannot create the file: " + exception.message
  result_with_attachment.FeedPost[:attachment] = nil
  return result_with_attachment
end

#search_chatter_feeds(object_type, query_string, binding, limit = 100) ⇒ Object

find all chatter feeds based on object_type, query_string, and given binding



66
67
68
# File 'lib/salesforce/chatter_feed.rb', line 66

def search_chatter_feeds(object_type, query_string, binding, limit=100)
  return get_all_chatter_feeds_with_attachments(nil, object_type, binding, 'no-attachment-for-search', limit, false, query_string)
end