mmangino-facebooker 1.0.29 → 1.0.30

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.autotest +15 -0
  2. data/Manifest.txt +129 -0
  3. data/Rakefile +2 -3
  4. data/examples/desktop_login.rb +14 -0
  5. data/facebooker.gemspec +43 -0
  6. data/lib/facebooker/adapters/adapter_base.rb +3 -2
  7. data/lib/facebooker/adapters/bebo_adapter.rb +6 -4
  8. data/lib/facebooker/batch_request.rb +11 -10
  9. data/lib/facebooker/logging.rb +6 -13
  10. data/lib/facebooker/mobile.rb +2 -2
  11. data/lib/facebooker/model.rb +15 -13
  12. data/lib/facebooker/models/applicationproperties.rb +1 -1
  13. data/lib/facebooker/models/applicationrestrictions.rb +3 -3
  14. data/lib/facebooker/models/event.rb +2 -2
  15. data/lib/facebooker/models/friend_list.rb +2 -2
  16. data/lib/facebooker/models/group.rb +4 -4
  17. data/lib/facebooker/models/page.rb +3 -2
  18. data/lib/facebooker/models/photo.rb +2 -2
  19. data/lib/facebooker/models/user.rb +13 -5
  20. data/lib/facebooker/models/work_info.rb +3 -2
  21. data/lib/facebooker/rails/controller.rb +6 -1
  22. data/lib/facebooker/rails/facebook_request_fix.rb +12 -8
  23. data/lib/facebooker/rails/facebook_session_handling.rb +1 -2
  24. data/lib/facebooker/rails/facebook_url_rewriting.rb +14 -11
  25. data/lib/facebooker/rails/helpers/fb_connect.rb +8 -2
  26. data/lib/facebooker/rails/helpers.rb +4 -3
  27. data/lib/facebooker/rails/publisher.rb +36 -30
  28. data/lib/facebooker/session.rb +81 -73
  29. data/lib/facebooker/version.rb +1 -1
  30. data/lib/facebooker.rb +41 -39
  31. data/test/facebooker/adapters_test.rb +23 -23
  32. data/test/facebooker/model_test.rb +10 -0
  33. data/test/facebooker/rails/publisher_test.rb +97 -88
  34. data/test/facebooker/rails_integration_test.rb +44 -43
  35. data/test/facebooker/session_test.rb +5 -5
  36. data/test/rack/facebook_test.rb +2 -3
  37. data/test/rails_test_helper.rb +14 -0
  38. data/test/test_helper.rb +5 -4
  39. metadata +21 -16
@@ -6,7 +6,7 @@ module Facebooker
6
6
  # other than the logged in user (if that's unallowed)
7
7
  class NonSessionUser < StandardError; end
8
8
  class Session
9
-
9
+
10
10
  #
11
11
  # Raised when a facebook session has expired. This
12
12
  # happens when the timeout is reached, or when the
@@ -62,49 +62,49 @@ module Facebooker
62
62
  class UserRegistrationFailed < StandardError
63
63
  attr_accessor :failed_users
64
64
  end
65
-
65
+
66
66
  API_SERVER_BASE_URL = ENV["FACEBOOKER_API"] == "new" ? "api.new.facebook.com" : "api.facebook.com"
67
67
  API_PATH_REST = "/restserver.php"
68
68
  WWW_SERVER_BASE_URL = ENV["FACEBOOKER_API"] == "new" ? "www.new.facebook.com" : "www.facebook.com"
69
69
  WWW_PATH_LOGIN = "/login.php"
70
70
  WWW_PATH_ADD = "/add.php"
71
71
  WWW_PATH_INSTALL = "/install.php"
72
-
72
+
73
73
  attr_writer :auth_token
74
74
  attr_reader :session_key
75
-
75
+
76
76
  def self.create(api_key=nil, secret_key=nil)
77
77
  api_key ||= self.api_key
78
78
  secret_key ||= self.secret_key
79
79
  raise ArgumentError unless !api_key.nil? && !secret_key.nil?
80
80
  new(api_key, secret_key)
81
81
  end
82
-
82
+
83
83
  def self.api_key
