Class: Facebooker::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/facebooker/session.rb

Direct Known Subclasses

CanvasSession, MockSession, Desktop

Defined Under Namespace

Classes: AlbumIsFull, BlankFeedTitle, CallOutOfOrder, ConfigurationMissing, Desktop, ExtendedPermissionRequired, FQLFieldDoesNotExist, FQLFunctionDoesNotExist, FQLParseError, FQLStatementNotIndexable, FQLTableDoesNotExist, FQLWrongNumberArgumentsPassedToFunction, FeedBodyDataInvalid, FeedBodyLengthTooLong, FeedBodyTemplateInvalid, FeedMarkupInvalid, FeedPhotosNotRetrieved, FeedTargetIdsInvalid, FeedTitleDataInvalid, FeedTitleTemplateInvalid, HostNotAllowed, IncorrectSignature, InvalidAPIKey, InvalidAlbumId, InvalidFeedPhotoLink, InvalidFeedPhotoSource, InvalidFeedTitleLength, InvalidFeedTitleLink, InvalidFeedTitleName, InvalidFriendList, MaxRequestsDepleted, MissingOrInvalidImageFile, MissingOrInvalidParameter, ServiceUnavailable, SessionExpired, SignatureTooOld, TemplateBundleInvalid, TemplateDataMissingRequiredTokens, TooManyUnapprovedPhotosPending, TooManyUserActionCalls, TooManyUserCalls, UnknownError, UserRegistrationFailed, UserUnRegistrationFailed

Constant Summary collapse

API_SERVER_BASE_URL =
ENV["FACEBOOKER_API"] == "new" ? "api.new.facebook.com" : "api.facebook.com"
API_PATH_REST =
"/restserver.php"
WWW_SERVER_BASE_URL =
ENV["FACEBOOKER_API"] == "new" ? "www.new.facebook.com" : "www.facebook.com"
WWW_PATH_LOGIN =
"/login.php"
WWW_PATH_ADD =
"/add.php"
WWW_PATH_INSTALL =
"/install.php"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key, secret_key) ⇒ Session

Returns a new instance of Session.



153
154
155
156
157
158
159
160
161
162
# File 'lib/facebooker/session.rb', line 153

def initialize(api_key, secret_key)
  @api_key        = api_key
  @secret_key     = secret_key
  @batch_request  = nil
  @session_key    = nil
  @uid            = nil
  @auth_token     = nil
  @secret_from_session = nil
  @expires        = nil
end

Instance Attribute Details

#auth_tokenObject



168
169
170
# File 'lib/facebooker/session.rb', line 168

def auth_token
  @auth_token ||= post 'facebook.auth.createToken'
end

#session_keyObject (readonly)

Returns the value of attribute session_key.



74
75
76
# File 'lib/facebooker/session.rb', line 74

def session_key
  @session_key
end

Class Method Details

.api_keyObject



83
84
85
# File 'lib/facebooker/session.rb', line 83

def self.api_key
  extract_key_from_environment(:api) || extract_key_from_configuration_file(:api) rescue report_inability_to_find_key(:api)
end

.configuration_file_pathObject



545
546
547
# File 'lib/facebooker/session.rb', line 545

def self.configuration_file_path
  @configuration_file_path || File.expand_path("~/.facebookerrc")
end

.configuration_file_path=(path) ⇒ Object



549
550
551
# File 'lib/facebooker/session.rb', line 549

def self.configuration_file_path=(path)
  @configuration_file_path = path
end

.create(api_key = nil, secret_key = nil) ⇒ Object

Raises:

  • (ArgumentError)


76
77
78
79
80
81
# File 'lib/facebooker/session.rb', line 76

def self.create(api_key=nil, secret_key=nil)
  api_key ||= self.api_key
  secret_key ||= self.secret_key
  raise ArgumentError unless !api_key.nil? && !secret_key.nil?
  new(api_key, secret_key)
end

.currentObject



91
92
93
# File 'lib/facebooker/session.rb', line 91

def self.current
  Thread.current['facebook_session']
end

.current=(session) ⇒ Object



95
96
97
# File 'lib/facebooker/session.rb', line 95

def self.current=(session)
  Thread.current['facebook_session'] = session
end

.secret_keyObject



87
88
89
# File 'lib/facebooker/session.rb', line 87

def self.secret_key
  extract_key_from_environment(:secret) || extract_key_from_configuration_file(:secret) rescue report_inability_to_find_key(:secret)
end

Instance Method Details

#add_next_parameters(options) ⇒ Object



132
133
134
135
136
137
# File 'lib/facebooker/session.rb', line 132

