koala 0.7.1 → 0.7.3

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 (34) hide show
  1. data/CHANGELOG +18 -0
  2. data/LICENSE +22 -0
  3. data/Manifest +19 -4
  4. data/Rakefile +2 -1
  5. data/examples/oauth_playground/Capfile +2 -0
  6. data/examples/oauth_playground/LICENSE +22 -0
  7. data/examples/oauth_playground/Rakefile +4 -0
  8. data/examples/oauth_playground/config/deploy.rb +39 -0
  9. data/examples/oauth_playground/config/facebook.yml +13 -0
  10. data/examples/oauth_playground/config.ru +27 -0
  11. data/examples/oauth_playground/lib/load_facebook.rb +3 -0
  12. data/examples/oauth_playground/lib/oauth_playground.rb +187 -0
  13. data/examples/oauth_playground/readme.md +8 -0
  14. data/examples/oauth_playground/spec/oauth_playground_spec.rb +35 -0
  15. data/examples/oauth_playground/spec/spec_helper.rb +36 -0
  16. data/examples/oauth_playground/tmp/restart.txt +0 -0
  17. data/examples/oauth_playground/views/index.erb +206 -0
  18. data/examples/oauth_playground/views/layout.erb +39 -0
  19. data/koala.gemspec +4 -4
  20. data/lib/{graph_api.rb → koala/graph_api.rb} +4 -4
  21. data/lib/koala.rb +95 -12
  22. data/readme.md +4 -1
  23. data/spec/facebook_data.yml +8 -3
  24. data/spec/koala/api_base_tests.rb +69 -2
  25. data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +4 -0
  26. data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +4 -0
  27. data/spec/koala/net_http_service_tests.rb +169 -5
  28. data/spec/koala/oauth/oauth_tests.rb +193 -40
  29. data/spec/mock_facebook_responses.yml +21 -1
  30. data/spec/mock_http_service.rb +6 -1
  31. metadata +27 -11
  32. /data/lib/{http_services.rb → koala/http_services.rb} +0 -0
  33. /data/lib/{realtime_updates.rb → koala/realtime_updates.rb} +0 -0
  34. /data/lib/{rest_api.rb → koala/rest_api.rb} +0 -0