84
84
  extract_key_from_environment(:api) || extract_key_from_configuration_file(:api) rescue report_inability_to_find_key(:api)
85
85
  end
86
-
86
+
87
87
  def self.secret_key
88
88
  extract_key_from_environment(:secret) || extract_key_from_configuration_file(:secret) rescue report_inability_to_find_key(:secret)
89
89
  end
90
-
90
+
91
91
  def self.current
92
92
  Thread.current['facebook_session']
93
93
  end
94
-
94
+
95
95
  def self.current=(session)
96
96
  Thread.current['facebook_session'] = session
97
97
  end
98
-
98
+
99
99
  def login_url(options={})
100
100
  options = default_login_url_options.merge(options)
101
101
  "#{Facebooker.login_url_base(@api_key)}#{login_url_optional_parameters(options)}"
102
102
  end
103
-
103
+
104
104
  def install_url(options={})
105
105
  "#{Facebooker.install_url_base(@api_key)}#{install_url_optional_parameters(options)}"
106
106
  end
107
-
107
+
108
108
  # The url to get user to approve extended permissions
109
109
  # http://wiki.developers.facebook.com/index.php/Extended_permission
110
110
  #
@@ -122,20 +122,20 @@ module Facebooker
122
122
  options = default_login_url_options.merge(options)
123
123
  "http://#{Facebooker.www_server_base_url}/authorize.php?api_key=#{@api_key}&v=1.0&ext_perm=#{permission}#{install_url_optional_parameters(options)}"
124
124
  end
125
-
125
+
126
126
  def install_url_optional_parameters(options)
127
127
  optional_parameters = []
128
128
  optional_parameters += add_next_parameters(options)
129
129
  optional_parameters.join
130
130
  end
131
-
131
+
132
132
  def add_next_parameters(options)
133
133
  opts = []
134
134
  opts << "&next=#{CGI.escape(options[:next])}" if options[:next]
135
135
  opts << "&next_cancel=#{CGI.escape(options[:next_cancel])}" if options[:next_cancel]
136
136
  opts
137
137
  end
138
-
138
+
139
139
  def login_url_optional_parameters(options)
140
140
  # It is important that unused options are omitted as stuff like &canvas=false will still display the canvas.
141
141
  optional_parameters = []
@@ -145,48 +145,54 @@ module Facebooker
145
145
  optional_parameters << "&canvas=true" if options[:canvas]
146
146
  optional_parameters.join
147
147
  end
148
-
148
+
149
149
  def default_login_url_options
150
150
  {}
151
151
  end
152
-
152
+
153
153
  def initialize(api_key, secret_key)
154
- @api_key = api_key
155
- @secret_key = secret_key
154
+ @api_key = api_key
155
+ @secret_key = secret_key
156
+ @batch_request = nil
157
+ @session_key = nil
158
+ @uid = nil
159
+ @auth_token = nil
160
+ @secret_from_session = nil
161
+ @expires = nil
156
162
  end
157
-
163
+
158
164
  def secret_for_method(method_name)
159
165
  @secret_key
160
166
  end
161
-
167
+
162
168
  def auth_token
163
169
  @auth_token ||= post 'facebook.auth.createToken'
164
170
  end
165
-
171
+
166
172
  def infinite?
167
173
  @expires == 0
168
174
  end
169
-
175
+
170
176
  def expired?
171
177
  @expires.nil? || (!infinite? && Time.at(@expires) <= Time.now)
172
178
  end
173
-
179
+
174
180
  def secured?
175
181
  !@session_key.nil? && !expired?
176
182
  end
177
-
183
+
178
184
  def secure!
179
185
  response = post 'facebook.auth.getSession', :auth_token => auth_token
180
186
  secure_with!(response['session_key'], response['uid'], response['expires'], response['secret'])
181
187
  end
182
-
188
+
183
189
  def secure_with!(session_key, uid = nil, expires = nil, secret_from_session = nil)
184
190
  @session_key = session_key
185
191
  @uid = uid ? Integer(uid) : post('facebook.users.getLoggedInUser', :session_key => session_key)
186
192
  @expires = Integer(expires)
187
193
  @secret_from_session = secret_from_session
