koala 0.9.0 → 1.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/CHANGELOG +33 -7
  2. data/Manifest +6 -14
  3. data/Rakefile +4 -3
  4. data/koala.gemspec +13 -8
  5. data/lib/koala/graph_api.rb +16 -3
  6. data/lib/koala/http_services.rb +100 -16
  7. data/lib/koala/rest_api.rb +73 -6
  8. data/lib/koala/test_users.rb +72 -0
  9. data/lib/koala.rb +101 -71
  10. data/readme.md +14 -13
  11. data/spec/facebook_data.yml +14 -8
  12. data/spec/koala/api_base_tests.rb +7 -0
  13. data/spec/koala/assets/beach.jpg +0 -0
  14. data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +5 -1
  15. data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +9 -4
  16. data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +10 -61
  17. data/spec/koala/graph_api/graph_api_tests.rb +86 -0
  18. data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +130 -126
  19. data/spec/koala/graph_api/graph_collection_tests.rb +2 -2
  20. data/spec/koala/live_testing_data_helper.rb +40 -12
  21. data/spec/koala/net_http_service_tests.rb +401 -152
  22. data/spec/koala/oauth/oauth_tests.rb +41 -72
  23. data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +7 -76
  24. data/spec/koala/rest_api/rest_api_tests.rb +118 -0
  25. data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +6 -4
  26. data/spec/koala/test_users/test_users_tests.rb +208 -0
  27. data/spec/koala/typhoeus_service_tests.rb +156 -0
  28. data/spec/koala_spec_helper.rb +43 -4
  29. data/spec/koala_spec_without_mocks.rb +4 -4
  30. data/spec/mock_facebook_responses.yml +69 -3
  31. data/spec/mock_http_service.rb +16 -1
  32. metadata +49 -23
  33. data/examples/oauth_playground/Capfile +0 -2
  34. data/examples/oauth_playground/LICENSE +0 -22
  35. data/examples/oauth_playground/Rakefile +0 -4
  36. data/examples/oauth_playground/config/deploy.rb +0 -39
  37. data/examples/oauth_playground/config/facebook.yml +0 -13
  38. data/examples/oauth_playground/config.ru +0 -27
  39. data/examples/oauth_playground/lib/load_facebook.rb +0 -3
  40. data/examples/oauth_playground/lib/oauth_playground.rb +0 -187
  41. data/examples/oauth_playground/readme.md +0 -8
  42. data/examples/oauth_playground/spec/oauth_playground_spec.rb +0 -35
  43. data/examples/oauth_playground/spec/spec_helper.rb +0 -36
  44. data/examples/oauth_playground/tmp/restart.txt +0 -0
  45. data/examples/oauth_playground/views/index.erb +0 -206
  46. data/examples/oauth_playground/views/layout.erb +0 -39
data/lib/koala.rb CHANGED
@@ -5,8 +5,9 @@ require 'digest/md5'
5
5
  require 'rubygems'
6
6
  require 'json'
7
7
 
8
- # openssl is required to support signed_request
8
+ # OpenSSL and Base64 are required to support signed_request
9
9
  require 'openssl'
10
+ require 'base64'
10
11
 
11
12
  # include default http services
12
13
  require 'koala/http_services'
@@ -17,10 +18,14 @@ require 'koala/graph_api'
17
18
  # add REST API methods
18
19
  require 'koala/rest_api'
19
20
 
21
+ # add realtime update methods
20
22
  require 'koala/realtime_updates'
21
23
 
24
+ # add test user methods
25
+ require 'koala/test_users'
26
+
22
27
  module Koala
23
-
28
+
24
29
  module Facebook
25
30
  # Ruby client library for the Facebook Platform.
26
31
  # Copyright 2010 Facebook
@@ -36,7 +41,7 @@ module Koala
36
41
  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
37
42
  # License for the specific language governing permissions and limitations
38
43
  # under the License.
39
- #
44
+ #
40
45
  # This client library is designed to support the Graph API and the official
41
46
  # Facebook JavaScript SDK, which is the canonical way to implement
42
47
  # Facebook authentication. Read more about the Graph API at
@@ -48,7 +53,8 @@ module Koala
48
53
  def initialize(access_token = nil)
49
54
  @access_token = access_token
50
55
  end