@@ -0,0 +1,206 @@
1
+ <div id="header">
2
+ <h1>Facebook OAuth Playground</h1>
3
+ <h4>Powered by <a href="http://github.com/arsduo/koala" target="_blank">Koala</a></h2>
4
+ <h4>For novelty use only. Remember, the application's secret key is public.</h4>
5
+ </div>
6
+
7
+ <style>
8
+ #header {
9
+ text-align: center;
10
+ }
11
+
12
+ h1, h2, h3, h4 { margin: 0; }
13
+
14
+ .section {
15
+ border: 1px solid black;
16
+ padding: 10px;
17
+ -moz-border-radius: 9px;
18
+ -webkit-border-radius: 9px;
19
+ margin-bottom: 10px;
20
+ width: 100%;
21
+ }
22
+
23
+ #contents {
24
+ border: 2px solid #CCC;
25
+ border-width: 2px 0;
26
+ background-color: #EEE;
27
+ padding: 14px 3px 8px 8px;
28
+ }
29
+
30
+ #configurationInfo {
31
+ float:left;
32
+ margin-right: 2.5%;
33
+ width: 25%;
34
+ }
35
+
36
+ #configurationInfo .section {
37
+ background-color: #CCC;
38
+ }
39
+
40
+ #permissions .header {
41
+ margin-bottom: 5px;
42
+ }
43
+
44
+ #permissions .list {
45
+ height: 380px;
46
+ overflow: auto;
47
+ }
48
+
49
+ #generatedInfo {
50
+ float: left;
51
+ width: 70%;
52
+ }
53
+
54
+ #generatedInfo .section {
55
+ border-color: gray;
56
+ background: #DDD;
57
+ overflow: auto;
58
+ }
59
+
60
+ .clearFloat {
61
+ height: 1px;
62
+ height: 0px;
63
+ clear: both;
64
+ overflow: hidden;
65
+ }
66
+
67
+ ul, li { margin: 0; padding: 0; list-style: none; }
68
+ ul { margin: 12px 0; }
69
+
70
+ .code {
71
+ font-family: Courier, fixed;
72
+ font-size: 1.15em;
73
+ width: 100%;
74
+ }
75
+
76
+ .explanation {
77
+ font-size: 0.9em;
78
+ }
79
+
80
+ .datumName {
81
+ font-weight: bold;
82
+ }
83
+
84
+ .permissionType {
85
+ font-style: italic;
86
+ }
87
+ </style>
88
+
89
+ </style>
90
+
91
+ <div id="contents">
92
+
93
+ <div id="configurationInfo">
94
+ <div id="fbApp" class="section">
95
+ <h3>Facebook App Info</h3>
96
+ <ul>
97
+ <% @app_data.each_pair do |key, value| %>
98
+ <li><span class="datumName"><%= key %>:</span> <%= value %></li>
99
+ <% end %>
100
+ </ul>
101
+ </div>
102
+
103
+ <div id="permissions" class="section">
104
+ <form method="get">
105
+ <div class="header">
106
+ <h3>Permissions</h3>
107
+ <input type="submit" value="Update permissions" />
108
+ <a href="/">Reset Selection</a>
109
+ <div class="explanation">Choose permissions for the OAuth URL and the fb:login button.</div>
110
+ <% if @fetched_permissions %>
111
+ <div class="permissionType">Showing currently-active permissions</div>
112
+ <div class="explanation">(These were fetched by Koala as the page loaded!)</div>
113
+ <% else %>
114
+ <div class="permissionType">Showing selected permissions</div>
115
+ <% end %>
116
+ </div>
117
+
118
+ <div class="list">
119
+ <% @available_permissions.each do |permissions| %>
120
+ <h4><%= permissions[:name] %> Permissions</h4>
121
+ <ul>
122
+ <% permissions[:perms].each do |p| %>
123
+ <li>
124
+ <input type="checkbox" id="permission<%= p %>" name="permissions[]" value="<%= p %>" <%= @active_permissions.include?(p) ? "checked='checked'" : "" %> />
125
+ <label for="permission<%= p %>"><%= p %></a> (<a href="#" onclick="FB.api({method: 'auth.revokeExtendedPermission', perm: '<%= p %>'}, function(response) { alert(response) }); return false;">revoke</a>)
126
+ </li>
127
+ <% end %>
128
+ </ul>
129
+ <% end %>
130
+ </div>
131
+ </form>
132
+ </div>
133
+ </div>
134
+
135
+ <div id="generatedInfo">
136
+ <div id="oauthURLs" class="section">
137
+ <h3>OAuth URLs</h3>
138
+ <ul>
139
+ <li><span class="datumName">Generate a code:</span> <a href="<%= @oauth.url_for_oauth_code(:permissions => @permissions) %>"><%= @oauth.url_for_oauth_code(:permissions => @permissions) %></a></li>
140
+ <li><span class="datumName">OAuth code:</span> <%= @code || "click on the link above" %></li>
141
+ <li>
142
+ <span class="datumName">Access token:</span> <%= @oauth_access_token || "click on the link above" %>
143
+ <% if @oauth_access_token %><div class="explanation">This was fetched by Koala as the page loaded!</div><% end %>
144
+ </li>
145
+ <li><span class="datumName">Expiration:</span> <%= @expiration || "click on the link above" %></li>
146
+ <li><span class="datumName">Raw access response:</span> <%= @raw_access_response || "click on the link above" %></li>
147
+ <li><span class="datumName">URL for access code:</span>
148
+ <% if @code %>
149
+ <a href="<%= @oauth.url_for_access_token(@code) %>"><%= @oauth.url_for_access_token(@code) %></a>
150
+ <% else %>
151
+ click on the link above
152
+ <% end %>
153
+ </li>
154
+ </ul>
155
+ </div>
156
+
157
+ <div id="jsLogin" class="section">
158
+ <h3>Javascript Login (e.g. Facebook Connect)</h3>
159
+ <p>
160
+ <fb:login-button onlogin="location.reload()" perms="<%= (@permissions || []).join(",") %>"></fb:login-button>
161
+ <% if @permissions %>
162
+ and prompt for <%= @permissions.join(", ") %>
163
+ <% end %>
164
+ <% if @facebook_cookies %>
165
+ <div class="logout">
166
+ <a href="#" onclick="FB.logout(function() { location.reload() }); return false;">Logout</a>
167
+ </div>
168
+ <% end %>
169
+ </p>
170
+ </div>
171
+
172
+ <div id="cookieInfo" class="section">
173
+ <h3>Cookie info</h3>
174
+ <ul>
175
+ <% if @facebook_cookies %>
176
+ <% @facebook_cookies.each_pair do |key, value| %>
177
+ <li><span class="datumName"><%= key %>:</span> <%= value %></li>
178
+ <% end %>
179
+ <% else %>
180
+ <li>You're not signed in via Javascript. Login below.</li>
181
+ <% end %>
182
+ <li><span class="datumName">Raw hash</span>:
183
+ <div class="code"><%= request.cookies.inspect %></div>
184
+ </li>
185
+ </ul>
186
+ </div>
187
+
188
+ <div id="koala" class="section">
189
+ <h3>Koala</h3>
190
+ <ul>
191
+ <li><span class="datumName">GraphAPI:</span>
192
+ <div class="code"><%= @access_token ? "@graph = Koala::Facebook::GraphAPI.new(\"#{@access_token}\")" : "sign in above" %></div>
193
+ </li>
194
+ <li><span class="datumName">OAuth:</span>
195
+ <div class="code">@oauth = Koala::Facebook::OAuth.new(<%= @app_data["app_id"] %>, "<%= @app_data["secret_key"] %>", "<%= @app_data["callback_url"] %>")</div>
196
+ </li>
197
+ </ul>
198
+ </div>
199
+ </div>
200
+
201
+ <div class="clearFloat">&nbsp;</div>
202
+ </div>
203
+
204
+ <center>
205
+ <h5>Check out the playground's code at <a href="http://github.com/arsduo/oauth_playground">http://github.com/arsduo/oauth_playground</a>!</h5>
206
+ </center>
@@ -0,0 +1,39 @@
1
+ <html>
2
+ <head>
3
+ <title>Facebook OAuth Playground</title>
4
+ <meta name="description" content="Making it easier to play with Facebook's new Graph API and OAuth authentication."></meta>
5
+ <style>
6
+ body {
7
+ font-family: verdana, arial, sans-serif;
8
+ font-size: 12px;
9
+ margin: 0px;
10
+ }
11
+ </style>
12
+ </head>
13
+ <body>
14
+
15
+ <script type="text/javascript">
16
+
17
+ var _gaq = _gaq || [];
18
+ _gaq.push(['_setAccount', 'UA-16395421-1']);
19
+ _gaq.push(['_trackPageview']);
20
+
21
+ (function() {
22
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
23
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
24
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
25
+ })();
26
+
27
+ </script>
28
+
29
+ <%= yield %>
30
+
31
+ <div id="fb-root"></div>
32
+ <script src="http://connect.facebook.net/en_US/all.js"></script>
33
+ <script>
34
+ FB.init({ appId: <%= @app_data["app_id"] %>, cookie: true, status: true, xfbml: true });
35
+ </script>
36
+
37
+ </body>
38
+
39
+ </html>
data/koala.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{koala}
5
- s.version = "0.7.1"
5
+ s.version = "0.7.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional"]
9
- s.date = %q{2010-05-27}
9
+ s.date = %q{2010-06-22}
10
10
  s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