188
194
  end
189
-
195
+
190
196
  def fql_query(query, format = 'XML')
191
197
  post('facebook.fql.query', :query => query, :format => format) do |response|
192
198
  type = response.shift
@@ -212,11 +218,11 @@ module Facebooker
212
218
  end
213
219
  end
214
220
  end
215
-
221
+
216
222
  def user
217
223
  @user ||= User.new(uid, self)
218
224
  end
219
-
225
+
220
226
  #
221
227
  # This one has so many parameters, a Hash seemed cleaner than a long param list. Options can be:
222
228
  # :uid => Filter by events associated with a user with this uid
@@ -231,7 +237,7 @@ module Facebooker
231
237
  end
232
238
  end
233
239
  end
234
-
240
+
235
241
  def event_members(eid)
236
242
  @members ||= post('facebook.events.getMembers', :eid => eid) do |response|
237
243
  response.map do |attendee_hash|
@@ -273,21 +279,21 @@ module Facebooker
273
279
  def server_cache
274
280
  Facebooker::ServerCache.new(self)
275
281
  end
276
-
282
+
277
283
  #
278
284
  # Returns a proxy object for handling calls to the Facebook Data API
279
285
  def data
280
286
  Facebooker::Data.new(self)
281
287
  end
282
-
288
+
283
289
  def admin
284
290
  Facebooker::Admin.new(self)
285
291
  end
286
-
292
+
287
293
  def mobile
288
294
  Facebooker::Mobile.new(self)
289
295
  end
290
-
296
+
291
297
  #
292
298
  # Given an array like:
293
299
  # [[userid, otheruserid], [yetanotherid, andanotherid]]
@@ -303,7 +309,7 @@ module Facebooker
303
309
  end
304
310
  post('facebook.friends.areFriends', :uids1 => uids1.join(','), :uids2 => uids2.join(','))
305
311
  end
306
-
312
+
307
313
  def get_photos(pids = nil, subj_id = nil, aid = nil)
308
314
  if [subj_id, pids, aid].all? {|arg| arg.nil?}
309
315
  raise ArgumentError, "Can't get a photo without a picture, album or subject ID"
@@ -314,7 +320,7 @@ module Facebooker
314
320
  end
315
321
  end
316
322
  end
317
-
323
+
318
324
  def get_albums(aids)
319
325
  @albums = post('facebook.photos.getAlbums', :aids => aids) do |response|
320
326
  response.map do |hash|
@@ -322,7 +328,7 @@ module Facebooker
322
328
  end
323
329
  end
324
330
  end
325
-
331
+
326
332
  def get_tags(pids)
327
333
  @tags = post('facebook.photos.getTags', :pids => pids) do |response|
328
334
  response.map do |hash|
@@ -330,14 +336,14 @@ module Facebooker
330
336
  end
331
337
  end
332
338
  end
333
-
339
+
334
340
  def add_tags(pid, x, y, tag_uid = nil, tag_text = nil )
335
341
  if [tag_uid, tag_text].all? {|arg| arg.nil?}
336
342
  raise ArgumentError, "Must enter a name or string for this tag"
337
343
  end
338
344
  @tags = post('facebook.photos.addTag', :pid => pid, :tag_uid => tag_uid, :tag_text => tag_text, :x => x, :y => y )
339
345
  end
340
-
346
+
341
347
  def send_notification(user_ids, fbml, email_fbml = nil)
342
348
  params = {:notification => fbml, :to_ids => user_ids.map{ |id| User.cast_to_facebook_id(id)}.join(',')}
343
349
  if email_fbml
@@ -348,25 +354,25 @@ module Facebooker
348
354
  unless uid?
349
355
  params[:type]="app_to_user"
350
356
  end
351
-
357
+
352
358
  post 'facebook.notifications.send', params,uid?
353
359
  end
354
-
360
+
355
361
  ##
356
362
  # Register a template bundle with Facebook.
357
363
  # returns the template id to use to send using this template
358
364
  def register_template_bundle(one_line_story_templates,short_story_templates=nil,full_story_template=nil, action_links=nil)
359
365
  parameters = {:one_line_story_templates => Array(one_line_story_templates).to_json}