51
-
56
+ attr_reader :access_token
57
+
52
58
  def api(path, args = {}, verb = "get", options = {}, &error_checking_block)
53
59
  # Fetches the given path in the Graph API.
54
60
  args["access_token"] = @access_token || @app_access_token if @access_token || @app_access_token
@@ -58,20 +64,20 @@ module Koala
58
64
 
59
65
  # make the request via the provided service
60
66
  result = Koala.make_request(path, args, verb, options)
61
-
67
+
62
68
  # Check for any 500 errors before parsing the body
63
69
  # since we're not guaranteed that the body is valid JSON
64
70
  # in the case of a server error
65
71
  raise APIError.new({"type" => "HTTP #{result.status.to_s}", "message" => "Response body: #{result.body}"}) if result.status >= 500
66
-
67
- # Parse the body as JSON and check for errors if provided a mechanism to do so
72
+
73
+ # Parse the body as JSON and check for errors if provided a mechanism to do so
68
74
  # Note: Facebook sometimes sends results like "true" and "false", which aren't strictly objects
69
75
  # and cause JSON.parse to fail -- so we account for that by wrapping the result in []
70
76
  body = response = JSON.parse("[#{result.body.to_s}]")[0]
71
77
  if error_checking_block
72
78
  yield(body)
73
79
  end
74
-
80
+
75
81
  # now return the desired information
76
82
  if options[:http_component]
77
83
  result.send(options[:http_component])
@@ -80,51 +86,57 @@ module Koala
80
86
  end
81
87
  end
82
88
  end
83
-
89
+
84
90
  class GraphAPI < API
85
91
  include GraphAPIMethods
86
92
  end
87
-
93
+
88
94
  class RestAPI < API
89
95
  include RestAPIMethods
90
96
  end
91
-
97
+
92
98
  class GraphAndRestAPI < API
93
99
  include GraphAPIMethods
94
100
  include RestAPIMethods
95
101
  end
96
-
102
+
97
103
  class RealtimeUpdates < API
98
104
  include RealtimeUpdateMethods
99
105
  end
100
-
106
+
107
+ class TestUsers < API
108
+ include TestUserMethods
109
+ # make the Graph API accessible in case someone wants to make other calls to interact with their users
110
+ attr_reader :graph_api
111
+ end
112
+
101
113
  class APIError < Exception
102
114
  attr_accessor :fb_error_type
103
115
  def initialize(details = {})
104
- self.fb_error_type = details["type"]
116
+ self.fb_error_type = details["type"]
105
117
  super("#{fb_error_type}: #{details["message"]}")
106
118
  end
107
119
  end
108
-
109
-
120
+
121
+
110
122
  class OAuth
111
123
  attr_reader :app_id, :app_secret, :oauth_callback_url
112
124
  def initialize(app_id, app_secret, oauth_callback_url = nil)
113
125
  @app_id = app_id
114
126
  @app_secret = app_secret
115
- @oauth_callback_url = oauth_callback_url
127
+ @oauth_callback_url = oauth_callback_url
116
128
  end
117
129
 
118
130
  def get_user_info_from_cookie(cookie_hash)
119
131
  # Parses the cookie set by the official Facebook JavaScript SDK.
120
- #
132
+ #
121
133
  # cookies should be a Hash, like the one Rails provides
122
- #
134
+ #
123
135
  # If the user is logged in via Facebook, we return a dictionary with the
124
136
  # keys "uid" and "access_token". The former is the user's Facebook ID,
125
137
  # and the latter can be used to make authenticated requests to the Graph API.
126
138
  # If the user is not logged in, we return None.
127
- #
139
+ #
128
140
  # Download the official Facebook JavaScript SDK at
129
141
  # http://github.com/facebook/connect-js/. Read more about Facebook
130
142
  # authentication at http://developers.facebook.com/docs/authentication/.
@@ -139,21 +151,21 @@ module Koala
139
151
 
140
152
  # generate the signature and make sure it matches what we expect
141
153
  auth_string = components.keys.sort.collect {|a| a == "sig" ? nil : "#{a}=#{components[a]}"}.reject {|a| a.nil?}.join("")
142
- sig = Digest::MD5.hexdigest(auth_string + @app_secret)
154
+ sig = Digest::MD5.hexdigest(auth_string + @app_secret)
143
155
  sig == components["sig"] && (components["expires"] == "0" || Time.now.to_i < components["expires"].to_i) ? components : nil