11
11
  s.email = %q{alex@alexkoppel.com}
12
- s.extra_rdoc_files = ["CHANGELOG", "lib/graph_api.rb", "lib/http_services.rb", "lib/koala.rb", "lib/realtime_updates.rb", "lib/rest_api.rb"]
13
- s.files = ["CHANGELOG", "Manifest", "Rakefile", "init.rb", "lib/graph_api.rb", "lib/http_services.rb", "lib/koala.rb", "lib/realtime_updates.rb", "lib/rest_api.rb", "readme.md", "spec/facebook_data.yml", "spec/koala/api_base_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb", "spec/koala/graph_api/graph_api_no_access_token_tests.rb", "spec/koala/graph_api/graph_api_with_access_token_tests.rb", "spec/koala/live_testing_data_helper.rb", "spec/koala/net_http_service_tests.rb", "spec/koala/oauth/oauth_tests.rb", "spec/koala/realtime_updates/realtime_updates_tests.rb", "spec/koala/rest_api/rest_api_no_access_token_tests.rb", "spec/koala/rest_api/rest_api_with_access_token_tests.rb", "spec/koala_spec.rb", "spec/koala_spec_helper.rb", "spec/koala_spec_without_mocks.rb", "spec/mock_facebook_responses.yml", "spec/mock_http_service.rb", "koala.gemspec"]
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb"]
13
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "Rakefile", "examples/oauth_playground/Capfile", "examples/oauth_playground/LICENSE", "examples/oauth_playground/Rakefile", "examples/oauth_playground/config.ru", "examples/oauth_playground/config/deploy.rb", "examples/oauth_playground/config/facebook.yml", "examples/oauth_playground/lib/load_facebook.rb", "examples/oauth_playground/lib/oauth_playground.rb", "examples/oauth_playground/readme.md", "examples/oauth_playground/spec/oauth_playground_spec.rb", "examples/oauth_playground/spec/spec_helper.rb", "examples/oauth_playground/tmp/restart.txt", "examples/oauth_playground/views/index.erb", "examples/oauth_playground/views/layout.erb", "init.rb", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb", "readme.md", "spec/facebook_data.yml", "spec/koala/api_base_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb", "spec/koala/graph_api/graph_api_no_access_token_tests.rb", "spec/koala/graph_api/graph_api_with_access_token_tests.rb", "spec/koala/live_testing_data_helper.rb", "spec/koala/net_http_service_tests.rb", "spec/koala/oauth/oauth_tests.rb", "spec/koala/realtime_updates/realtime_updates_tests.rb", "spec/koala/rest_api/rest_api_no_access_token_tests.rb", "spec/koala/rest_api/rest_api_with_access_token_tests.rb", "spec/koala_spec.rb", "spec/koala_spec_helper.rb", "spec/koala_spec_without_mocks.rb", "spec/mock_facebook_responses.yml", "spec/mock_http_service.rb", "koala.gemspec"]
14
14
  s.homepage = %q{http://github.com/arsduo/koala}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Koala", "--main", "readme.md"]
16
16
  s.require_paths = ["lib"]
@@ -47,11 +47,11 @@ module Koala
47
47
  graph_call("#{id}/#{connection_name}", args)["data"]
48
48
  end
49
49
 
50
- def get_picture(object)
51
- result = graph_call("#{object}/picture", {}, "get", :http_component => :headers)
50
+ def get_picture(object, args = {})
51
+ result = graph_call("#{object}/picture", args, "get", :http_component => :headers)
52
52
  result["Location"]
53
- end
54
-
53
+ end
54
+
55
55
  def put_object(parent_object, connection_name, args = {})
56
56
  # Writes the given object to the graph, connected to the given parent.
57
57
  #
data/lib/koala.rb CHANGED
@@ -6,15 +6,15 @@ require 'rubygems'
6
6
  require 'json'
7
7
 
8
8
  # include default http services
9
- require 'http_services'
9
+ require 'koala/http_services'
10
10
 
11
11
  # add Graph API methods
12
- require 'graph_api'
12
+ require 'koala/graph_api'
13
13
 
14
14
  # add REST API methods
15
- require 'rest_api'
15
+ require 'koala/rest_api'
16
16
 
17
- require 'realtime_updates'
17
+ require 'koala/realtime_updates'
18
18
 
19
19
  module Koala
20
20
 
@@ -52,6 +52,11 @@ module Koala
52
52
  # make the request via the provided service
53
53
  result = Koala.make_request(path, args, verb, options)
54
54
 
55
+ # Check for any 500 errors before parsing the body
56
+ # since we're not guaranteed that the body is valid JSON
57
+ # in the case of a server error
58
+ raise APIError.new({"type" => "HTTP #{result.status.to_s}", "message" => "Response body: #{result.body}"}) if result.status >= 500
59
+
55
60
  # Parse the body as JSON and check for errors if provided a mechanism to do so
56
61
  # Note: Facebook sometimes sends results like "true" and "false", which aren't strictly objects
57
62
  # and cause JSON.parse to fail -- so we account for that by wrapping the result in []
@@ -103,11 +108,10 @@ module Koala
103
108
  @oauth_callback_url = oauth_callback_url
104
109
  end
105
110
 
106
- def get_user_from_cookie(cookie_hash)
111
+ def get_user_info_from_cookie(cookie_hash)
107
112
  # Parses the cookie set by the official Facebook JavaScript SDK.
108
113
  #
109
- # cookies should be a dictionary-like object mapping cookie names to
110
- # cookie values.
114
+ # cookies should be a Hash, like the one Rails provides
111
115
  #
112
116
  # If the user is logged in via Facebook, we return a dictionary with the
113
117
  # keys "uid" and "access_token". The former is the user's Facebook ID,
@@ -132,8 +136,20 @@ module Koala
132
136
  sig == components["sig"] && (components["expires"] == "0" || Time.now.to_i < components["expires"].to_i) ? components : nil
133
137
  end
134
138
  end
139
+ alias_method :get_user_info_from_cookies, :get_user_info_from_cookie
140
+
141
+ def get_user_from_cookie(cookies)
142
+ # overload this to be backward compatible with older implementations
143
+ # icky ruby magic, but it's _really_ cool we can do this
144
+ info = get_user_info_from_cookies(cookies)
145
+ string = info["uid"]
146
+
147
+ overload_as_hash(string, info)
148
+ end
135
149
  alias_method :get_user_from_cookies, :get_user_from_cookie
136
150
 
151
+ # URLs
152
+
137
153
  def url_for_oauth_code(options = {})
138
154
  # for permissions, see http://developers.facebook.com/docs/authentication/permissions
139
155
  permissions = options[:permissions]
@@ -156,18 +172,68 @@ module Koala
156
172
  raise ArgumentError, "url_for_access_token must get a callback either from the OAuth object or in the parameters!" unless callback
157
173
  "https://#{GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@app_secret}&code=#{code}"
158
174
  end
159
-
160
- def get_access_token(code)
175
+
176
+ def get_access_token_info(code)
161
177
  # convenience method to get a parsed token from Facebook for a given code
162
178
  # should this require an OAuth callback URL?
163
179
  get_token_from_server(:code => code, :redirect_uri => @oauth_callback_url)
164
180
  end
165
181
 
166
- def get_app_access_token
182
+ def get_access_token(code)
183
+ info = get_access_token_info(code)
184
+ # upstream methods will throw errors if needed
185
+ string = info["access_token"]
186
+
187
+ overload_as_hash(string, info)
188
+ end
189
+
190
+ def get_app_access_token_info
167
191
  # convenience method to get a the application's sessionless access token
168
192
  get_token_from_server({:type => 'client_cred'}, true)
169
193
  end
170
194
 
195
+ def get_app_access_token
196
+ info = get_app_access_token_info
197
+ string = info["access_token"]
198
+
199
+ overload_as_hash(string, info)
200
+ end
201
+
202
+ # from session keys
203
+ def get_token_info_from_session_keys(sessions)
204
+ # fetch the OAuth tokens from Facebook
205
+ response = fetch_token_string({
206
+ :type => 'client_cred',
207
+ :sessions => sessions.join(",")
208
+ }, true, "exchange_sessions")
209
+
210
+ # get_token_from_session_key should return an empty body if an empty string or nil is provided
211
+ # if invalid tokens are provided, it returns an array of nulls, which is a valid result
212
+ if response == ""
213
+ raise APIError.new("ArgumentError", "get_token_from_session_key received an error (empty response body) for sessions #{sessions.inspect}!")
214
+ end
215
+
216
+ JSON.parse(response)
217
+ end
218
+
219
+ def get_tokens_from_session_keys(sessions)
220
+ # get the original hash results
221
+ results = get_token_info_from_session_keys(sessions)
222
+ # now recollect them as backward-compatible strings
223
+ # for easier use
224
+ results.collect do |r|
225
+ string = r["access_token"]
226
+
227
+ overload_as_hash string, r
228
+ end
229
+ end
230
+
231
+ def get_token_from_session_key(session)
232
+ # convenience method for a single key
233
+ # gets the overlaoded strings automatically
234
+ get_tokens_from_session_keys([session])[0]
235
+ end
236
+
171
237
  protected
172
238
 
173
239
  def get_token_from_server(args, post = false)
@@ -189,12 +255,29 @@ module Koala
189
255
  components
190
256
  end
191
257
 
192
- def fetch_token_string(args, post = false)
193
- Koala.make_request("oauth/access_token", {
258
+ def fetch_token_string(args, post = false, endpoint = "access_token")
259
+ Koala.make_request("oauth/#{endpoint}", {
194
260
  :client_id => @app_id,
195
261
  :client_secret => @app_secret
196
262
  }.merge!(args), post ? "post" : "get").body
197
263
  end
264
+
265
+ # overload the object to be accessible as a hash
266
+ # used to make get_*_token methods backward compatible
267
+ # icky ruby magic, but it's _really_ cool we can do this
268
+ def overload_as_hash(obj, hash)
269
+ command = <<-EOS
270
+ def [](index)
271
+ puts "WARNING: get_app_access_token now provides the access token as a string; use get_app_access_token_info if you want the hash with expirations. Otherwise you no longer need to call [] to get the token itself."
272
+ hash = #{hash.inspect}
273
+ hash[index]
274
+ end
275
+ EOS
276
+
277
+ (class << obj; self; end).class_eval command
278
+
279
+ obj
280
+ end
198
281
  end
199
282
  end
200
283
 
data/readme.md CHANGED
@@ -34,7 +34,7 @@ We reserve the right to expand the built-in REST API coverage to additional conv
34
34
  OAuth
35
35
  -----
36
36
  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:
37
- @oauth = Koala::Facebook::OAuth.new(app_id, code, callback_url)
37
+ @oauth = Koala::Facebook::OAuth.new(app_id, code, callback_url)
38
38
 
39
39
  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:
40
40
  @oauth.get_user_from_cookie(cookies)
@@ -50,6 +50,9 @@ You can also get your application's own access token, which can be used without
50
50
 
51
51
  That's it! It's pretty simple once you get the hang of it. If you're new to OAuth, though, check out the wiki and the OAuth Playground example site (see below).
52
52
 
53
+ *Exchanging session keys:* Stuck building tab applications on Facebook? Wishing you had an OAuth token so you could use the Graph API? You're in luck! Koala now allows you to exchange session keys for OAuth access tokens:
54
+ @oauth.get_token_from_session_key(session_key)
55
+ @oauth.get_tokens_from_session_keys(array_of_session_keys)
53
56
 
54
57
  Real-time Updates
55
58
  -----
@@ -5,14 +5,19 @@
5
5
 
6
6
  # You must supply this value yourself to test the GraphAPI class.
7
7
  # Your OAuth token should have publish_stream and read_stream permissions.
8
- oauth_token: 119908831367602|2.6WkxQTbQPGFCyLblPYdsMg__.3600.1274979600-2905623|8YPVs-jBmpWC6y10pMCWzMRFrdk.
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.6WkxQTbQPGFCyLblPYdsMg__.3600.1274979600-2905623|zHzbqwoONeqNxOXX7z9LZlpEGdc.
15
-
14
+ code:
15
+ # easiest way to get session keys: use multiple test accounts with the Javascript login at http://oauth.twoalex.com
16
+ session_key:
17
+ multiple_session_keys:
18
+ -
19
+ -
20
+
16
21
  # These values will work out of the box
17
22
  app_id: 119908831367602
18
23
  secret: e45e55a333eec232d4206d2703de1307
@@ -29,9 +29,45 @@ class ApiBaseTests < Test::Unit::TestCase
29
29
  service.api('anything')
30
30
  end
31
31
 
32
- it "should properly handle the http_component parameter"
32
+ it "should get the attribute of a Koala::Response given by the http_component parameter" do
33
+ http_component = :method_name
34
+
35
+ response = mock('Mock KoalaResponse', :body => '', :status => 200)
36
+ response.should_receive(http_component).and_return('')
37
+
38
+ Koala.stub(:make_request).and_return(response)
39
+
40
+ @service.api('anything', 'get', {}, :http_component => http_component)
41
+ end
33
42
 
34
- it "should execute a block to test for errors if passed one"
43
+ it "should return the body of the request as JSON if no http_component is given" do
44
+ response = stub('response', :body => 'body', :status => 200)
45
+ Koala.stub(:make_request).and_return(response)
46
+
47
+ json_body = mock('JSON body')
48
+ JSON.stub(:parse).and_return([json_body])
49
+
50
+ @service.api('anything').should == json_body
51
+ end
52
+
53
+ it "should execute a block with the response body if passed one" do
54
+ body = '{}'
55
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, body, {}))
56
+
57
+ yield_test = mock('Yield Tester')
58
+ yield_test.should_receive(:pass)
59
+
60
+ @service.api('anything') do |arg|
61
+ yield_test.pass
62
+ arg.should == JSON.parse(body)
63
+ end
64
+ end
65
+
66
+ it "should raise an API error if the HTTP response code is greater than or equal to 500" do
67
+ Koala.stub(:make_request).and_return(Koala::Response.new(500, 'response body', {}))
68
+
69
+ lambda { @service.api('anything') }.should raise_exception(Koala::Facebook::APIError)
70
+ end
35
71
 
36
72
  it "should handle rogue true/false as responses" do
37
73
  Koala.should_receive(:make_request).and_return(Koala::Response.new(200, 'true', {}))
@@ -41,4 +77,35 @@ class ApiBaseTests < Test::Unit::TestCase
41
77
  @service.api('anything').should be_false
42
78
  end
43
79
  end
80
+ end
81
+
82
+ shared_examples_for "methods that return overloaded strings" do
83
+ before :each do
84
+ @key ||= "access_token"
85
+ end
86
+
87
+ it "should be overloaded to be backward compatible" do
88
+ @result.respond_to?(:[]).should be_true
89
+ end
90
+
91
+ it "should allow hash access to the access token info" do
92
+ @result[@key].should == @result
93
+ end
94
+
95
+ it "should output a deprecation warning when the result is used as a hash" do
96
+ out = nil
97
+
98
+ begin
99
+ # we want to capture the deprecation warning as well as the output
100
+ # credit to http://thinkingdigitally.com/archive/capturing-output-from-puts-in-ruby/ for the technique
101
+ out = StringIO.new
102
+ $stdout = out
103
+ @result[@key]
104
+ ensure
105
+ $stdout = STDOUT
106
+ end
107
+
108
+ # ensure we got a warning
109
+ out.should_not be_nil
110
+ end
44
111
  end
@@ -34,6 +34,10 @@ shared_examples_for "Koala GraphAPI without an access token" do
34
34
  @api.get_picture("chris.baclig").should =~ /http\:\/\//
35
35
  end
36
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
+
37
41
  it "should be able to access connections from public Pages" do
38
42
  result = @api.get_connections("contextoptional", "likes")
39
43
  result.should be_a(Array)
@@ -31,6 +31,10 @@ it "should get public data about a user" do
31
31
  @api.get_picture("chris.baclig").should =~ /http\:\/\//
32
32
  end
33
33
 
34
+ it "should be able to access a user's picture, given a picture type" do
35
+ @api.get_picture("chris.baclig", {:type => 'large'}).should =~ /^http\:\/\//
36
+ end
37
+
34
38
  it "should be able to access connections from users" do
35
39
  result = @api.get_connections("lukeshepard", "likes")
36
40
  result.length.should > 0