koala 1.3.0rc2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -5,12 +5,15 @@ New methods:
5
5
  -- GraphCollection.parse_page_url now exposes useful functionality for non-Rails apps
6
6
  -- RealtimeUpdates#subscription_path and TestUsers#test_user_accounts_path are now public
7
7
  Updated methods:
8
+ -- REST API methods are now deprecated (see http://developers.facebook.com/blog/post/616/)
8
9
  -- OAuth#url_for_access_token and #url_for_oauth_code now include any provided options as URL parameters
9
10
  -- APIError#raw_response allows access to the raw error response received from Facebook
10
11
  -- Utils.deprecate only prints each message once (no more spamming)
11
12
  -- API#get_page_access_token now accepts additional arguments and HTTP options (like other calls)
12
13
  -- TestUsers and RealtimeUpdates methods now take http_options arguments
13
14
  -- All methods with http_options can now take :http_component => :response for the complete response
15
+ -- OAuth#get_user_info_from_cookies returns nil rather than an error if the cookies are expired (thanks, herzio)
16
+ -- TestUsers#delete_all now uses the Batch API and is much faster
14
17
  Internal improvements:
15
18
  -- FQL queries now use the Graph API behind-the-scenes
16
19
  -- Cleaned up file and class organization, with aliases for backward compatibility
@@ -38,6 +38,8 @@ module Koala
38
38
  #
39
39
  # @return the result from Facebook
40
40
  def rest_call(fb_method, args = {}, options = {}, verb = "get")
41
+ Koala::Utils.deprecate("The REST API is now deprecated; please use the equivalent Graph API methods instead. See http://developers.facebook.com/blog/post/616/.")
42
+
41
43
  options = options.merge!(:rest_api => true, :read_only => READ_ONLY_METHODS.include?(fb_method.to_s))
42
44
 
43
45
  api("method/#{fb_method}", args.merge('format' => 'json'), verb, options) do |response|
@@ -31,14 +31,14 @@ module Koala
31
31
  # You can pass Rack/Rails/Sinatra's cookie hash directly to this method.
32
32
  #
33
33
  # @return the authenticated user's information as a hash, or nil.
34
- def get_user_info_from_cookie(cookie_hash)
34
+ def get_user_info_from_cookies(cookie_hash)
35
35
  if signed_cookie = cookie_hash["fbsr_#{@app_id}"]
36
36
  parse_signed_cookie(signed_cookie)
37
37
  elsif unsigned_cookie = cookie_hash["fbs_#{@app_id}"]
38
38
  parse_unsigned_cookie(unsigned_cookie)
39
39
  end
40
40
  end
41
- alias_method :get_user_info_from_cookies, :get_user_info_from_cookie
41
+ alias_method :get_user_info_from_cookie, :get_user_info_from_cookies
42
42
 
43
43
  # Parses the cookie set Facebook's JavaScript SDK and returns only the user ID.
44
44
  #
@@ -47,13 +47,17 @@ module Koala
47
47
  # @param (see #get_user_info_from_cookie)
48
48
  #
49
49
  # @return the authenticated user's Facebook ID, or nil.
50
- def get_user_from_cookie(cookies)
51
- if info = get_user_info_from_cookies(cookies)
52
- # signed cookie has user_id, unsigned cookie has uid
53
- string = info["user_id"] || info["uid"]
50
+ def get_user_from_cookies(cookies)
51
+ if signed_cookie = cookies["fbsr_#{@app_id}"]
52
+ if components = parse_signed_request(signed_cookie)
53
+ components["user_id"]
54
+ end
55
+ elsif info = get_user_info_from_cookies(cookies)
56
+ # Parsing unsigned cookie
57
+ info["uid"]
54
58
  end
55
59
  end
56
- alias_method :get_user_from_cookies, :get_user_from_cookie
60
+ alias_method :get_user_from_cookie, :get_user_from_cookies
57
61
 
58
62
  # URLs
59
63
 
@@ -284,8 +288,15 @@ module Koala
284
288
 
285
289
  def parse_signed_cookie(fb_cookie)
286
290
  components = parse_signed_request(fb_cookie)
287
- if (code = components["code"]) && token_info = get_access_token_info(code, :redirect_uri => '')
288
- components.merge(token_info)
291
+ if code = components["code"]
292
+ begin
293
+ token_info = get_access_token_info(code, :redirect_uri => '')
294
+ rescue Koala::Facebook::APIError => err
295
+ return nil if err.message =~ /Code was invalid or expired/
296
+ raise
297
+ end
298
+
299
+ components.merge(token_info) if token_info
289
300
  else
290
301
  nil
291
302
  end
@@ -1,4 +1,5 @@
1
1
  require 'koala'
2
+
2
3
  module Koala
3
4
  module Facebook
4
5
 
@@ -81,7 +82,7 @@ module Koala
81
82
  @api.delete_object(test_user, options)
82
83
  end
83
84
 
84
- # Deletes all test users.
85
+ # Deletes all test users in batches of 50.
85
86
  #
86
87
  # @note if you have a lot of test users (> 20), this operation can take a long time.
87
88
  #
@@ -89,7 +90,20 @@ module Koala
89
90
  #
90
91
  # @return a list of the test users that have been deleted
91
92
  def delete_all(options = {})
92
- list(options).each {|u| delete(u, options)}
93
+ # ideally we'd save a call by checking next_page_params, but at the time of writing
94
+ # Facebook isn't consistently returning full pages after the first one
95
+ previous_list = nil
96
+ while (test_user_list = list(options)).length > 0
97
+ # avoid infinite loops if Facebook returns buggy users you can't delete
98
+ # see http://developers.facebook.com/bugs/223629371047398
99
+ break if test_user_list == previous_list
100
+
101
+ test_user_list.each_slice(50) do |users|
102
+ self.api.batch(options) {|batch_api| users.each {|u| batch_api.delete_object(u["id"]) }}
103
+ end
104
+
105
+ previous_list = test_user_list
106
+ end
93
107
  end
94
108
 
95
109
  # Updates a test user's attributes.
@@ -1,3 +1,3 @@
1
1
  module Koala
2
- VERSION = "1.3.0rc2"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -2,6 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  # Support for legacy / deprecated interfaces
4
4
  describe "legacy APIs" do
5
+
6
+ it "deprecates the REST API" do
7
+ api = Koala::Facebook::API.new
8
+ api.stub(:api)
9
+ Koala::Utils.should_receive(:deprecate)
10
+ api.rest_call("stuff")
11
+ end
12
+
5
13
  describe Koala::Facebook::GraphAPI do
6
14
  describe "class consolidation" do
7
15
  before :each do
@@ -104,10 +104,26 @@ describe "Koala::Facebook::OAuth" do
104
104
  @oauth.get_user_info_from_cookies(@cookie)["access_token"].should == @token
105
105
  end
106
106
 
107
- it "returns nil if the call to FB fails" do
107
+ it "returns nil if the call to FB returns no data" do
108
108
  @oauth.stub(:get_access_token_info).and_return(nil)
109
109
  @oauth.get_user_info_from_cookies(@cookie).should be_nil
110
110
  end
111
+
112
+ it "returns nil if the call to FB returns an expired code error" do
113
+ @oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::APIError.new(
114
+ "type" => "OAuthException",
115
+ "message" => "Code was invalid or expired. Session has expired at unix time 1324044000. The current unix time is 1324300957."
116
+ ))
117
+ @oauth.get_user_info_from_cookies(@cookie).should be_nil
118
+ end
119
+
120
+ it "raises the error if the call to FB returns a different error" do
121
+ @oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::APIError.new(
122
+ "type" => "OtherError",
123
+ "message" => "A Facebook Error"
124
+ ))
125
+ expect { @oauth.get_user_info_from_cookies(@cookie) }.to raise_exception(Koala::Facebook::APIError)
126
+ end
111
127
  end