360
-
366
+
361
367
  parameters[:action_links] = action_links.to_json unless action_links.blank?
362
-
368
+
363
369
  parameters[:short_story_templates] = Array(short_story_templates).to_json unless short_story_templates.blank?
364
370
 
365
371
  parameters[:full_story_template] = full_story_template.to_json unless full_story_template.blank?
366
372
 
367
373
  post("facebook.feed.registerTemplateBundle", parameters, false)
368
374
  end
369
-
375
+
370
376
  ##
371
377
  # publish a previously rendered template bundle
372
378
  # see http://wiki.developers.facebook.com/index.php/Feed.publishUserAction
@@ -378,8 +384,8 @@ module Facebooker
378
384
  parameters[:story_size] = story_size unless story_size.nil?
379
385
  post("facebook.feed.publishUserAction", parameters)
380
386
  end
381
-
382
-
387
+
388
+
383
389
  ##
384
390
  # Send email to as many as 100 users at a time
385
391
  def send_email(user_ids, subject, text, fbml = nil)
@@ -387,17 +393,17 @@ module Facebooker
387
393
  params = {:fbml => fbml, :recipients => user_ids.map{ |id| User.cast_to_facebook_id(id)}.join(','), :text => text, :subject => subject}
388
394
  post 'facebook.notifications.sendEmail', params
389
395
  end
390
-
396
+
391
397
  # Only serialize the bare minimum to recreate the session.
392
398
  def marshal_load(variables)#:nodoc:
393
399
  fields_to_serialize.each_with_index{|field, index| instance_variable_set_value(field, variables[index])}
394
400
  end
395
-
401
+
396
402
  # Only serialize the bare minimum to recreate the session.
397
403
  def marshal_dump#:nodoc:
398
404
  fields_to_serialize.map{|field| instance_variable_value(field)}
399
405
  end
400
-
406
+
401
407
  # Only serialize the bare minimum to recreate the session.
402
408
  def to_yaml( opts = {} )
403
409
  YAML::quick_emit(self.object_id, opts) do |out|
@@ -408,29 +414,29 @@ module Facebooker
408
414
  end
409
415
  end
410
416
  end
411
-
417
+
412
418
  def instance_variable_set_value(field, value)
413
419
  self.instance_variable_set("@#{field}", value)
414
420
  end
415
-
421
+
416
422
  def instance_variable_value(field)
417
423
  self.instance_variable_get("@#{field}")
418
424
  end
419
-
425
+
420
426
  def fields_to_serialize
421
427
  %w(session_key uid expires secret_from_session auth_token api_key secret_key)
422
428
  end
423
-
429
+
424
430
  class Desktop < Session
425
431
  def login_url
426
432
  super + "&auth_token=#{auth_token}"
427
433
  end
428
-
434
+
429
435
  def secret_for_method(method_name)
430
436
  secret = auth_request_methods.include?(method_name) ? super : @secret_from_session
431
437
  secret
432
438
  end
433
-
439
+
434
440
  def post(method, params = {},use_session=false)
435
441
  if method == 'facebook.profile.getFBML' || method == 'facebook.profile.setFBML'
436
442
  raise NonSessionUser.new("User #{@uid} is not the logged in user.") unless @uid == params[:uid]
@@ -442,17 +448,17 @@ module Facebooker
442
448
  ['facebook.auth.getSession', 'facebook.auth.createToken']
443
449
  end
444
450
  end
445
-
451
+
446
452
  def batch_request?
447
453
  @batch_request
448
454
  end
449
-
455
+
450
456
  def add_to_batch(req,&proc)
451
457
  batch_request = BatchRequest.new(req,proc)
452
458
  Thread.current[:facebooker_current_batch_queue]<<batch_request
453
459
  batch_request
454
460
  end
455
-
461
+
456
462
  # Submit the enclosed requests for this session inside a batch
457
463
  #
458
464
  # All requests will be sent to Facebook at the end of the block
@@ -500,7 +506,7 @@ module Facebooker
500
506
  @batch_request=false
501
507
  BatchRun.current_batch=nil
502
508
  end