144
156
  end
145
157
  end
146
158
  alias_method :get_user_info_from_cookies, :get_user_info_from_cookie
147
-
159
+
148
160
  def get_user_from_cookie(cookies)
149
161
  if info = get_user_info_from_cookies(cookies)
150
162
  string = info["uid"]
151
163
  end
152
164
  end
153
165
  alias_method :get_user_from_cookies, :get_user_from_cookie
154
-
166
+
155
167
  # URLs
156
-
168
+
157
169
  def url_for_oauth_code(options = {})
158
170
  # for permissions, see http://developers.facebook.com/docs/authentication/permissions
159
171
  permissions = options[:permissions]
@@ -163,54 +175,71 @@ module Koala
163
175
  raise ArgumentError, "url_for_oauth_code must get a callback either from the OAuth object or in the options!" unless callback
164
176
 
165
177
  # Creates the URL for oauth authorization for a given callback and optional set of permissions
166
- "https://#{GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{callback}#{scope}"
178
+ "https://#{GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{callback}#{scope}"
167
179
  end
168
-
180
+
169
181
  def url_for_access_token(code, options = {})
170
182
  # Creates the URL for the token corresponding to a given code generated by Facebook
171
183
  callback = options[:callback] || @oauth_callback_url
172
184
  raise ArgumentError, "url_for_access_token must get a callback either from the OAuth object or in the parameters!" unless callback
173
185
  "https://#{GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@app_secret}&code=#{code}"
174
186
  end
175
-
187
+
176
188
  def get_access_token_info(code)
177
189
  # convenience method to get a parsed token from Facebook for a given code
178
190
  # should this require an OAuth callback URL?
179
191
  get_token_from_server(:code => code, :redirect_uri => @oauth_callback_url)
180
192
  end
181
-
193
+
182
194
  def get_access_token(code)
183
195
  # upstream methods will throw errors if needed
184
- if info = get_access_token_info(code)
185
- string = info["access_token"]
196
+ if info = get_access_token_info(code)
197
+ string = info["access_token"]
186
198
  end
187
199
  end
188
-
200
+
189
201
  def get_app_access_token_info
190
- # convenience method to get a the application's sessionless access token
202
+ # convenience method to get a the application's sessionless access token
191
203
  get_token_from_server({:type => 'client_cred'}, true)
192
204
  end
193
-
205
+
194
206
  def get_app_access_token
195
207
  if info = get_app_access_token_info
196
- string = info["access_token"]
208
+ string = info["access_token"]
197
209
  end
198
210
  end
199
-
200
- # signed_request
201
- def parse_signed_request(request)
202
- # Facebook's signed requests come in two parts -- the signature and the data payload
203
- # see http://developers.facebook.com/docs/authentication/canvas
204
- encoded_sig, payload = request.split(".")
205
-
206
- sig = base64_url_decode(encoded_sig)
207
-
208
- # if the signature matches, return the data, decoded and parsed as JSON
209
- if OpenSSL::HMAC.digest("sha256", @app_secret, payload) == sig
210
- JSON.parse(base64_url_decode(payload))
211
- else
212
- nil
213
- end
211
+
212
+ # provided directly by Facebook
213
+ # see https://github.com/facebook/crypto-request-examples/blob/master/sample.rb
214
+ # and http://developers.facebook.com/docs/authentication/canvas/encryption_proposal
215
+ def parse_signed_request(input, max_age = 3600)
216
+ encoded_sig, encoded_envelope = input.split('.', 2)
217
+ envelope = JSON.parse(base64_url_decode(encoded_envelope))
218
+ algorithm = envelope['algorithm']
219
+
220
+ raise 'Invalid request. (Unsupported algorithm.)' \
221
+ if algorithm != 'AES-256-CBC HMAC-SHA256' && algorithm != 'HMAC-SHA256'
222
+
223
+ raise 'Invalid request. (Too old.)' \
224
+ if algorithm == "AES-256-CBC HMAC-SHA256" && envelope['issued_at'].to_i < Time.now.to_i - max_age
225
+
226
+ raise 'Invalid request. (Invalid signature.)' \
227
+ if base64_url_decode(encoded_sig) !=
228
+ OpenSSL::HMAC.hexdigest(
229
+ 'sha256', @app_secret, encoded_envelope).split.pack('H*')
230
+
231
+ # for requests that are signed, but not encrypted, we're done
232
+ return envelope if algorithm == 'HMAC-SHA256'
233
+
234
+ # otherwise, decrypt the payload
235
+ cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
236
+ cipher.decrypt
237
+ cipher.key = @app_secret
238
+ cipher.iv = base64_url_decode(envelope['iv'])
239
+ cipher.padding = 0
240
+ decrypted_data = cipher.update(base64_url_decode(envelope['payload']))
241
+ decrypted_data << cipher.final
242
+ return JSON.parse(decrypted_data.strip)
214
243
  end
