koala 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -0
- data/Manifest +15 -0
- data/Rakefile +1 -1
- data/examples/oauth_playground/Capfile +2 -0
- data/examples/oauth_playground/LICENSE +22 -0
- data/examples/oauth_playground/Rakefile +4 -0
- data/examples/oauth_playground/config.ru +27 -0
- data/examples/oauth_playground/config/deploy.rb +39 -0
- data/examples/oauth_playground/config/facebook.yml +13 -0
- data/examples/oauth_playground/lib/load_facebook.rb +3 -0
- data/examples/oauth_playground/lib/oauth_playground.rb +187 -0
- data/examples/oauth_playground/readme.md +8 -0
- data/examples/oauth_playground/spec/oauth_playground_spec.rb +35 -0
- data/examples/oauth_playground/spec/spec_helper.rb +36 -0
- data/examples/oauth_playground/tmp/restart.txt +0 -0
- data/examples/oauth_playground/views/index.erb +206 -0
- data/examples/oauth_playground/views/layout.erb +39 -0
- data/koala.gemspec +3 -3
- data/lib/koala.rb +36 -6
- data/lib/koala/graph_api.rb +63 -2
- data/lib/koala/http_services.rb +3 -2
- data/readme.md +37 -12
- data/spec/facebook_data.yml +17 -5
- data/spec/koala/api_base_tests.rb +15 -0
- data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +13 -4
- data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +14 -3
- data/spec/koala/graph_api/graph_collection_tests.rb +104 -0
- data/spec/koala/net_http_service_tests.rb +1 -1
- data/spec/koala/oauth/oauth_tests.rb +245 -113
- data/spec/koala_spec_helper.rb +1 -0
- data/spec/mock_facebook_responses.yml +39 -26
- data/spec/mock_http_service.rb +1 -1
- metadata +18 -3
File without changes
|
@@ -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"> </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.
|
5
|
+
s.version = "0.9.0"
|
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-
|
9
|
+
s.date = %q{2010-09-30}
|
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
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", "init.rb", "koala.gemspec", "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"]
|
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", "koala.gemspec", "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/graph_api/graph_collection_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"]
|
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"]
|
data/lib/koala.rb
CHANGED
@@ -5,6 +5,9 @@ require 'digest/md5'
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'json'
|
7
7
|
|
8
|
+
# openssl is required to support signed_request
|
9
|
+
require 'openssl'
|
10
|
+
|
8
11
|
# include default http services
|
9
12
|
require 'koala/http_services'
|
10
13
|
|
@@ -49,9 +52,13 @@ module Koala
|
|
49
52
|
def api(path, args = {}, verb = "get", options = {}, &error_checking_block)
|
50
53
|
# Fetches the given path in the Graph API.
|
51
54
|
args["access_token"] = @access_token || @app_access_token if @access_token || @app_access_token
|
55
|
+
|
56
|
+
# add a leading /
|
57
|
+
path = "/#{path}" unless path =~ /^\//
|
58
|
+
|
52
59
|
# make the request via the provided service
|
53
60
|
result = Koala.make_request(path, args, verb, options)
|
54
|
-
|
61
|
+
|
55
62
|
# Check for any 500 errors before parsing the body
|
56
63
|
# since we're not guaranteed that the body is valid JSON
|
57
64
|
# in the case of a server error
|
@@ -189,6 +196,22 @@ module Koala
|
|
189
196
|
string = info["access_token"]
|
190
197
|
end
|
191
198
|
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
|
214
|
+
end
|
192
215
|
|
193
216
|
# from session keys
|
194
217
|
def get_token_info_from_session_keys(sessions)
|
@@ -198,9 +221,8 @@ module Koala
|
|
198
221
|
:sessions => sessions.join(",")
|
199
222
|
}, true, "exchange_sessions")
|
200
223
|
|
201
|
-
#
|
202
|
-
|
203
|
-
if response == ""
|
224
|
+
# Facebook returns an empty body in certain error conditions
|
225
|
+
if response == ""
|
204
226
|
raise APIError.new("ArgumentError", "get_token_from_session_key received an error (empty response body) for sessions #{sessions.inspect}!")
|
205
227
|
end
|
206
228
|
|
@@ -211,7 +233,7 @@ module Koala
|
|
211
233
|
# get the original hash results
|
212
234
|
results = get_token_info_from_session_keys(sessions)
|
213
235
|
# now recollect them as just the access tokens
|
214
|
-
results.collect { |r|
|
236
|
+
results.collect { |r| r ? r["access_token"] : nil }
|
215
237
|
end
|
216
238
|
|
217
239
|
def get_token_from_session_key(session)
|
@@ -242,11 +264,19 @@ module Koala
|
|
242
264
|
end
|
243
265
|
|
244
266
|
def fetch_token_string(args, post = false, endpoint = "access_token")
|
245
|
-
Koala.make_request("oauth/#{endpoint}", {
|
267
|
+
Koala.make_request("/oauth/#{endpoint}", {
|
246
268
|
:client_id => @app_id,
|
247
269
|
:client_secret => @app_secret
|
248
270
|
}.merge!(args), post ? "post" : "get").body
|
249
271
|
end
|
272
|
+
|
273
|
+
# 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]
|
279
|
+
end
|
250
280
|
end
|
251
281
|
end
|
252
282
|
|
data/lib/koala/graph_api.rb
CHANGED
@@ -2,6 +2,59 @@ module Koala
|
|
2
2
|
module Facebook
|
3
3
|
GRAPH_SERVER = "graph.facebook.com"
|
4
4
|
|
5
|
+
class GraphCollection < Array
|
6
|
+
#This class is a light wrapper for collections returned
|
7
|
+
#from the Graph API.
|
8
|
+
#
|
9
|
+
#It extends Array to allow direct access to the data colleciton
|
10
|
+
#which should allow it to drop in seamlessly.
|
11
|
+
#
|
12
|
+
#It also allows access to paging information and the
|
13
|
+
#ability to get the next/previous page in the collection
|
14
|
+
#by calling next_page or previous_page.
|
15
|
+
attr_reader :paging
|
16
|
+
attr_reader :api
|
17
|
+
|
18
|
+
def initialize(response, api)
|
19
|
+
super response["data"]
|
20
|
+
@paging = response["paging"]
|
21
|
+
@api = api
|
22
|
+
end
|
23
|
+
|
24
|
+
# defines methods for NEXT and PREVIOUS pages
|
25
|
+
%w{next previous}.each do |this|
|
26
|
+
|
27
|
+
# def next_page
|
28
|
+
# def previous_page
|
29
|
+
define_method "#{this.to_sym}_page" do
|
30
|
+
base, args = send("#{this}_page_params")
|
31
|
+
base ? @api.get_page([base, args]) : nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# def next_page_params
|
35
|
+
# def previous_page_params
|
36
|
+
define_method "#{this.to_sym}_page_params" do
|
37
|
+
return nil unless @paging and @paging[this]
|
38
|
+
parse_page_url(@paging[this])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_page_url(url)
|
43
|
+
match = url.match(/.com\/(.*)\?(.*)/)
|
44
|
+
base = match[1]
|
45
|
+
args = match[2]
|
46
|
+
params = CGI.parse(args)
|
47
|
+
new_params = {}
|
48
|
+
params.each_pair do |key,value|
|
49
|
+
new_params[key] = value.join ","
|
50
|
+
end
|
51
|
+
[base,new_params]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
5
58
|
module GraphAPIMethods
|
6
59
|
# A client for the Facebook Graph API.
|
7
60
|
#
|
@@ -41,11 +94,18 @@ module Koala
|
|
41
94
|
# we raise an exception.
|
42
95
|
graph_call("", args.merge("ids" => ids.join(",")))
|
43
96
|
end
|
97
|
+
|
98
|
+
def get_page(params)
|
99
|
+
result = graph_call(*params)
|
100
|
+
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
101
|
+
end
|
44
102
|
|
45
103
|
def get_connections(id, connection_name, args = {})
|
46
104
|
# Fetchs the connections for given object.
|
47
|
-
graph_call("#{id}/#{connection_name}", args)
|
105
|
+
result = graph_call("#{id}/#{connection_name}", args)
|
106
|
+
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
48
107
|
end
|
108
|
+
|
49
109
|
|
50
110
|
def get_picture(object, args = {})
|
51
111
|
result = graph_call("#{object}/picture", args, "get", :http_component => :headers)
|
@@ -113,7 +173,8 @@ module Koala
|
|
113
173
|
|
114
174
|
def search(search_terms, args = {})
|
115
175
|
# Searches for a given term
|
116
|
-
graph_call("search", args.merge({:q => search_terms}))
|
176
|
+
result = graph_call("search", args.merge({:q => search_terms}))
|
177
|
+
result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
|
117
178
|
end
|
118
179
|
|
119
180
|
def graph_call(*args)
|
data/lib/koala/http_services.rb
CHANGED
@@ -39,7 +39,7 @@ module Koala
|
|
39
39
|
|
40
40
|
protected
|
41
41
|
def self.encode_params(param_hash)
|
42
|
-
#
|
42
|
+
# unfortunately, we can't use to_query because that's Rails, not Ruby
|
43
43
|
# if no hash (e.g. no auth token) return empty string
|
44
44
|
((param_hash || {}).collect do |key_and_value|
|
45
45
|
key_and_value[1] = key_and_value[1].to_json if key_and_value[1].class != String
|
@@ -61,7 +61,8 @@ module Koala
|
|
61
61
|
# if the verb isn't get or post, send it as a post argument
|
62
62
|
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
63
63
|
server = options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER
|
64
|
-
|
64
|
+
typhoeus_options = {:params => args}.merge(options[:typhoeus_options] || {})
|
65
|
+
response = self.send(verb, "https://#{server}#{path}", typhoeus_options)
|
65
66
|
Koala::Response.new(response.code, response.body, response.headers_hash)
|
66
67
|
end
|
67
68
|
end # class_eval
|