koala 1.2.0 → 1.3.0
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.
- data/.gitignore +3 -1
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/.yardopts +3 -0
- data/CHANGELOG +43 -0
- data/Gemfile +14 -0
- data/Guardfile +6 -0
- data/koala.gemspec +4 -4
- data/lib/koala/api/batch_operation.rb +83 -0
- data/lib/koala/api/graph_api.rb +476 -0
- data/lib/koala/{graph_batch_api.rb → api/graph_batch_api.rb} +22 -17
- data/lib/koala/api/graph_collection.rb +107 -0
- data/lib/koala/api/legacy.rb +26 -0
- data/lib/koala/{rest_api.rb → api/rest_api.rb} +36 -10
- data/lib/koala/api.rb +93 -0
- data/lib/koala/http_service/multipart_request.rb +41 -0
- data/lib/koala/http_service/response.rb +18 -0
- data/lib/koala/http_service/uploadable_io.rb +187 -0
- data/lib/koala/http_service.rb +73 -23
- data/lib/koala/oauth.rb +173 -36
- data/lib/koala/realtime_updates.rb +89 -51
- data/lib/koala/test_users.rb +122 -32
- data/lib/koala/utils.rb +11 -4
- data/lib/koala/version.rb +1 -1
- data/lib/koala.rb +16 -95
- data/readme.md +30 -13
- data/spec/cases/api_spec.rb +28 -21
- data/spec/cases/error_spec.rb +10 -0
- data/spec/cases/graph_api_batch_spec.rb +100 -58
- data/spec/cases/graph_collection_spec.rb +23 -7
- data/spec/cases/http_service_spec.rb +14 -34
- data/spec/cases/koala_spec.rb +22 -4
- data/spec/cases/legacy_spec.rb +115 -0
- data/spec/cases/multipart_request_spec.rb +66 -0
- data/spec/cases/oauth_spec.rb +232 -108
- data/spec/cases/realtime_updates_spec.rb +154 -47
- data/spec/cases/test_users_spec.rb +276 -217
- data/spec/cases/uploadable_io_spec.rb +1 -1
- data/spec/cases/utils_spec.rb +29 -5
- data/spec/fixtures/mock_facebook_responses.yml +50 -26
- data/spec/spec_helper.rb +3 -0
- data/spec/support/custom_matchers.rb +28 -0
- data/spec/support/graph_api_shared_examples.rb +274 -70
- data/spec/support/koala_test.rb +27 -16
- data/spec/support/mock_http_service.rb +2 -2
- data/spec/support/rest_api_shared_examples.rb +46 -162
- metadata +33 -25
- data/lib/koala/batch_operation.rb +0 -74
- data/lib/koala/graph_api.rb +0 -270
- data/lib/koala/graph_collection.rb +0 -59
- data/lib/koala/uploadable_io.rb +0 -181
- data/spec/cases/graph_and_rest_api_spec.rb +0 -22
- data/spec/cases/graph_api_spec.rb +0 -22
- data/spec/cases/rest_api_spec.rb +0 -41
data/lib/koala/oauth.rb
CHANGED
|
@@ -1,65 +1,165 @@
|
|
|
1
|
+
# OpenSSL and Base64 are required to support signed_request
|
|
2
|
+
require 'openssl'
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
1
5
|
module Koala
|
|
2
6
|
module Facebook
|
|
7
|
+
|
|
8
|
+
DIALOG_HOST = "www.facebook.com"
|
|
9
|
+
|
|
3
10
|
class OAuth
|
|
4
11
|
attr_reader :app_id, :app_secret, :oauth_callback_url
|
|
12
|
+
|
|
13
|
+
# Creates a new OAuth client.
|
|
14
|
+
#
|
|
15
|
+
# @param app_id [String, Integer] a Facebook application ID
|
|
16
|
+
# @param app_secret a Facebook application secret
|
|
17
|
+
# @param oauth_callback_url the URL in your app to which users authenticating with OAuth will be sent
|
|
5
18
|
def initialize(app_id, app_secret, oauth_callback_url = nil)
|
|
6
19
|
@app_id = app_id
|
|
7
20
|
@app_secret = app_secret
|
|
8
21
|
@oauth_callback_url = oauth_callback_url
|
|
9
22
|
end
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
|
|
24
|
+
# Parses the cookie set Facebook's JavaScript SDK.
|
|
25
|
+
#
|
|
26
|
+
# @note in parsing Facebook's new signed cookie format this method has to make a request to Facebook.
|
|
27
|
+
# We recommend storing authenticated user info in your Rails session (or equivalent) and only
|
|
28
|
+
# calling this when needed.
|
|
29
|
+
#
|
|
30
|
+
# @param cookie_hash a set of cookies that includes the Facebook cookie.
|
|
31
|
+
# You can pass Rack/Rails/Sinatra's cookie hash directly to this method.
|
|
32
|
+
#
|
|
33
|
+
# @return the authenticated user's information as a hash, or nil.
|
|
34
|
+
def get_user_info_from_cookies(cookie_hash)
|
|
20
35
|
if signed_cookie = cookie_hash["fbsr_#{@app_id}"]
|
|
21
36
|
parse_signed_cookie(signed_cookie)
|
|
22
37
|
elsif unsigned_cookie = cookie_hash["fbs_#{@app_id}"]
|
|
23
38
|
parse_unsigned_cookie(unsigned_cookie)
|
|
24
39
|
end
|
|
25
40
|
end
|
|
26
|
-
alias_method :
|
|
41
|
+
alias_method :get_user_info_from_cookie, :get_user_info_from_cookies
|
|
27
42
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
# Parses the cookie set Facebook's JavaScript SDK and returns only the user ID.
|
|
44
|
+
#
|
|
45
|
+
# @note (see #get_user_info_from_cookie)
|
|
46
|
+
#
|
|
47
|
+
# @param (see #get_user_info_from_cookie)
|
|
48
|
+
#
|
|
49
|
+
# @return the authenticated user's Facebook ID, or nil.
|
|
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"]
|
|
31
58
|
end
|
|
32
59
|
end
|
|
33
|
-
alias_method :
|
|
60
|
+
alias_method :get_user_from_cookie, :get_user_from_cookies
|
|
34
61
|
|
|
35
62
|
# URLs
|
|
36
|
-
|
|
63
|
+
|
|
64
|
+
# Builds an OAuth URL, where users will be prompted to log in and for any desired permissions.
|
|
65
|
+
# When the users log in, you receive a callback with their
|
|
66
|
+
# See http://developers.facebook.com/docs/authentication/.
|
|
67
|
+
#
|
|
68
|
+
# @see #url_for_access_token
|
|
69
|
+
#
|
|
70
|
+
# @note The server-side authentication and dialog methods should only be used
|
|
71
|
+
# if your application can't use the Facebook Javascript SDK,
|
|
72
|
+
# which provides a much better user experience.
|
|
73
|
+
# See http://developers.facebook.com/docs/reference/javascript/.
|
|
74
|
+
#
|
|
75
|
+
# @param options any query values to add to the URL, as well as any special/required values listed below.
|
|
76
|
+
# @option options permissions an array or comma-separated string of desired permissions
|
|
77
|
+
#
|
|
78
|
+
# @raise ArgumentError if no OAuth callback was specified in OAuth#new or in options as :redirect_uri
|
|
79
|
+
#
|
|
80
|
+
# @return an OAuth URL you can send your users to
|
|
37
81
|
def url_for_oauth_code(options = {})
|
|
38
82
|
# for permissions, see http://developers.facebook.com/docs/authentication/permissions
|
|
39
|
-
permissions = options
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
raise ArgumentError, "url_for_oauth_code must get a callback either from the OAuth object or in the options!" unless callback
|
|
45
|
-
|
|
83
|
+
if permissions = options.delete(:permissions)
|
|
84
|
+
options[:scope] = permissions.is_a?(Array) ? permissions.join(",") : permissions
|
|
85
|
+
end
|
|
86
|
+
url_options = {:client_id => @app_id}.merge(options)
|
|
87
|
+
|
|
46
88
|
# Creates the URL for oauth authorization for a given callback and optional set of permissions
|
|
47
|
-
"https://#{GRAPH_SERVER}/oauth/authorize
|
|
89
|
+
build_url("https://#{GRAPH_SERVER}/oauth/authorize", true, url_options)
|
|
48
90
|
end
|
|
49
91
|
|
|
92
|
+
# Once you receive an OAuth code, you need to redeem it from Facebook using an appropriate URL.
|
|
93
|
+
# (This is done by your server behind the scenes.)
|
|
94
|
+
# See http://developers.facebook.com/docs/authentication/.
|
|
95
|
+
#
|
|
96
|
+
# @see #url_for_oauth_code
|
|
97
|
+
#
|
|
98
|
+
# @note (see #url_for_oauth_code)
|
|
99
|
+
#
|
|
100
|
+
# @param code an OAuth code received from Facebook
|
|
101
|
+
# @param options any additional query parameters to add to the URL
|
|
102
|
+
#
|
|
103
|
+
# @raise (see #url_for_oauth_code)
|
|
104
|
+
#
|
|
105
|
+
# @return an URL your server can query for the user's access token
|
|
50
106
|
def url_for_access_token(code, options = {})
|
|
51
107
|
# Creates the URL for the token corresponding to a given code generated by Facebook
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
108
|
+
url_options = {
|
|
109
|
+
:client_id => @app_id,
|
|
110
|
+
:code => code,
|
|
111
|
+
:client_secret => @app_secret
|
|
112
|
+
}.merge(options)
|
|
113
|
+
build_url("https://#{GRAPH_SERVER}/oauth/access_token", true, url_options)
|
|
55
114
|
end
|
|
56
115
|
|
|
116
|
+
# Builds a URL for a given dialog (feed, friends, OAuth, pay, send, etc.)
|
|
117
|
+
# See http://developers.facebook.com/docs/reference/dialogs/.
|
|
118
|
+
#
|
|
119
|
+
# @note (see #url_for_oauth_code)
|
|
120
|
+
#
|
|
121
|
+
# @param dialog_type the kind of Facebook dialog you want to show
|
|
122
|
+
# @param options any additional query parameters to add to the URL
|
|
123
|
+
#
|
|
124
|
+
# @return an URL your server can query for the user's access token
|
|
125
|
+
def url_for_dialog(dialog_type, options = {})
|
|
126
|
+
# some endpoints require app_id, some client_id, supply both doesn't seem to hurt
|
|
127
|
+
url_options = {:app_id => @app_id, :client_id => @app_id}.merge(options)
|
|
128
|
+
build_url("http://#{DIALOG_HOST}/dialog/#{dialog_type}", true, url_options)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# access tokens
|
|
132
|
+
|
|
133
|
+
# Fetches an access token, token expiration, and other info from Facebook.
|
|
134
|
+
# Useful when you've received an OAuth code using the server-side authentication process.
|
|
135
|
+
# @see url_for_oauth_code
|
|
136
|
+
#
|
|
137
|
+
# @note (see #url_for_oauth_code)
|
|
138
|
+
#
|
|
139
|
+
# @param code (see #url_for_access_token)
|
|
140
|
+
# @param options any additional parameters to send to Facebook when redeeming the token
|
|
141
|
+
#
|
|
142
|
+
# @raise Koala::Facebook::APIError if Facebook returns an error response
|
|
143
|
+
#
|
|
144
|
+
# @return a hash of the access token info returned by Facebook (token, expiration, etc.)
|
|
57
145
|
def get_access_token_info(code, options = {})
|
|
58
146
|
# convenience method to get a parsed token from Facebook for a given code
|
|
59
147
|
# should this require an OAuth callback URL?
|
|
60
148
|
get_token_from_server({:code => code, :redirect_uri => options[:redirect_uri] || @oauth_callback_url}, false, options)
|
|
61
149
|
end
|
|
62
150
|
|
|
151
|
+
|
|
152
|
+
# Fetches the access token (ignoring expiration and other info) from Facebook.
|
|
153
|
+
# Useful when you've received an OAuth code using the server-side authentication process.
|
|
154
|
+
# @see get_access_token_info
|
|
155
|
+
#
|
|
156
|
+
# @note (see #url_for_oauth_code)
|
|
157
|
+
#
|
|
158
|
+
# @param (see #get_access_token_info)
|
|
159
|
+
#
|
|
160
|
+
# @raise (see #get_access_token_info)
|
|
161
|
+
#
|
|
162
|
+
# @return the access token
|
|
63
163
|
def get_access_token(code, options = {})
|
|
64
164
|
# upstream methods will throw errors if needed
|
|
65
165
|
if info = get_access_token_info(code, options)
|
|
@@ -67,24 +167,40 @@ module Koala
|
|
|
67
167
|
end
|
|
68
168
|
end
|
|
69
169
|
|
|
170
|
+
# Fetches the application's access token, along with any other information provided by Facebook.
|
|
171
|
+
# See http://developers.facebook.com/docs/authentication/ (search for App Login).
|
|
172
|
+
#
|
|
173
|
+
# @param options any additional parameters to send to Facebook when redeeming the token
|
|
174
|
+
#
|
|
175
|
+
# @return the application access token and other information (expiration, etc.)
|
|
70
176
|
def get_app_access_token_info(options = {})
|
|
71
177
|
# convenience method to get a the application's sessionless access token
|
|
72
178
|
get_token_from_server({:type => 'client_cred'}, true, options)
|
|
73
179
|
end
|
|
74
180
|
|
|
181
|
+
# Fetches the application's access token (ignoring expiration and other info).
|
|
182
|
+
# @see get_app_access_token_info
|
|
183
|
+
#
|
|
184
|
+
# @param (see #get_app_access_token_info)
|
|
185
|
+
#
|
|
186
|
+
# @return the application access token
|
|
75
187
|
def get_app_access_token(options = {})
|
|
76
188
|
if info = get_app_access_token_info(options)
|
|
77
189
|
string = info["access_token"]
|
|
78
190
|
end
|
|
79
191
|
end
|
|
80
192
|
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
193
|
+
# Parses a signed request string provided by Facebook to canvas apps or in a secure cookie.
|
|
194
|
+
#
|
|
195
|
+
# @param input the signed request from Facebook
|
|
196
|
+
#
|
|
197
|
+
# @raise RuntimeError if the signature is incomplete, invalid, or using an unsupported algorithm
|
|
198
|
+
#
|
|
199
|
+
# @return a hash of the validated request information
|
|
86
200
|
def parse_signed_request(input)
|
|
87
201
|
encoded_sig, encoded_envelope = input.split('.', 2)
|
|
202
|
+
raise 'SignedRequest: Invalid (incomplete) signature data' unless encoded_sig && encoded_envelope
|
|
203
|
+
|
|
88
204
|
signature = base64_url_decode(encoded_sig).unpack("H*").first
|
|
89
205
|
envelope = MultiJson.decode(base64_url_decode(encoded_envelope))
|
|
90
206
|
|
|
@@ -94,11 +210,15 @@ module Koala
|
|
|
94
210
|
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @app_secret, encoded_envelope)
|
|
95
211
|
raise 'SignedRequest: Invalid signature' if (signature != hmac)
|
|
96
212
|
|
|
97
|
-
|
|
213
|
+
envelope
|
|
98
214
|
end
|
|
99
215
|
|
|
100
|
-
#
|
|
216
|
+
# Old session key code
|
|
217
|
+
|
|
218
|
+
# @deprecated Facebook no longer provides session keys.
|
|
101
219
|
def get_token_info_from_session_keys(sessions, options = {})
|
|
220
|
+
Koala::Utils.deprecate("Facebook no longer provides session keys. The relevant OAuth methods will be removed in the next release.")
|
|
221
|
+
|
|
102
222
|
# fetch the OAuth tokens from Facebook
|
|
103
223
|
response = fetch_token_string({
|
|
104
224
|
:type => 'client_cred',
|
|
@@ -116,6 +236,7 @@ module Koala
|
|
|
116
236
|
MultiJson.decode(response)
|
|
117
237
|
end
|
|
118
238
|
|
|
239
|
+
# @deprecated (see #get_token_info_from_session_keys)
|
|
119
240
|
def get_tokens_from_session_keys(sessions, options = {})
|
|
120
241
|
# get the original hash results
|
|
121
242
|
results = get_token_info_from_session_keys(sessions, options)
|
|
@@ -123,6 +244,7 @@ module Koala
|
|
|
123
244
|
results.collect { |r| r ? r["access_token"] : nil }
|
|
124
245
|
end
|
|
125
246
|
|
|
247
|
+
# @deprecated (see #get_token_info_from_session_keys)
|
|
126
248
|
def get_token_from_session_key(session, options = {})
|
|
127
249
|
# convenience method for a single key
|
|
128
250
|
# gets the overlaoded strings automatically
|
|
@@ -166,8 +288,15 @@ module Koala
|
|
|
166
288
|
|
|
167
289
|
def parse_signed_cookie(fb_cookie)
|
|
168
290
|
components = parse_signed_request(fb_cookie)
|
|
169
|
-
if
|
|
170
|
-
|
|
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
|
|
171
300
|
else
|
|
172
301
|
nil
|
|
173
302
|
end
|
|
@@ -186,6 +315,14 @@ module Koala
|
|
|
186
315
|
str += '=' * (4 - str.length.modulo(4))
|
|
187
316
|
Base64.decode64(str.tr('-_', '+/'))
|
|
188
317
|
end
|
|
318
|
+
|
|
319
|
+
def build_url(base, require_redirect_uri = false, url_options = {})
|
|
320
|
+
if require_redirect_uri && !(url_options[:redirect_uri] ||= url_options.delete(:callback) || @oauth_callback_url)
|
|
321
|
+
raise ArgumentError, "url_for_dialog must get a callback either from the OAuth object or in the parameters!"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
"#{base}?#{Koala::HTTPService.encode_params(url_options)}"
|
|
325
|
+
end
|
|
189
326
|
end
|
|
190
327
|
end
|
|
191
328
|
end
|
|
@@ -1,36 +1,27 @@
|
|
|
1
1
|
module Koala
|
|
2
2
|
module Facebook
|
|
3
|
-
|
|
4
|
-
#
|
|
3
|
+
class RealtimeUpdates
|
|
4
|
+
# Manage realtime callbacks for changes to users' information.
|
|
5
|
+
# See http://developers.facebook.com/docs/reference/api/realtime.
|
|
6
|
+
#
|
|
7
|
+
# @note: to subscribe to real-time updates, you must have an application access token
|
|
8
|
+
# or provide the app secret when initializing your RealtimeUpdates object.
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# parses the challenge params and makes sure the call is legitimate
|
|
12
|
-
# returns the challenge string to be sent back to facebook if true
|
|
13
|
-
# returns false otherwise
|
|
14
|
-
# this is a class method, since you don't need to know anything about the app
|
|
15
|
-
# saves a potential trip fetching the app access token
|
|
16
|
-
def self.meet_challenge(params, verify_token = nil, &verification_block)
|
|
17
|
-
if params["hub.mode"] == "subscribe" &&
|
|
18
|
-
# you can make sure this is legitimate through two ways
|
|
19
|
-
# if your store the token across the calls, you can pass in the token value
|
|
20
|
-
# and we'll make sure it matches
|
|
21
|
-
(verify_token && params["hub.verify_token"] == verify_token) ||
|
|
22
|
-
# alternately, if you sent a specially-constructed value (such as a hash of various secret values)
|
|
23
|
-
# you can pass in a block, which we'll call with the verify_token sent by Facebook
|
|
24
|
-
# if it's legit, return anything that evaluates to true; otherwise, return nil or false
|
|
25
|
-
(verification_block && yield(params["hub.verify_token"]))
|
|
26
|
-
params["hub.challenge"]
|
|
27
|
-
else
|
|
28
|
-
false
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
10
|
+
# The application API interface used to communicate with Facebook.
|
|
11
|
+
# @return [Koala::Facebook::API]
|
|
12
|
+
attr_reader :api
|
|
13
|
+
attr_reader :app_id, :app_access_token, :secret
|
|
33
14
|
|
|
15
|
+
# Create a new RealtimeUpdates instance.
|
|
16
|
+
# If you don't have your app's access token, provide the app's secret and
|
|
17
|
+
# Koala will make a request to Facebook for the appropriate token.
|
|
18
|
+
#
|
|
19
|
+
# @param options initialization options.
|
|
20
|
+
# @option options :app_id the application's ID.
|
|
21
|
+
# @option options :app_access_token an application access token, if known.
|
|
22
|
+
# @option options :secret the application's secret.
|
|
23
|
+
#
|
|
24
|
+
# @raise ArgumentError if the application ID and one of the app access token or the secret are not provided.
|
|
34
25
|
def initialize(options = {})
|
|
35
26
|
@app_id = options[:app_id]
|
|
36
27
|
@app_access_token = options[:app_access_token]
|
|
@@ -45,45 +36,92 @@ module Koala
|
|
|
45
36
|
@app_access_token = oauth.get_app_access_token
|
|
46
37
|
end
|
|
47
38
|
|
|
48
|
-
@
|
|
39
|
+
@api = API.new(@app_access_token)
|
|
49
40
|
end
|
|
50
41
|
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
|
|
42
|
+
# Subscribe to realtime updates for certain fields on a given object (user, page, etc.).
|
|
43
|
+
# See {http://developers.facebook.com/docs/reference/api/realtime the realtime updates documentation}
|
|
44
|
+
# for more information on what objects and fields you can register for.
|
|
45
|
+
#
|
|
46
|
+
# @note Your callback_url must be set up to handle the verification request or the subscription will not be set up.
|
|
47
|
+
#
|
|
48
|
+
# @param object a Facebook ID (name or number)
|
|
49
|
+
# @param fields the fields you want your app to be updated about
|
|
50
|
+
# @param callback_url the URL Facebook should ping when an update is available
|
|
51
|
+
# @param verify_token a token included in the verification request, allowing you to ensure the call is genuine
|
|
52
|
+
# (see the docs for more information)
|
|
53
|
+
# @param options (see Koala::HTTPService.make_request)
|
|
54
|
+
#
|
|
55
|
+
# @return true if successful, false (or an APIError) otherwise.
|
|
56
|
+
def subscribe(object, fields, callback_url, verify_token, options = {})
|
|
55
57
|
args = {
|
|
56
58
|
:object => object,
|
|
57
59
|
:fields => fields,
|
|
58
60
|
:callback_url => callback_url,
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
+
}.merge(verify_token ? {:verify_token => verify_token} : {})
|
|
61
62
|
# a subscription is a success if Facebook returns a 200 (after hitting your server for verification)
|
|
62
|
-
@
|
|
63
|
+
@api.graph_call(subscription_path, args, 'post', options.merge(:http_component => :status)) == 200
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
# Unsubscribe from updates for a particular object or from updates.
|
|
67
|
+
#
|
|
68
|
+
# @param object the object whose subscriptions to delete.
|
|
69
|
+
# If no object is provided, all subscriptions will be removed.
|
|
70
|
+
# @param options (see Koala::HTTPService.make_request)
|
|
71
|
+
#
|
|
72
|
+
# @return true if the unsubscription is successful, false (or an APIError) otherwise.
|
|
73
|
+
def unsubscribe(object = nil, options = {})
|
|
74
|
+
@api.graph_call(subscription_path, object ? {:object => object} : {}, "delete", options.merge(:http_component => :status)) == 200
|
|
71
75
|
end
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
# List all active subscriptions for this application.
|
|
78
|
+
#
|
|
79
|
+
# @param options (see Koala::HTTPService.make_request)
|
|
80
|
+
#
|
|
81
|
+
# @return [Array] a list of active subscriptions
|
|
82
|
+
def list_subscriptions(options = {})
|
|
83
|
+
@api.graph_call(subscription_path, {}, "get", options)
|
|
75
84
|
end
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
# As a security measure (to prevent DDoS attacks), Facebook sends a verification request to your server
|
|
87
|
+
# after you request a subscription.
|
|
88
|
+
# This method parses the challenge params and makes sure the call is legitimate.
|
|
89
|
+
#
|
|
90
|
+
# @param params the request parameters sent by Facebook. (You can pass in a Rails params hash.)
|
|
91
|
+
# @param verify_token the verify token sent in the {#subscribe subscription request}, if you provided one
|
|
92
|
+
#
|
|
93
|
+
# @yield verify_token if you need to compute the verification token
|
|
94
|
+
# (for instance, if your callback URL includes a record ID, which you look up
|
|
95
|
+
# and use to calculate a hash), you can pass meet_challenge a block, which
|
|
96
|
+
# will receive the verify_token received back from Facebook.
|
|
97
|
+
#
|
|
98
|
+
# @return the challenge string to be sent back to Facebook, or false if the request is invalid.
|
|
99
|
+
def self.meet_challenge(params, verify_token = nil, &verification_block)
|
|
100
|
+
if params["hub.mode"] == "subscribe" &&
|
|
101
|
+
# you can make sure this is legitimate through two ways
|
|
102
|
+
# if your store the token across the calls, you can pass in the token value
|
|
103
|
+
# and we'll make sure it matches
|
|
104
|
+
(verify_token && params["hub.verify_token"] == verify_token) ||
|
|
105
|
+
# alternately, if you sent a specially-constructed value (such as a hash of various secret values)
|
|
106
|
+
# you can pass in a block, which we'll call with the verify_token sent by Facebook
|
|
107
|
+
# if it's legit, return anything that evaluates to true; otherwise, return nil or false
|
|
108
|
+
(verification_block && yield(params["hub.verify_token"]))
|
|
109
|
+
params["hub.challenge"]
|
|
110
|
+
else
|
|
111
|
+
false
|
|
112
|
+
end
|
|
80
113
|
end
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
114
|
+
|
|
115
|
+
# The Facebook subscription management URL for your application.
|
|
84
116
|
def subscription_path
|
|
85
117
|
@subscription_path ||= "#{@app_id}/subscriptions"
|
|
86
118
|
end
|
|
119
|
+
|
|
120
|
+
# @private
|
|
121
|
+
def graph_api
|
|
122
|
+
Koala::Utils.deprecate("the TestUsers.graph_api accessor is deprecated and will be removed in a future version; please use .api instead.")
|
|
123
|
+
@api
|
|
124
|
+
end
|
|
87
125
|
end
|
|
88
126
|
end
|
|
89
127
|
end
|