215
244
 
216
245
  # from session keys
@@ -220,66 +249,68 @@ module Koala
220
249
  :type => 'client_cred',
221
250
  :sessions => sessions.join(",")
222
251
  }, true, "exchange_sessions")
223
-
252
+
224
253
  # Facebook returns an empty body in certain error conditions
225
- if response == ""
226
- raise APIError.new("ArgumentError", "get_token_from_session_key received an error (empty response body) for sessions #{sessions.inspect}!")
254
+ if response == ""
255
+ raise APIError.new({
256
+ "type" => "ArgumentError",
257
+ "message" => "get_token_from_session_key received an error (empty response body) for sessions #{sessions.inspect}!"
258
+ })
227
259
  end
228
-
260
+
229
261
  JSON.parse(response)
230
262
  end
231
-
263
+
232
264
  def get_tokens_from_session_keys(sessions)
233
265
  # get the original hash results
234
266
  results = get_token_info_from_session_keys(sessions)
235
267
  # now recollect them as just the access tokens
236
268
  results.collect { |r| r ? r["access_token"] : nil }
237
269
  end
238
-
270
+
239
271
  def get_token_from_session_key(session)
240
272
  # convenience method for a single key
241
273
  # gets the overlaoded strings automatically
242
274
  get_tokens_from_session_keys([session])[0]
243
275
  end
244
-
276
+
245
277
  protected
246
-
278
+
247
279
  def get_token_from_server(args, post = false)
248
280
  # fetch the result from Facebook's servers
249
281
  result = fetch_token_string(args, post)
250
-
282
+
251
283
  # if we have an error, parse the error JSON and raise an error
252
284
  raise APIError.new((JSON.parse(result)["error"] rescue nil) || {}) if result =~ /error/
253
285
 
254
286
  # otherwise, parse the access token
255
- parse_access_token(result)
287
+ parse_access_token(result)
256
288
  end
257
-
289
+
258
290
  def parse_access_token(response_text)
259
291
  components = response_text.split("&").inject({}) do |hash, bit|
260
292
  key, value = bit.split("=")
261
293
  hash.merge!(key => value)
262
294
  end
263
- components
295
+ components
264
296
  end
265
297
 
266
298
  def fetch_token_string(args, post = false, endpoint = "access_token")
267
299
  Koala.make_request("/oauth/#{endpoint}", {
268
- :client_id => @app_id,
300
+ :client_id => @app_id,
269
301
  :client_secret => @app_secret
270
- }.merge!(args), post ? "post" : "get").body
302
+ }.merge!(args), post ? "post" : "get", :use_ssl => true).body
271
303
  end
272
-
304
+
273
305
  # base 64
274
- def base64_url_decode(string)
275
- # to properly decode what Facebook provides, we need to add == to the end
276
- # and translate certain characters to others before running the actual decoding
277
- # see http://developers.facebook.com/docs/authentication/canvas
278
- "#{string}==".tr("-_", "+/").unpack("m")[0]
306
+ # directly from https://github.com/facebook/crypto-request-examples/raw/master/sample.rb
307
+ def base64_url_decode(str)
308
+ str += '=' * (4 - str.length.modulo(4))
309
+ Base64.decode64(str.gsub('-', '+').gsub('_', '/'))
279
310
  end
280
311
  end
281
312
  end
282
-
313
+
283
314
  # finally, set up the http service Koala methods used to make requests
284
315
  # you can use your own (for HTTParty, etc.) by calling Koala.http_service = YourModule
285
316
  def self.http_service=(service)
@@ -288,7 +319,6 @@ module Koala
288
319
 