def add_next_parameters(options)
  opts = []
  opts << "&next=#{CGI.escape(options[:next])}" if options[:next]
  opts << "&next_cancel=#{CGI.escape(options[:next_cancel])}" if options[:next_cancel]
  opts
end

#add_tags(pid, x, y, tag_uid = nil, tag_text = nil) ⇒ Object



340
341
342
343
344
345
# File 'lib/facebooker/session.rb', line 340

def add_tags(pid, x, y, tag_uid = nil, tag_text = nil )
  if [tag_uid, tag_text].all? {|arg| arg.nil?}
    raise ArgumentError, "Must enter a name or string for this tag"        
  end
  @tags = post('facebook.photos.addTag', :pid => pid, :tag_uid => tag_uid, :tag_text => tag_text, :x => x, :y => y )
end

#add_to_batch(req, &proc) ⇒ Object



456
457
458
459
460
# File 'lib/facebooker/session.rb', line 456

def add_to_batch(req,&proc)
  batch_request = BatchRequest.new(req,proc)
  Thread.current[:facebooker_current_batch_queue]<<batch_request
  batch_request
end

#adminObject



289
290
291
# File 'lib/facebooker/session.rb', line 289

def admin
  Facebooker::Admin.new(self)
end

#batch(serial_only = false) ⇒ Object

Submit the enclosed requests for this session inside a batch

All requests will be sent to Facebook at the end of the block each method inside the block will return a proxy object attempting to access the proxy before the end of the block will yield an exception

For Example:

facebook_session.batch do
  @send_result = facebook_session.send_notification([12451752],"Woohoo")
  @albums = facebook_session.user.albums
end
puts @albums.first.inspect

is valid, however

facebook_session.batch do
  @send_result = facebook_session.send_notification([12451752],"Woohoo")
  @albums = facebook_session.user.albums
  puts @albums.first.inspect
end

will raise Facebooker::BatchRequest::UnexecutedRequest

If an exception is raised while processing the result, that exception will be re-raised on the next access to that object or when exception_raised? is called

for example, if the send_notification resulted in TooManyUserCalls being raised, calling

@send_result.exception_raised?

would re-raise that exception if there was an error retrieving the albums, it would be re-raised when

@albums.first

is called



497
498
499
500
501
502
503
504
505
506
507
508
# File 'lib/facebooker/session.rb', line 497

def batch(serial_only=false)
  @batch_request=true
  Thread.current[:facebooker_current_batch_queue]=[]
  yield
  # Set the batch request to false so that post will execute the batch job
  @batch_request=false
  BatchRun.current_batch=Thread.current[:facebooker_current_batch_queue]
  post("facebook.batch.run",:method_feed=>BatchRun.current_batch.map{|q| q.uri}.to_json,:serial_only=>serial_only.to_s)
ensure
  @batch_request=false
  BatchRun.current_batch=nil
end

#batch_request?Boolean

Returns:

  • (Boolean)


452
453
454
# File 'lib/facebooker/session.rb', line 452

def batch_request?
  @batch_request
end

#check_friendship(array_of_pairs_of_users) ⇒ Object

Given an array like:

[userid, otheruserid], [yetanotherid, andanotherid]

returns a Hash indicating friendship of those pairs: otheruserid] => true, [yetanotherid, andanotherid] => false if one of the Hash values is nil, it means the facebook platform’s answer is “I don’t know”



303
304
305
306
307
308
309
310
311
# File 'lib/facebooker/session.rb', line 303

def check_friendship(array_of_pairs_of_users)
  uids1 = []
  uids2 = []
  array_of_pairs_of_users.each do |pair|
    uids1 << pair.first
    uids2 << pair.last
  end
  post('facebook.friends.areFriends', :uids1 => uids1.join(','), :uids2 => uids2.join(','))
end

#dataObject

Returns a proxy object for handling calls to the Facebook Data API



285
286
287
# File 'lib/facebooker/session.rb', line 285

def data
  Facebooker::Data.new(self)
end

#default_login_url_optionsObject



149
150
151
# File 'lib/facebooker/session.rb', line 149

def 
  {}
end

#event_members(eid) ⇒ Object



241
242
243
244
245
246
247
# File 'lib/facebooker/session.rb', line 241

def event_members(eid)
  @members ||= post('facebook.events.getMembers', :eid => eid) do |response|
    response.map do |attendee_hash|
      Event::Attendance.from_hash(attendee_hash)
    end
  end
end

#events(options = {}) ⇒ Object