503
-
509
+
504
510
  def post_without_logging(method, params = {}, use_session_key = true, &proc)
505
511
  add_facebook_params(params, method)
506
512
  use_session_key && @session_key && params[:session_key] ||= @session_key
@@ -513,7 +519,7 @@ module Facebooker
513
519
  result
514
520
  end
515
521
  end
516
-
522
+
517
523
  def post(method, params = {}, use_session_key = true, &proc)
518
524
  if batch_request?
519
525
  post_without_logging(method, params, use_session_key, &proc)
@@ -523,7 +529,7 @@ module Facebooker
523
529
  end
524
530
  end
525
531
  end
526
-
532
+
527
533
  def post_file(method, params = {})
528
534
  base = params.delete(:base)
529
535
  Logging.log_fb_api(method, params) do
@@ -532,16 +538,18 @@ module Facebooker
532
538
  service.post_file(params.merge(:base => base, :sig => signature_for(params.reject{|key, value| key.nil?})))
533
539
  end
534
540
  end
535
-
536
-
541
+
542
+
543
+ @configuration_file_path = nil
544
+
537
545
  def self.configuration_file_path
538
546
  @configuration_file_path || File.expand_path("~/.facebookerrc")
539
547
  end
540
-
548
+
541
549
  def self.configuration_file_path=(path)
542
550
  @configuration_file_path = path
543
551
  end
544
-
552
+
545
553
  private
546
554
  def add_facebook_params(hash, method)
547
555
  hash[:method] = method
@@ -549,36 +557,36 @@ module Facebooker
549
557
  hash[:call_id] = Time.now.to_f.to_s unless method == 'facebook.auth.getSession'
550
558
  hash[:v] = "1.0"
551
559
  end
552
-
560
+
553
561
  # This ultimately delgates to the adapter
554
562
  def self.extract_key_from_environment(key_name)
555
563
  Facebooker.send(key_name.to_s + "_key") rescue nil
556
564
  end
557
-
565
+
558
566
  def self.extract_key_from_configuration_file(key_name)
559
567
  read_configuration_file[key_name]
560
568
  end
561
-
569
+
562
570
  def self.report_inability_to_find_key(key_name)
563
571
  raise ConfigurationMissing, "Could not find configuration information for #{key_name}"
564
572
  end
565
-
573
+
566
574
  def self.read_configuration_file
567
575
  eval(File.read(configuration_file_path))
568
576
  end
569
-
577
+
570
578
  def service
571
579
  @service ||= Service.new(Facebooker.api_server_base, Facebooker.api_rest_path, @api_key)
572
580
  end
573
-
581
+
574
582
  def uid
575
583
  @uid || (secure!; @uid)
576
584
  end
577
-
585
+
578
586
  def uid?
579
587
  !! @uid
580
588
  end
581
-
589
+
582
590
  def signature_for(params)
583
591
  raw_string = params.inject([]) do |collection, pair|
584
592
  collection << pair.join("=")
@@ -587,7 +595,7 @@ module Facebooker
587
595
  Digest::MD5.hexdigest([raw_string, secret_for_method(params[:method])].join)
588
596
  end
589
597
  end
590
-
598
+
591
599
  class CanvasSession < Session
592
600
  def default_login_url_options
593
601
  {:canvas => true}
@@ -2,7 +2,7 @@ module Facebooker #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 0
5
- TINY = 29
5
+ TINY = 30
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/facebooker.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  begin
2
2
  unless Object.const_defined?("ActiveSupport") and ActiveSupport.const_defined?("JSON")
3
- require 'json'
3
+ require 'json'
4
4
  module Facebooker
5
5
  def self.json_decode(str)
6
6
  JSON.parse(str)
@@ -12,9 +12,9 @@ begin
12
12
  ActiveSupport::JSON.decode(str)
13
13
  end
14
14
  end
15
- end
15
+ end
16
16
  rescue
17
- require 'json'
17
+ require 'json'
18
18
  end
19
19
  require 'zlib'
20
20
  require 'digest/md5'
@@ -22,9 +22,15 @@ require 'digest/md5'
22
22
 
23
23
 
24
24
  module Facebooker
25
-
25
+
26
+ @facebooker_configuration = {}
27
+ @current_adapter = nil
28
+ @set_asset_host_to_callback_url = nil
29
+ @path_prefix = nil
30
+ @use_curl = false
31
+
26
32
  class << self
27
-
33
+
28
34
  def load_configuration(facebooker_yaml_file)
29
35
  if File.exist?(facebooker_yaml_file)
30
36
  if defined? RAILS_ENV
@@ -35,7 +41,7 @@ module Facebooker
35
41
  apply_configuration(config)
36
42
  end
37
43
  end
38
-
44
+
39
45
  # Sets the Facebook environment based on a hash of options.
40
46
  # By default the hash passed in is loaded from facebooker.yml, but it can also be passed in
41
47
  # manually every request to run multiple Facebook apps off one Rails app.
@@ -53,70 +59,66 @@ module Facebooker
53
59
  Facebooker.timeout = config['timeout']
54
60
  @facebooker_configuration = config
55
61
  end
56
-
62
+
57
63
  def facebooker_config
58
- @facebooker_configuration || {} # to prevent pretty_errors error if the config hasn't been set yet
59
- end
60
-
61
- def current_adapter=(adapter_class)
62
- @current_adapter = adapter_class
64
+ @facebooker_configuration
63
65
  end
64
-
66
+
67
+ # TODO: This should be converted to attr_accessor, but we need to
68
+ # get all the require statements at the top of the file to work.
69
+
70
+ # Set the current adapter
71
+ attr_writer :current_adapter
72
+
73
+ # Get the current adapter
65
74
  def current_adapter
66
75
  @current_adapter || Facebooker::AdapterBase.default_adapter
67
76
  end
68
-
77
+
69
78
  def load_adapter(params)
70
79
  self.current_adapter = Facebooker::AdapterBase.load_adapter(params)
71
80
  end
72
-
81
+
73
82
  def facebook_path_prefix=(path)
74
83
  current_adapter.facebook_path_prefix = path
75
84
  end
76
-
85
+
77
86
  # Default is canvas_page_name in yml file
78
87
  def facebook_path_prefix
79
88
  current_adapter.facebook_path_prefix
80
89
  end
81
-
90
+
82
91
  def is_for?(application_container)
83
92
  current_adapter.is_for?(application_container)
84
93
  end
85
-
94
+
86
95
  def set_asset_host_to_callback_url=(val)
87
96
  @set_asset_host_to_callback_url=val
88
97
  end
89
-
98
+
90
99
  def set_asset_host_to_callback_url
91
- @set_asset_host_to_callback_url.nil? ? true : @set_asset_host_to_callback_url
92
- end
93
-
94
- def use_curl=(val)
95
- @use_curl=val
96
- end
97
-
98
- def use_curl?
99
- @use_curl
100
+ @set_asset_host_to_callback_url || true
100
101
  end
101
-
102
+
103
+ attr_accessor :use_curl
104
+ alias :use_curl? :use_curl
105
+
102
106
  def timeout=(val)
103
107
  @timeout = val.to_i
104
108
  end
105
-
109
+
106
110
  def timeout
107
111
  @timeout
108
112
  end
109
-
113
+
110
114
  [:api_key,:secret_key, :www_server_base_url,:login_url_base,:install_url_base,:api_rest_path,:api_server_base,:api_server_base_url,:canvas_server_base, :video_server_base].each do |delegated_method|
111
115
  define_method(delegated_method){ return current_adapter.send(delegated_method)}
112
116
  end
113
-
114
-
115
- def path_prefix
116
- @path_prefix
117
- end
118
-
119
-
117
+
118
+
119
+ attr_reader :path_prefix
120
+
121
+
120
122
  # Set the asset path to the canvas path for just this one request
121
123
  # by definition, we will make this a canvas request
122
124
  def with_asset_path_for_canvas
@@ -130,7 +132,7 @@ module Facebooker
130
132
  ActionController::Base.asset_host = original_asset_host
131
133
  end
132
134
  end
133
-
135
+
134
136
  # If this request is_canvas_request
135
137
  # then use the application name as the url root
136
138
  def request_for_canvas(is_canvas_request)