289
320
  # by default, try requiring Typhoeus -- if that works, use it
290
321
  begin
291
- require 'typhoeus'
292
322
  Koala.http_service = TyphoeusService
293
323
  rescue LoadError
294
324
  Koala.http_service = NetHTTPService
data/readme.md CHANGED
@@ -1,28 +1,28 @@
1
1
  Koala
2
2
  ====
3
- Koala (<a href="http://github.com/arsduo/koala" target="_blank">http://github.com/arsduo/koala</a>) is a new Facebook library for Ruby, supporting the Graph API, the old REST API, realtime updates, and OAuth validation. We wrote Koala with four goals:
3
+ Koala (<a href="http://github.com/arsduo/koala" target="_blank">http://github.com/arsduo/koala</a>) is a new Facebook library for Ruby, supporting the Graph API, the old REST API, realtime updates, and OAuth validation. We wrote Koala with four goals:
4
4
 
5
- * Lightweight: Koala should be as light and simple as Facebook’s own new libraries, providing API accessors and returning simple JSON. (We clock in, with comments, just over 500 lines of code.)
5
+ * Lightweight: Koala should be as light and simple as Facebook’s own new libraries, providing API accessors and returning simple JSON. (We clock in, with comments, just over 750 lines of code.)
6
6
  * Fast: Koala should, out of the box, be quick. In addition to supporting the vanilla Ruby networking libraries, it natively supports Typhoeus, our preferred gem for making fast HTTP requests. Of course, That brings us to our next topic:
7
7
  * Flexible: Koala should be useful to everyone, regardless of their current configuration. (We have no dependencies beyond the JSON gem. Koala also has a built-in mechanism for using whichever HTTP library you prefer to make requests against the graph.)
8
8
  * Tested: Koala should have complete test coverage, so you can rely on it. (Our complete test coverage can be run against either mocked responses or the live Facebook servers.)
9
9
 
10
10
  Graph API
11
11
  ----
12
- The Graph API is the simple, slick new interface to Facebook's data. Using it with Koala is quite straightforward:
12
+ The Graph API is the simple, slick new interface to Facebook's data. Using it with Koala is quite straightforward:
13
13
 
14
14
  graph = Koala::Facebook::GraphAPI.new(oauth_access_token)
15
15
  profile = graph.get_object("me")
16
16
  friends = graph.get_connections("me", "friends")
17
17
  graph.put_object("me", "feed", :message => "I am writing on my wall!")
18
18
 
19
- The response of most requests is the JSON data returned from the Facebook servers as a Hash.
19
+ The response of most requests is the JSON data returned from the Facebook servers as a Hash.
20
20
 
21
21
  When retrieving data that returns an array of results (for example, when calling GraphAPI#get_connections or GraphAPI#search) a GraphCollection object (a sub-class of Array) will be returned, which contains added methods for getting the next and previous page of results:
22
-
22
+
23
23
  # Returns the feed items for the currently logged-in user as a GraphCollection
24
24
  feed = graph.get_connections("me", "feed")
25
-
25
+
26
26
  # GraphCollection is a sub-class of Array, so you can use it as a usual Array
27
27
  first_entry = feed[0]
28
28
  last_entry = feed.last
@@ -33,7 +33,7 @@ When retrieving data that returns an array of results (for example, when calling
33
33
  # Returns an array describing the URL for the next page: [path, arguments]
34
34
  # This is useful for paging across multiple requests
35
35
  next_path, next_args = feed.next_page_params
36
-
36
+
37
37
  # You can use those params to easily get the next (or prevous) page
38
38
  page = graph.get_page(feed.next_page_params)
39
39
 
@@ -41,25 +41,26 @@ Check out the wiki for more examples.
41
41
 
42
42
  The old-school REST API
43
43
  -----
44
- Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls that can't yet be done via the Graph.
44
+ Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls that can't yet be done via the Graph.
45
45
 
46
46
  Koala now supports the old-school REST API using OAuth access tokens; to use this, instantiate your class using the RestAPI class:
47
47
 
48
48
  @rest = Koala::Facebook::RestAPI.new(oauth_access_token)
49
49
  @rest.fql_query(my_fql_query) # convenience method
50
50
  @rest.rest_call("stream.publish", arguments_hash) # generic version
51
-
52
- We reserve the right to expand the built-in REST API coverage to additional convenience methods in the future, depending on how fast Facebook moves to fill in the gaps.
51
+
52
+ We reserve the right to expand the built-in REST API coverage to additional convenience methods in the future, depending on how fast Facebook moves to fill in the gaps.
53
53
 
54
54
  (If you want the power of both APIs in the palm of your hand, try out the GraphAndRestAPI class.)
55
55
 
56
56
  OAuth
57
57
  -----
58
58
  You can use the Graph and REST APIs without an OAuth access token, but the real magic happens when you provide Facebook an OAuth token to prove you're authenticated. Koala provides an OAuth class to make that process easy:
59
- @oauth = Koala::Facebook::OAuth.new(app_id, code, callback_url)
59
+ @oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
60
60
 
61
61
  If your application uses Koala and the Facebook [JavaScript SDK](http://github.com/facebook/connect-js) (formerly Facebook Connect), you can use the OAuth class to parse the cookies:
62
- @oauth.get_user_from_cookie(cookies)
62
+ @oauth.get_user_from_cookies(cookies) # gets the user's ID
63
+ @oauth.get_user_info_from_cookies(cookies) # parses and returns the entire hash
63
64
 
64
65
  And if you have to use the more complicated [redirect-based OAuth process](http://developers.facebook.com/docs/authentication/), Koala helps out there, too:
65
66
  # generate authenticating URL
@@ -118,7 +119,7 @@ Some resources to help you as you play with Koala and the Graph API:
118
119
  Testing
119
120
  -----
120
121
 
121
- Unit tests are provided for all of Koala's methods. By default, these tests run against mock responses and hence are ready out of the box:
122
+ Unit tests are provided for all of Koala's methods. By default, these tests run against mock responses and hence are ready out of the box:
122
123
  # From the spec directory
123
124
  spec koala_spec.rb
124
125
 
@@ -4,19 +4,19 @@
4
4
  # Just remember to update all fields!
5
5
 
6
6
  # You must supply this value yourself to test the GraphAPI class.
7
- # Your OAuth token should have publish_stream and read_stream permissions.
8
- oauth_token: 119908831367602|2.K0IVdhrRngS7VQM4Z_s6_g__.3600.1285844400-2905623|Q3VNUb9haS3s29X4SYPk6VL1f9A
7
+ # Your OAuth token should have publish_stream, read_stream, and user_photos permissions.
8
+ oauth_token:
9
9
 
10
10
  # for testing the OAuth class
11
11
  # baseline app
12
12
  oauth_test_data:
13
13
  # You must supply this value yourself, since they will expire.
14
- code: 2.K0IVdhrRngS7VQM4Z_s6_g__.3600.1285844400-2905623|b5PCXOhEMe2FJXPHAg_mY3Psl6M
14
+ code:
15
15
  # easiest way to get session keys: use multiple test accounts with the Javascript login at http://oauth.twoalex.com
16
- session_key: 2.K0IVdhrRngS7VQM4Z_s6_g__.3600.1285844400-2905623
16
+ session_key:
17
17
  multiple_session_keys:
18
- - 2.K0IVdhrRngS7VQM4Z_s6_g__.3600.1285844400-2905623
19
- - 2.K0IVdhrRngS7VQM4Z_s6_g__.3600.1285844400-2905623
18
+ -
19
+ -
20
20
 
21
21
  # These values will work out of the box
22
22
  app_id: 119908831367602
@@ -44,8 +44,14 @@ oauth_test_data:
44
44
  signed_request_result:
45
45
  "0": payload
46
46
  algorithm: HMAC-SHA256
47
-
48
-
47
+ # signed params
48
+ # examples from http://developers.facebook.com/docs/authentication/canvas/encryption_proposal
49
+ signed_params: t63pZQ4Q3ZTHJt0hOsKrY2pb28xRlduW0pg4lL_Zhl4.eyJhbGdvcml0aG0iOiJBRVMtMjU2LUNCQyBITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTI4NzYwMTk4OCwiaXYiOiJmRExKQ1cteWlYbXVOYTI0ZVNhckpnIiwicGF5bG9hZCI6IllHeW00cG9Rbk1UckVnaUFPa0ZUVkk4NWxsNVJ1VWlFbC1JZ3FmeFRPVEhRTkl2VlZJOFk4a1Z1T29lS2FXT2Vhc3NXRlRFdjBRZ183d0NDQkVlbjdsVUJCemxGSjFWNjNISjNBZjBTSW5nY3hXVEo3TDZZTGF0TW13WGdEQXZXbjVQc2ZxeldrNG1sOWg5RExuWXB0V0htREdMNmlCaU9oTjdXeUk3cDZvRXBWcmlGdUp3X2NoTG9QYjhhM3ZHRG5vVzhlMlN4eDA2QTJ4MnhraWFwdmcifQ
50
+ signed_params_secret: 13750c9911fec5865d01f3bd00bdf4db
51
+ signed_params_result:
52
+ access_token: "101244219942650|2.wdrSr7KyE_VwQ0fjwOfW9A__.3600.1287608400-499091902|XzxMQd-_4tjlC2VEgide4rmg6LI"
53
+ expires_in: 6412
54
+ user_id: "499091902"
49
55
 
50
56
  subscription_test_data:
51
57
  subscription_path: http://oauth.twoalex.com/subscriptions
@@ -1,4 +1,5 @@
1
1
  class ApiBaseTests < Test::Unit::TestCase
2
+
2
3
  describe "Koala API base class" do
3
4
  before(:each) do
4
5
  @service = Koala::Facebook::API.new
@@ -29,6 +30,12 @@ class ApiBaseTests < Test::Unit::TestCase
29
30
  service.api('anything')
30
31
  end
31
32
 
33
+ it "should have an attr_reader for access token" do
34
+ token = 'adfadf'
35
+ service = Koala::Facebook::API.new token
36
+ service.access_token.should == token
37
+ end
38
+
32
39
  it "should get the attribute of a Koala::Response given by the http_component parameter" do
33
40
  http_component = :method_name
34
41
 
Binary file
@@ -3,8 +3,12 @@ class GraphAndRestAPINoTokenTests < Test::Unit::TestCase
3
3
  before(:each) do
4
4
  @api = Koala::Facebook::GraphAndRestAPI.new
5
5
  end
6
-
6
+
7
+ it_should_behave_like "Koala RestAPI"
7
8
  it_should_behave_like "Koala RestAPI without an access token"
9
+
10
+ it_should_behave_like "Koala GraphAPI"
8
11
  it_should_behave_like "Koala GraphAPI without an access token"
12
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
9
13
  end
10
14
  end
@@ -1,11 +1,16 @@
1
1
  class GraphAndRestAPIWithTokenTests < Test::Unit::TestCase
2
2
  describe "Koala GraphAndRestAPI without an access token" do
3
- it_should_behave_like "live testing examples"
4
- it_should_behave_like "Koala RestAPI with an access token"
5
- it_should_behave_like "Koala GraphAPI with an access token"
6
-
3
+ include LiveTestingDataHelper
4
+
7
5
  before(:each) do
8
6
  @api = Koala::Facebook::GraphAndRestAPI.new(@token)
9
7
  end
8
+
9
+ it_should_behave_like "Koala RestAPI"
10
+ it_should_behave_like "Koala RestAPI with an access token"
11
+
12
+ it_should_behave_like "Koala GraphAPI"
13
+ it_should_behave_like "Koala GraphAPI with an access token"
14
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
10
15
  end
11
16
  end
@@ -1,9 +1,4 @@
1
1
  shared_examples_for "Koala GraphAPI without an access token" do
2
- it "should get public data about a user" do
3
- result = @api.get_object("koppel")
4
- # the results should have an ID and a name, among other things
5
- (result["id"] && result["name"]).should
6
- end
7
2
 
8
3
  it "should not get private data about a user" do
9
4
  result = @api.get_object("koppel")
@@ -11,46 +6,14 @@ shared_examples_for "Koala GraphAPI without an access token" do
11
6
  result["updated_time"].should be_nil
12
7
  end
13
8
 
14
- it "should get public data about a Page" do
15
- result = @api.get_object("contextoptional")
16
- # the results should have an ID and a name, among other things
17
- (result["id"] && result["name"]).should
18
- end
19
-
20
9
  it "should not be able to get data about 'me'" do
21
10
  lambda { @api.get_object("me") }.should raise_error(Koala::Facebook::APIError)
22
11
  end
23
12
 
24
- it "should be able to get multiple objects" do
25
- results = @api.get_objects(["contextoptional", "naitik"])
26
- results.length.should == 2
27
- end
28
-
29
13
  it "shouldn't be able to access connections from users" do
30
14
  lambda { @api.get_connections("lukeshepard", "likes") }.should raise_error(Koala::Facebook::APIError)
31
15
  end
32
16
 
33
- it "should be able to access a user's picture" do
34
- @api.get_picture("chris.baclig").should =~ /http\:\/\//
35
- end
36
-
37
- it "should be able to access a user's picture, given a picture type" do
38
- @api.get_picture("chris.baclig", {:type => 'large'}).should =~ /^http\:\/\//
39
- end
40
-
41
- it "should be able to access connections from public Pages" do
42
- result = @api.get_connections("contextoptional", "photos")
43
- result.should be_a(Array)
44
- end
45
-
46
- # paging
47
- # see also graph_collection_tests
48
- it "should make a request for a page when provided a specific set of page params" do
49
- query = [1, 2]
50
- @api.should_receive(:graph_call).with(*query)
51
- @api.get_page(query)
52
- end
53
-
54
17
  it "should not be able to put an object" do
55
18
  lambda { @result = @api.put_object("lukeshepard", "feed", :message => "Hello, world") }.should raise_error(Koala::Facebook::APIError)
56
19
  puts "Error! Object #{@result.inspect} somehow put onto Luke Shepard's wall!" if @result
@@ -60,7 +23,7 @@ shared_examples_for "Koala GraphAPI without an access token" do
60
23
  it "should not be able to post to a feed" do
61
24
  (lambda do
62
25
  attachment = {:name => "Context Optional", :link => "http://www.contextoptional.com/"}
63
- @result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
26
+ @result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
64
27
  end).should raise_error(Koala::Facebook::APIError)
65
28
  puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
66
29
  end
@@ -68,7 +31,7 @@ shared_examples_for "Koala GraphAPI without an access token" do
68
31
  it "should not be able to comment on an object" do
69
32
  # random public post on the ContextOptional wall
70
33
  lambda { @result = @api.put_comment("7204941866_119776748033392", "The hackathon was great!") }.should raise_error(Koala::Facebook::APIError)
71
- puts "Error! Object #{@result.inspect} somehow commented on post 7204941866_119776748033392!" if @result
34
+ puts "Error! Object #{@result.inspect} somehow commented on post 7204941866_119776748033392!" if @result
72
35
  end
73
36
 
74
37
  it "should not be able to like an object" do
@@ -76,29 +39,13 @@ shared_examples_for "Koala GraphAPI without an access token" do
76
39
  end
77
40
 
78
41
  # DELETE
79
- it "should not be able to delete posts" do
42
+ it "should not be able to delete posts" do
80
43
  # test post on the Ruby SDK Test application
81
44
  lambda { @result = @api.delete_object("115349521819193_113815981982767") }.should raise_error(Koala::Facebook::APIError)
82
45
  end
83
-
84
- # SEARCH
85
- it "should be able to search" do
86
- result = @api.search("facebook")
87
- result.length.should be_an(Integer)
88
- end
89
-
90
- it_should_behave_like "Koala GraphAPI with GraphCollection"
91
46
 
92
- # API
93
- it "should never use the rest api server" do
94
- Koala.should_receive(:make_request).with(
95
- anything,
96
- anything,
97
- anything,
98
- hash_not_including(:rest_api => true)
99
- ).and_return(Koala::Response.new(200, "", {}))
100
-
101
- @api.api("anything")
47
+ it "should not be able to delete a like" do
48
+ lambda { @api.delete_like("7204941866_119776748033392") }.should raise_error(Koala::Facebook::APIError)
102
49
  end
103
50
  end
104
51
 
@@ -106,9 +53,11 @@ class FacebookNoAccessTokenTests < Test::Unit::TestCase
106
53
  describe "Koala GraphAPI without an access token" do
107
54
  before :each do
108
55
  @api = Koala::Facebook::GraphAPI.new
109
- end
110
-
56
+ end
57
+
58
+ it_should_behave_like "Koala GraphAPI"
111
59
  it_should_behave_like "Koala GraphAPI without an access token"
60
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
61
+
112
62
  end
113
63
  end
114
-