This one has so many parameters, a Hash seemed cleaner than a long param list. Options can be: :uid => Filter by events associated with a user with this uid :eids => Filter by this list of event ids. This is a comma-separated list of eids. :start_time => Filter with this UTC as lower bound. A missing or zero parameter indicates no lower bound. (Time or Integer) :end_time => Filter with this UTC as upper bound. A missing or zero parameter indicates no upper bound. (Time or Integer) :rsvp_status => Filter by this RSVP status.



233
234
235
236
237
238
239
# File 'lib/facebooker/session.rb', line 233

def events(options = {})
  @events ||= post('facebook.events.get', options) do |response|
    response.map do |hash|
      Event.from_hash(hash)
    end
  end
end

#expired?Boolean

Returns:

  • (Boolean)


176
177
178
# File 'lib/facebooker/session.rb', line 176

def expired?
  @expires.nil? || (!infinite? && Time.at(@expires) <= Time.now)
end

#fields_to_serializeObject



426
427
428
# File 'lib/facebooker/session.rb', line 426

def fields_to_serialize
  %w(session_key uid expires secret_from_session auth_token api_key secret_key)
end

#fql_query(query, format = 'XML') ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/facebooker/session.rb', line 196

def fql_query(query, format = 'XML')
  post('facebook.fql.query', :query => query, :format => format) do |response|
    type = response.shift
    return [] if type.nil?
    response.shift.map do |hash|
      case type
      when 'user'
        user = User.new
        user.session = self
        user.populate_from_hash!(hash)
        user
      when 'photo'
        Photo.from_hash(hash)
      when 'page'
        Page.from_hash(hash)
      when 'page_admin'
        Page.from_hash(hash)
      when 'event_member'
        Event::Attendance.from_hash(hash)
      else
        hash
      end
    end
  end
end

#get_albums(aids) ⇒ Object



324
325
326
327
328
329
330
# File 'lib/facebooker/session.rb', line 324

def get_albums(aids)
  @albums = post('facebook.photos.getAlbums', :aids => aids) do |response|
    response.map do |hash|        
      Album.from_hash(hash)
    end
  end
end

#get_photos(pids = nil, subj_id = nil, aid = nil) ⇒ Object



313
314
315
316
317
318
319
320
321
322
# File 'lib/facebooker/session.rb', line 313

def get_photos(pids = nil, subj_id = nil,  aid = nil)
  if [subj_id, pids, aid].all? {|arg| arg.nil?}
    raise ArgumentError, "Can't get a photo without a picture, album or subject ID" 
  end
  @photos = post('facebook.photos.get', :subj_id => subj_id, :pids => pids, :aid => aid ) do |response|
    response.map do |hash|
      Photo.from_hash(hash)
    end
  end
end

#get_tags(pids) ⇒ Object



332
333
334
335
336
337
338
# File 'lib/facebooker/session.rb', line 332

def get_tags(pids)
  @tags = post('facebook.photos.getTags', :pids => pids)  do |response|
    response.map do |hash|
      Tag.from_hash(hash)
    end
  end
end

#infinite?Boolean

Returns:

  • (Boolean)


172
173
174
# File 'lib/facebooker/session.rb', line 172

def infinite?
  @expires == 0
end

#install_url(options = {}) ⇒ Object



104
105
106
# File 'lib/facebooker/session.rb', line 104

def install_url(options={})
  "#{Facebooker.install_url_base(@api_key)}#{install_url_optional_parameters(options)}"
end

#install_url_optional_parameters(options) ⇒ Object



126
127
128
129
130
# File 'lib/facebooker/session.rb', line 126

def install_url_optional_parameters(options)
  optional_parameters = []      
  optional_parameters += add_next_parameters(options)
  optional_parameters.join
end

#instance_variable_set_value(field, value) ⇒ Object



418
419
420
# File 'lib/facebooker/session.rb', line 418

def instance_variable_set_value(field, value)
  self.instance_variable_set("@#{field}", value)
end

#instance_variable_value(field) ⇒ Object



422
423
424
# File 'lib/facebooker/session.rb', line 422

def instance_variable_value(field)
  self.instance_variable_get("@#{field}")
end

#is_fan(page_id, uid) ⇒ Object

Takes page_id and uid, returns true if uid is a fan of the page_id



272
273
274
# File 'lib/facebooker/session.rb', line 272

def is_fan(page_id, uid)
  post('facebook.pages.isFan', :page_id=>page_id, :uid=>uid)
end

#login_url(options = {}) ⇒ Object



99
100
101
102
# File 'lib/facebooker/session.rb', line 99

def (options={})
  options = .merge(options)
  "#{Facebooker.(@api_key)}#{(options)}"
end

#login_url_optional_parameters(options) ⇒ Object



139
140
141
142
143
144
145
146
147
# File 'lib/facebooker/session.rb', line 139

def (options)
  # It is important that unused options are omitted as stuff like &canvas=false will still display the canvas. 
  optional_parameters = []
  optional_parameters += add_next_parameters(options)
  optional_parameters << "&skipcookie=true" if options[:skip_cookie]
  optional_parameters << "&hide_checkbox=true" if options[:hide_checkbox]
  optional_parameters << "&canvas=true" if options[:canvas]
  optional_parameters.join
end

#marshal_dumpObject

Only serialize the bare minimum to recreate the session.



403
404
405
# File 'lib/facebooker/session.rb', line 403

def marshal_dump#:nodoc:
  fields_to_serialize.map{|field| instance_variable_value(field)}
end

#marshal_load(variables) ⇒ Object

Only serialize the bare minimum to recreate the session.



398
399
400
# File 'lib/facebooker/session.rb', line 398

def marshal_load(variables)#:nodoc:
  fields_to_serialize.each_with_index{|field, index| instance_variable_set_value(field, variables[index])}
end

#mobileObject



293
294
295
# File 'lib/facebooker/session.rb', line 293

def mobile
  Facebooker::Mobile.new(self)
end

#pages(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


261
262
263
264
265
266
267
268
269
# File 'lib/facebooker/session.rb', line 261

def pages(options = {})
  raise ArgumentError, 'fields option is mandatory' unless options.has_key?(:fields)
  @pages ||= {}
  @pages[options] ||= post('facebook.pages.getInfo', options) do |response|
    response.map do |hash|
      Page.from_hash(hash)
    end
  end
end

#permission_url(permission, options = {}) ⇒ Object

The url to get user to approve extended permissions wiki.developers.facebook.com/index.php/Extended_permission

permissions:

  • email

  • offline_access

  • status_update

  • photo_upload

  • video_upload

  • create_listing

  • create_event

  • rsvp_event

  • sms



121
122
123
124
# File 'lib/facebooker/session.rb', line 121

def permission_url(permission,options={})
  options = .merge(options)
  "http://#{Facebooker.www_server_base_url}/authorize.php?api_key=#{@api_key}&v=1.0&ext_perm=#{permission}#{install_url_optional_parameters(options)}"
end

#post(method, params = {}, use_session_key = true, &proc) ⇒ Object



523
524
525
526
527
528
529
530
531
# File 'lib/facebooker/session.rb', line 523

def post(method, params = {}, use_session_key = true, &proc)
  if batch_request?
    post_without_logging(method, params, use_session_key, &proc)
  else
    Logging.log_fb_api(method, params) do
      post_without_logging(method, params, use_session_key, &proc)
    end
  end
end

#post_file(method, params = {}) ⇒ Object



533
534
535
536
537
538
539
540
# File 'lib/facebooker/session.rb', line 533

def post_file(method, params = {})
  base = params.delete(:base)
  Logging.log_fb_api(method, params) do
    add_facebook_params(params, method)
    @session_key && params[:session_key] ||= @session_key unless params[:uid]
    service.post_file(params.merge(:base => base, :sig => signature_for(params.reject{|key, value| key.nil?})))
  end
end

#post_without_logging(method, params = {}, use_session_key = true, &proc) ⇒ Object



510
511
512
513
514
515
516
517
518
519
520
521
# File 'lib/facebooker/session.rb', line 510

def post_without_logging(method, params = {}, use_session_key = true, &proc)
  add_facebook_params(params, method)
  use_session_key && @session_key && params[:session_key] ||= @session_key
  final_params=params.merge(:sig => signature_for(params))
  if batch_request?
    add_to_batch(final_params,&proc)
  else
    result = service.post(final_params)
    result = yield result if block_given?
    result
  end
end

#publish_user_action(bundle_id, data = {}, target_ids = nil, body_general = nil, story_size = nil) ⇒ Object

publish a previously rendered template bundle see wiki.developers.facebook.com/index.php/Feed.publishUserAction



380
381
382
383
384
385
386
# File 'lib/facebooker/session.rb', line 380

def publish_user_action(bundle_id,data={},target_ids=nil,body_general=nil,story_size=nil)
  parameters={:template_bundle_id=>bundle_id,:template_data=>data.to_json}
  parameters[:target_ids] = target_ids unless target_ids.blank?
  parameters[:body_general] = body_general unless body_general.blank?
  parameters[:story_size] = story_size unless story_size.nil?
  post("facebook.feed.publishUserAction", parameters)