112
128
 
113
129
  it "doesn't parse invalid cookies" do
@@ -166,12 +182,12 @@ describe "Koala::Facebook::OAuth" do
166
182
  @oauth.stub(:get_access_token_info).and_return("access_token" => "my token")
167
183
  end
168
184
 
169
- it "uses get_user_info_from_cookies to parse the cookies" do
170
- @oauth.should_receive(:get_user_info_from_cookies).with(@cookie).and_return({})
185
+ it "does not uses get_user_info_from_cookies to parse the cookies" do
186
+ @oauth.should_not_receive(:get_user_info_from_cookies).with(@cookie).and_return({})
171
187
  @oauth.get_user_from_cookies(@cookie)
172
188
  end
173
189
 
174
- it "uses return the token string if the cookies are valid" do
190
+ it "uses return the facebook user id string if the cookies are valid" do
175
191
  result = @oauth.get_user_from_cookies(@cookie)
176
192
  result.should == "2905623" # the user who generated the original test cookie
177
193
  end
@@ -179,19 +179,27 @@ describe "Koala::Facebook::TestUsers" do
179
179
  end
180
180
 
181
181
  describe "#delete_all" do
182
- it "deletes all users found by the list commnand" do
183
- array = [1, 2, 3]
184
- @test_users.should_receive(:list).and_return(array)
185
- array.each {|i| @test_users.should_receive(:delete).with(i, anything) }
182
+ it "deletes the batch API to deleten all users found by the list commnand" do
183
+ array = 200.times.collect { {"id" => rand}}
184
+ @test_users.should_receive(:list).and_return(array, [])
185
+ batch_api = stub("batch API")
186
+ @test_users.api.should_receive(:batch).and_yield(batch_api).any_number_of_times
187
+ array.each {|item| batch_api.should_receive(:delete_object).with(item["id"]) }
186
188
  @test_users.delete_all