end

#register_template_bundle(one_line_story_templates, short_story_templates = nil, full_story_template = nil, action_links = nil) ⇒ Object

Register a template bundle with Facebook. returns the template id to use to send using this template



364
365
366
367
368
369
370
371
372
373
374
# File 'lib/facebooker/session.rb', line 364

def register_template_bundle(one_line_story_templates,short_story_templates=nil,full_story_template=nil, action_links=nil)
  parameters = {:one_line_story_templates => Array(one_line_story_templates).to_json}

  parameters[:action_links] = action_links.to_json unless action_links.blank?

  parameters[:short_story_templates] = Array(short_story_templates).to_json unless short_story_templates.blank?

  parameters[:full_story_template] = full_story_template.to_json unless full_story_template.blank?

  post("facebook.feed.registerTemplateBundle", parameters, false)
end

#secret_for_method(method_name) ⇒ Object



164
165
166
# File 'lib/facebooker/session.rb', line 164

def secret_for_method(method_name)
  @secret_key
end

#secure!Object



184
185
186
187
# File 'lib/facebooker/session.rb', line 184

def secure!
  response = post 'facebook.auth.getSession', :auth_token => auth_token
  secure_with!(response['session_key'], response['uid'], response['expires'], response['secret'])
end

#secure_with!(session_key, uid = nil, expires = nil, secret_from_session = nil) ⇒ Object



189
190
191
192
193
194
# File 'lib/facebooker/session.rb', line 189

def secure_with!(session_key, uid = nil, expires = nil, secret_from_session = nil)
  @session_key = session_key
  @uid = uid ? Integer(uid) : post('facebook.users.getLoggedInUser', :session_key => session_key)
  @expires = Integer(expires)
  @secret_from_session = secret_from_session
end

#secured?Boolean

Returns:

  • (Boolean)


180
181
182
# File 'lib/facebooker/session.rb', line 180

def secured?
  !@session_key.nil? && !expired?
end

#send_email(user_ids, subject, text, fbml = nil) ⇒ Object

Send email to as many as 100 users at a time



391
392
393
394
395
# File 'lib/facebooker/session.rb', line 391

def send_email(user_ids, subject, text, fbml = nil) 			
  user_ids = Array(user_ids)
  params = {:fbml => fbml, :recipients => user_ids.map{ |id| User.cast_to_facebook_id(id)}.join(','), :text => text, :subject => subject} 
  post 'facebook.notifications.sendEmail', params
end

#send_notification(user_ids, fbml, email_fbml = nil) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/facebooker/session.rb', line 347

def send_notification(user_ids, fbml, email_fbml = nil)
  params = {:notification => fbml, :to_ids => user_ids.map{ |id| User.cast_to_facebook_id(id)}.join(',')}
  if email_fbml
    params[:email] = email_fbml
  end
  params[:type]="user_to_user"
  # if there is no uid, this is an announcement
  unless uid?
    params[:type]="app_to_user"
  end

  post 'facebook.notifications.send', params,uid?
end

#server_cacheObject

Returns a proxy object for handling calls to Facebook cached items such as images and FBML ref handles



279
280
281
# File 'lib/facebooker/session.rb', line 279

def server_cache
  Facebooker::ServerCache.new(self)
end

#to_yaml(opts = {}) ⇒ Object

Only serialize the bare minimum to recreate the session.



408
409
410
411
412
413
414
415
416
# File 'lib/facebooker/session.rb', line 408

def to_yaml( opts = {} )
  YAML::quick_emit(self.object_id, opts) do |out|
    out.map(taguri) do |map|
      fields_to_serialize.each do |field|
        map.add(field, instance_variable_value(field))
      end
    end
  end
end

#userObject



222
223
224
# File 'lib/facebooker/session.rb', line 222

def user
  @user ||= User.new(uid, self)
end

#users(user_ids, fields = []) ⇒ Object



255
256
257
258
259
# File 'lib/facebooker/session.rb', line 255

def users(user_ids, fields=[])
  post("facebook.users.getInfo",:uids=>user_ids.join(","),:fields=>User.user_fields(fields)) do |users|
    users.map { |u| User.new(u)}
  end
end

#users_standard(user_ids, fields = []) ⇒ Object



249
250
251
252
253
# File 'lib/facebooker/session.rb', line 249

def users_standard(user_ids, fields=[])
  post("facebook.users.getStandardInfo",:uids=>user_ids.join(","),:fields=>User.standard_fields(fields)) do |users|
    users.map { |u| User.new(u)}
  end
end