187
189
  end
188
190
 
189
- it "accepts http options that get passed to both list and delete" do
190
- array = [1, 2, 3]
191
+ it "accepts http options that get passed to both list and the batch call" do
191
192
  options = {:some_http_option => true}
192
- @test_users.should_receive(:list).with(options).and_return(array)
193
- array.each {|i| @test_users.should_receive(:delete).with(anything, options) }
193
+ @test_users.should_receive(:list).with(options).and_return([{"id" => rand}], [])
194
+ @test_users.api.should_receive(:batch).with(options)
194
195
  @test_users.delete_all(options)
196
+ end
197
+
198
+ it "breaks if Facebook sends back the same list twice" do
199
+ list = [{"id" => rand}]
200
+ @test_users.should_receive(:list).any_number_of_times.and_return(list)
201
+ @test_users.api.should_receive(:batch).once
202
+ @test_users.delete_all
195
203
  end
196
204
  end
197
205
 
@@ -426,7 +426,7 @@ graph_api:
426
426
  with_token: '{"id": "888888888", "access_token":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}'
427
427
  no_args:
428
428
  get:
429
- with_token: '{"data":[{"id": "999999999", "access_token":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}, {"id": "888888888", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}]}'
429
+ with_token: '{"data":[{"id": "999999999", "access_token":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}, {"id": "888888888", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}], "paging":{"next":"https://graph.facebook.com/119908831367602/accounts/test-users?access_token=119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw&limit=50&offset=50&__after_id=100003241848740"}}'
430
430
 
431
431
  /999999999:
432
432
  no_args:
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: koala
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0rc2
5
- prerelease: 5
4
+ version: 1.3.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional
@@ -13,7 +13,7 @@ date: 2011-10-04 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
16
- requirement: &70189471321260 !ruby/object:Gem::Requirement
16
+ requirement: &70194747941160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70189471321260
24
+ version_requirements: *70194747941160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: faraday
27
- requirement: &70189471320500 !ruby/object:Gem::Requirement
27
+ requirement: &70194747940100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.7.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70189471320500
35
+ version_requirements: *70194747940100
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70189471319840 !ruby/object:Gem::Requirement
38
+ requirement: &70194747938880 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.8.0rc1
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70189471319840
46
+ version_requirements: *70194747938880
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &70189471318960 !ruby/object:Gem::Requirement
49
+ requirement: &70194747937740 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: 0.8.7
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70189471318960
57
+ version_requirements: *70194747937740
58
58
  description: Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write
59
59
  access to the social graph via the Graph and REST APIs, as well as support for realtime
60
60
  updates and OAuth and Facebook Connect authentication. Koala is fully tested and
@@ -142,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
142
  version: '0'
143
143
  segments:
144
144
  - 0
145
- hash: 1629034737345566413
145
+ hash: 3741350754426721879
146
146
  required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  none: false
148
148
  requirements: