koala 2.4.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/test.yml +32 -0
- data/Gemfile +5 -3
- data/ISSUE_TEMPLATE +25 -0
- data/PULL_REQUEST_TEMPLATE +11 -0
- data/changelog.md +161 -4
- data/code_of_conduct.md +64 -12
- data/koala.gemspec +5 -1
- data/lib/koala/api/batch_operation.rb +3 -6
- data/lib/koala/api/{graph_api.rb → graph_api_methods.rb} +29 -104
- data/lib/koala/api/graph_batch_api.rb +112 -65
- data/lib/koala/api/graph_collection.rb +19 -12
- data/lib/koala/api/graph_error_checker.rb +4 -3
- data/lib/koala/api.rb +65 -26
- data/lib/koala/configuration.rb +56 -0
- data/lib/koala/errors.rb +22 -2
- data/lib/koala/http_service/request.rb +133 -0
- data/lib/koala/http_service/response.rb +6 -4
- data/lib/koala/http_service/uploadable_io.rb +0 -5
- data/lib/koala/http_service.rb +29 -76
- data/lib/koala/oauth.rb +8 -8
- data/lib/koala/realtime_updates.rb +26 -21
- data/lib/koala/test_users.rb +9 -8
- data/lib/koala/version.rb +1 -1
- data/lib/koala.rb +7 -9
- data/readme.md +83 -109
- data/spec/cases/api_spec.rb +176 -69
- data/spec/cases/configuration_spec.rb +11 -0
- data/spec/cases/error_spec.rb +16 -3
- data/spec/cases/graph_api_batch_spec.rb +75 -44
- data/spec/cases/graph_api_spec.rb +15 -29
- data/spec/cases/graph_collection_spec.rb +47 -34
- data/spec/cases/graph_error_checker_spec.rb +31 -2
- data/spec/cases/http_service/request_spec.rb +250 -0
- data/spec/cases/http_service/response_spec.rb +24 -0
- data/spec/cases/http_service_spec.rb +126 -286
- data/spec/cases/koala_spec.rb +7 -5
- data/spec/cases/oauth_spec.rb +41 -2
- data/spec/cases/realtime_updates_spec.rb +51 -13
- data/spec/cases/test_users_spec.rb +56 -2
- data/spec/cases/uploadable_io_spec.rb +31 -31
- data/spec/fixtures/cat.m4v +0 -0
- data/spec/fixtures/facebook_data.yml +4 -6
- data/spec/fixtures/mock_facebook_responses.yml +41 -78
- data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
- data/spec/integration/graph_collection_spec.rb +8 -5
- data/spec/spec_helper.rb +2 -2
- data/spec/support/graph_api_shared_examples.rb +152 -337
- data/spec/support/koala_test.rb +11 -13
- data/spec/support/mock_http_service.rb +11 -14
- data/spec/support/uploadable_io_shared_examples.rb +4 -4
- metadata +47 -48
- data/.autotest +0 -12
- data/.travis.yml +0 -17
- data/Guardfile +0 -6
- data/autotest/discover.rb +0 -1
- data/lib/koala/api/rest_api.rb +0 -135
- data/lib/koala/http_service/multipart_request.rb +0 -41
- data/spec/cases/multipart_request_spec.rb +0 -65
- data/spec/support/rest_api_shared_examples.rb +0 -168
@@ -0,0 +1,133 @@
|
|
1
|
+
module Koala
|
2
|
+
module HTTPService
|
3
|
+
class Request
|
4
|
+
attr_reader :raw_path, :raw_args, :raw_verb, :raw_options
|
5
|
+
|
6
|
+
# @param path the server path for this request
|
7
|
+
# @param args (see Koala::Facebook::API#api)
|
8
|
+
# @param verb the HTTP method to use.
|
9
|
+
# If not get or post, this will be turned into a POST request with the appropriate :method
|
10
|
+
# specified in the arguments.
|
11
|
+
# @param options various flags to indicate which server to use. (see Koala::Facebook::API#api)
|
12
|
+
# @param options
|
13
|
+
# @option options :video use the server designated for video uploads
|
14
|
+
# @option options :beta use the beta tier
|
15
|
+
# @option options :use_ssl force https, even if not needed
|
16
|
+
# @option options :json whether or not to send JSON to Facebook
|
17
|
+
def initialize(path:, verb:, args: {}, options: {})
|
18
|
+
@raw_path = path
|
19
|
+
@raw_args = args
|
20
|
+
@raw_verb = verb
|
21
|
+
@raw_options = options
|
22
|
+
end
|
23
|
+
|
24
|
+
# Determines which type of request to send to Facebook. Facebook natively accepts GETs and POSTs, for others we have to include the method in the post body.
|
25
|
+
#
|
26
|
+
# @return one of get or post
|
27
|
+
def verb
|
28
|
+
["get", "post"].include?(raw_verb) ? raw_verb : "post"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Determines the path to be requested on Facebook, incorporating an API version if specified.
|
32
|
+
#
|
33
|
+
# @return the original path, with API version if appropriate.
|
34
|
+
def path
|
35
|
+
# if an api_version is specified and the path does not already contain
|
36
|
+
# one, prepend it to the path
|
37
|
+
api_version = raw_options[:api_version] || Koala.config.api_version
|
38
|
+
if api_version && !path_contains_api_version?
|
39
|
+
begins_with_slash = raw_path[0] == "/"
|
40
|
+
divider = begins_with_slash ? "" : "/"
|
41
|
+
"/#{api_version}#{divider}#{raw_path}"
|
42
|
+
else
|
43
|
+
raw_path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Determines any arguments to be sent in a POST body.
|
48
|
+
#
|
49
|
+
# @return {} for GET; the provided args for POST; those args with the method parameter for
|
50
|
+
# other values
|
51
|
+
def post_args
|
52
|
+
if raw_verb == "get"
|
53
|
+
{}
|
54
|
+
elsif raw_verb == "post"
|
55
|
+
args
|
56
|
+
else
|
57
|
+
args.merge(method: raw_verb)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_args
|
62
|
+
raw_verb == "get" ? args : {}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Calculates a set of request options to pass to Faraday.
|
66
|
+
#
|
67
|
+
# @return a hash combining GET parameters (if appropriate), default options, and
|
68
|
+
# any specified for the request.
|
69
|
+
def options
|
70
|
+
# figure out our options for this request
|
71
|
+
add_ssl_options(
|
72
|
+
# for GETs, we pass the params to Faraday to encode
|
73
|
+
{params: get_args}.merge(HTTPService.http_options).merge(raw_options)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Whether or not this request should use JSON.
|
78
|
+
#
|
79
|
+
# @return true or false
|
80
|
+
def json?
|
81
|
+
raw_options[:format] == :json
|
82
|
+
end
|
83
|
+
|
84
|
+
# The address of the appropriate Facebook server.
|
85
|
+
#
|
86
|
+
# @return a complete server address with protocol
|
87
|
+
def server
|
88
|
+
uri = "#{options[:use_ssl] ? "https" : "http"}://#{Koala.config.graph_server}"
|
89
|
+
# if we want to use the beta tier or the video server, make those substitutions as
|
90
|
+
# appropriate
|
91
|
+
replace_server_component(
|
92
|
+
replace_server_component(uri, options[:video], Koala.config.video_replace),
|
93
|
+
options[:beta],
|
94
|
+
Koala.config.beta_replace
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
# The arguments to include in the request.
|
101
|
+
def args
|
102
|
+
raw_args.inject({}) do |hash, (key, value)|
|
103
|
+
# Resolve UploadableIOs into data Facebook can work with
|
104
|
+
hash.merge(key => value.is_a?(UploadableIO) ? value.to_upload_io : value)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_ssl_options(opts)
|
109
|
+
# require https by default (can be overriden by explicitly setting other SSL options)
|
110
|
+
{
|
111
|
+
use_ssl: true,
|
112
|
+
ssl: {verify: true}.merge(opts[:ssl] || {})
|
113
|
+
}.merge(opts)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Determines whether a given path already contains an API version.
|
117
|
+
#
|
118
|
+
# @param path the URL path.
|
119
|
+
#
|
120
|
+
# @return true or false accordingly.
|
121
|
+
def path_contains_api_version?
|
122
|
+
# looks for "/$MAJOR[.$MINOR]/" in the path
|
123
|
+
match = /^\/?(v\d+(?:\.\d+)?)\//.match(raw_path)
|
124
|
+
!!(match && match[1])
|
125
|
+
end
|
126
|
+
|
127
|
+
def replace_server_component(host, condition_met, replacement)
|
128
|
+
return host unless condition_met
|
129
|
+
host.gsub(Koala.config.host_path_matcher, replacement)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -9,10 +9,12 @@ module Koala
|
|
9
9
|
@body = body
|
10
10
|
@headers = headers
|
11
11
|
end
|
12
|
+
|
13
|
+
def data
|
14
|
+
# quirks_mode is needed because Facebook sometimes returns a raw true or false value --
|
15
|
+
# in Ruby 2.4 we can drop that.
|
16
|
+
@data ||= JSON.parse(body, quirks_mode: true) unless body.empty?
|
17
|
+
end
|
12
18
|
end
|
13
19
|
end
|
14
|
-
|
15
|
-
# @private
|
16
|
-
# legacy support for when Response lived directly under Koala
|
17
|
-
Response = HTTPService::Response
|
18
20
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require "net/http/post/multipart"
|
2
1
|
require "tempfile"
|
3
2
|
|
4
3
|
module Koala
|
@@ -181,8 +180,4 @@ module Koala
|
|
181
180
|
end
|
182
181
|
end
|
183
182
|
end
|
184
|
-
|
185
|
-
# @private
|
186
|
-
# legacy support for when UploadableIO lived directly under Koala
|
187
|
-
UploadableIO = HTTPService::UploadableIO
|
188
183
|
end
|
data/lib/koala/http_service.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
require '
|
2
|
+
require 'faraday/multipart' unless defined? Faraday::FilePart # hack for faraday < 1.9 to avoid warnings
|
3
3
|
require 'koala/http_service/uploadable_io'
|
4
4
|
require 'koala/http_service/response'
|
5
|
+
require 'koala/http_service/request'
|
5
6
|
|
6
7
|
module Koala
|
7
8
|
module HTTPService
|
@@ -18,103 +19,62 @@ module Koala
|
|
18
19
|
# We encode requests in a Facebook-compatible multipart request,
|
19
20
|
# and use whichever adapter has been configured for this application.
|
20
21
|
DEFAULT_MIDDLEWARE = Proc.new do |builder|
|
21
|
-
builder.
|
22
|
+
builder.request :multipart
|
22
23
|
builder.request :url_encoded
|
23
24
|
builder.adapter Faraday.default_adapter
|
24
25
|
end
|
25
26
|
|
26
|
-
# Default
|
27
|
-
#
|
27
|
+
# Default server information for Facebook. These can be overridden by setting config values.
|
28
|
+
# See Koala.config.
|
28
29
|
DEFAULT_SERVERS = {
|
29
30
|
:graph_server => 'graph.facebook.com',
|
30
31
|
:dialog_host => 'www.facebook.com',
|
31
|
-
:rest_server => 'api.facebook.com',
|
32
|
-
# certain Facebook services (beta, video) require you to access different
|
33
|
-
# servers. If you're using your own servers, for instance, for a proxy,
|
34
|
-
# you can change both the matcher and the replacement values.
|
35
|
-
# So for instance, if you're talking to fbproxy.mycompany.com, you could
|
36
|
-
# set up beta.fbproxy.mycompany.com for FB's beta tier, and set the
|
37
|
-
# matcher to /\.fbproxy/ and the beta_replace to '.beta.fbproxy'.
|
38
32
|
:host_path_matcher => /\.facebook/,
|
39
33
|
:video_replace => '-video.facebook',
|
40
34
|
:beta_replace => '.beta.facebook'
|
41
35
|
}
|
42
36
|
|
43
|
-
# The address of the appropriate Facebook server.
|
44
|
-
#
|
45
|
-
# @param options various flags to indicate which server to use.
|
46
|
-
# @option options :rest_api use the old REST API instead of the Graph API
|
47
|
-
# @option options :video use the server designated for video uploads
|
48
|
-
# @option options :beta use the beta tier
|
49
|
-
# @option options :use_ssl force https, even if not needed
|
50
|
-
#
|
51
|
-
# @return a complete server address with protocol
|
52
|
-
def self.server(options = {})
|
53
|
-
server = "#{options[:rest_api] ? Koala.config.rest_server : Koala.config.graph_server}"
|
54
|
-
server.gsub!(Koala.config.host_path_matcher, Koala.config.video_replace) if options[:video]
|
55
|
-
server.gsub!(Koala.config.host_path_matcher, Koala.config.beta_replace) if options[:beta]
|
56
|
-
"#{options[:use_ssl] ? "https" : "http"}://#{server}"
|
57
|
-
end
|
58
|
-
|
59
37
|
# Makes a request directly to Facebook.
|
60
38
|
# @note You'll rarely need to call this method directly.
|
61
39
|
#
|
62
40
|
# @see Koala::Facebook::API#api
|
63
41
|
# @see Koala::Facebook::GraphAPIMethods#graph_call
|
64
|
-
# @see Koala::Facebook::RestAPIMethods#rest_call
|
65
42
|
#
|
66
|
-
# @param
|
67
|
-
# @param args (see Koala::Facebook::API#api)
|
68
|
-
# @param verb the HTTP method to use.
|
69
|
-
# If not get or post, this will be turned into a POST request with the appropriate :method
|
70
|
-
# specified in the arguments.
|
71
|
-
# @param options (see Koala::Facebook::API#api)
|
43
|
+
# @param request a Koala::HTTPService::Request object
|
72
44
|
#
|
73
45
|
# @raise an appropriate connection error if unable to make the request to Facebook
|
74
46
|
#
|
75
47
|
# @return [Koala::HTTPService::Response] a response object representing the results from Facebook
|
76
|
-
def self.make_request(
|
77
|
-
#
|
78
|
-
|
79
|
-
|
80
|
-
# turn all the keys to strings (Faraday has issues with symbols under 1.8.7) and resolve UploadableIOs
|
81
|
-
params = args.inject({}) {|hash, kv| hash[kv.first.to_s] = kv.last.is_a?(UploadableIO) ? kv.last.to_upload_io : kv.last; hash}
|
48
|
+
def self.make_request(request)
|
49
|
+
# set up our Faraday connection
|
50
|
+
conn = Faraday.new(request.server, faraday_options(request.options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
|
82
51
|
|
83
|
-
|
84
|
-
request_options = {:params => (verb == "get" ? params : {})}.merge(http_options || {}).merge(options)
|
85
|
-
request_options[:use_ssl] = true if args["access_token"] # require https if there's a token
|
86
|
-
if request_options[:use_ssl]
|
87
|
-
ssl = (request_options[:ssl] ||= {})
|
88
|
-
ssl[:verify] = true unless ssl.has_key?(:verify)
|
89
|
-
end
|
52
|
+
filtered_args = request.raw_args.dup.transform_keys(&:to_s)
|
90
53
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
path = "/#{api_version}#{divider}#{path}"
|
54
|
+
if Koala.config.mask_tokens
|
55
|
+
%w(access_token input_token).each do |arg_token|
|
56
|
+
if (token = filtered_args[arg_token])
|
57
|
+
filtered_args[arg_token] = token[0, 10] + '*****' + token[-5, 5]
|
58
|
+
end
|
59
|
+
end
|
98
60
|
end
|
99
61
|
|
100
|
-
|
101
|
-
# we have to manually assign params to the URL or the
|
102
|
-
conn = Faraday.new(server(request_options), faraday_options(request_options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
|
62
|
+
Koala::Utils.debug "STARTED => #{request.verb.upcase}: #{request.path} params: #{filtered_args.inspect}"
|
103
63
|
|
104
|
-
|
105
|
-
|
64
|
+
if request.verb == "post" && request.json?
|
65
|
+
# JSON requires a bit more handling
|
66
|
+
# remember, all non-GET requests are turned into POSTs, so this covers everything but GETs
|
106
67
|
response = conn.post do |req|
|
107
|
-
req.path = path
|
68
|
+
req.path = request.path
|
108
69
|
req.headers["Content-Type"] = "application/json"
|
109
|
-
req.body =
|
70
|
+
req.body = request.post_args.to_json
|
110
71
|
req
|
111
72
|
end
|
112
73
|
else
|
113
|
-
response = conn.send(verb, path,
|
74
|
+
response = conn.send(request.verb, request.path, request.post_args)
|
114
75
|
end
|
115
76
|
|
116
|
-
#
|
117
|
-
Koala::Utils.debug "#{verb.upcase}: #{path} params: #{params.inspect}"
|
77
|
+
Koala::Utils.debug "FINISHED => #{request.verb.upcase}: #{request.path} params: #{filtered_args.inspect}"
|
118
78
|
Koala::HTTPService::Response.new(response.status.to_i, response.body, response.headers)
|
119
79
|
end
|
120
80
|
|
@@ -130,21 +90,14 @@ module Koala
|
|
130
90
|
# @return the appropriately-encoded string
|
131
91
|
def self.encode_params(param_hash)
|
132
92
|
((param_hash || {}).sort_by{|k, v| k.to_s}.collect do |key_and_value|
|
133
|
-
|
134
|
-
|
93
|
+
value = key_and_value[1]
|
94
|
+
unless value.is_a? String
|
95
|
+
value = value.to_json
|
96
|
+
end
|
97
|
+
"#{key_and_value[0].to_s}=#{CGI.escape value}"
|
135
98
|
end).join("&")
|
136
99
|
end
|
137
100
|
|
138
|
-
# Determines whether a given path already contains an API version.
|
139
|
-
#
|
140
|
-
# @param path the URL path.
|
141
|
-
#
|
142
|
-
# @return true or false accordingly.
|
143
|
-
def self.path_contains_api_version?(path)
|
144
|
-
match = /^\/?(v\d+(?:\.\d+)?)\//.match(path)
|
145
|
-
!!(match && match[1])
|
146
|
-
end
|
147
|
-
|
148
101
|
private
|
149
102
|
|
150
103
|
def self.faraday_options(options)
|
data/lib/koala/oauth.rb
CHANGED
@@ -12,10 +12,10 @@ module Koala
|
|
12
12
|
# @param app_id [String, Integer] a Facebook application ID
|
13
13
|
# @param app_secret a Facebook application secret
|
14
14
|
# @param oauth_callback_url the URL in your app to which users authenticating with OAuth will be sent
|
15
|
-
def initialize(app_id, app_secret, oauth_callback_url = nil)
|
16
|
-
@app_id = app_id
|
17
|
-
@app_secret = app_secret
|
18
|
-
@oauth_callback_url = oauth_callback_url
|
15
|
+
def initialize(app_id = nil, app_secret = nil, oauth_callback_url = nil)
|
16
|
+
@app_id = app_id || Koala.config.app_id
|
17
|
+
@app_secret = app_secret || Koala.config.app_secret
|
18
|
+
@oauth_callback_url = oauth_callback_url || Koala.config.oauth_callback_url
|
19
19
|
end
|
20
20
|
|
21
21
|
# Parses the cookie set Facebook's JavaScript SDK.
|
@@ -134,7 +134,7 @@ module Koala
|
|
134
134
|
if response == ''
|
135
135
|
raise BadFacebookResponse.new(200, '', 'generate_client_code received an error: empty response body')
|
136
136
|
else
|
137
|
-
result =
|
137
|
+
result = JSON.parse(response)
|
138
138
|
end
|
139
139
|
|
140
140
|
result.has_key?('code') ? result['code'] : raise(Koala::KoalaError.new("Facebook returned a valid response without the expected 'code' in the body (response = #{response})"))
|
@@ -240,7 +240,7 @@ module Koala
|
|
240
240
|
raise OAuthSignatureError, 'Invalid (incomplete) signature data' unless encoded_sig && encoded_envelope
|
241
241
|
|
242
242
|
signature = base64_url_decode(encoded_sig).unpack("H*").first
|
243
|
-
envelope =
|
243
|
+
envelope = JSON.parse(base64_url_decode(encoded_envelope))
|
244
244
|
|
245
245
|
raise OAuthSignatureError, "Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'
|
246
246
|
|
@@ -260,8 +260,8 @@ module Koala
|
|
260
260
|
end
|
261
261
|
|
262
262
|
def parse_access_token(response_text)
|
263
|
-
|
264
|
-
rescue
|
263
|
+
JSON.parse(response_text)
|
264
|
+
rescue JSON::ParserError
|
265
265
|
response_text.split("&").inject({}) do |hash, bit|
|
266
266
|
key, value = bit.split("=")
|
267
267
|
hash.merge!(key => value)
|
@@ -7,9 +7,6 @@ module Koala
|
|
7
7
|
# @note: to subscribe to real-time updates, you must have an application access token
|
8
8
|
# or provide the app secret when initializing your RealtimeUpdates object.
|
9
9
|
|
10
|
-
# The application API interface used to communicate with Facebook.
|
11
|
-
# @return [Koala::Facebook::API]
|
12
|
-
attr_reader :api
|
13
10
|
attr_reader :app_id, :app_access_token, :secret
|
14
11
|
|
15
12
|
# Create a new RealtimeUpdates instance.
|
@@ -23,20 +20,27 @@ module Koala
|
|
23
20
|
#
|
24
21
|
# @raise ArgumentError if the application ID and one of the app access token or the secret are not provided.
|
25
22
|
def initialize(options = {})
|
26
|
-
@app_id = options[:app_id]
|
27
|
-
@app_access_token = options[:app_access_token]
|
28
|
-
@secret = options[:secret]
|
23
|
+
@app_id = options[:app_id] || Koala.config.app_id
|
24
|
+
@app_access_token = options[:app_access_token] || Koala.config.app_access_token
|
25
|
+
@secret = options[:secret] || Koala.config.app_secret
|
29
26
|
unless @app_id && (@app_access_token || @secret) # make sure we have what we need
|
30
27
|
raise ArgumentError, "Initialize must receive a hash with :app_id and either :app_access_token or :secret! (received #{options.inspect})"
|
31
28
|
end
|
29
|
+
end
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
# The app access token, either provided on initialization or fetched from Facebook using the
|
32
|
+
# app_id and secret.
|
33
|
+
def app_access_token
|
34
|
+
# If a token isn't provided but we need it, fetch it
|
35
|
+
@app_access_token ||= Koala::Facebook::OAuth.new(@app_id, @secret).get_app_access_token
|
36
|
+
end
|
38
37
|
|
39
|
-
|
38
|
+
# The application API interface used to communicate with Facebook.
|
39
|
+
# @return [Koala::Facebook::API]
|
40
|
+
def api
|
41
|
+
# Only instantiate the API if needed. validate_update doesn't require it, so we shouldn't
|
42
|
+
# make an unnecessary request to get the app_access_token.
|
43
|
+
@api ||= API.new(app_access_token)
|
40
44
|
end
|
41
45
|
|
42
46
|
# Subscribe to realtime updates for certain fields on a given object (user, page, etc.).
|
@@ -60,7 +64,7 @@ module Koala
|
|
60
64
|
:callback_url => callback_url,
|
61
65
|
}.merge(verify_token ? {:verify_token => verify_token} : {})
|
62
66
|
# a subscription is a success if Facebook returns a 200 (after hitting your server for verification)
|
63
|
-
|
67
|
+
api.graph_call(subscription_path, args, 'post', options)
|
64
68
|
end
|
65
69
|
|
66
70
|
# Unsubscribe from updates for a particular object or from updates.
|
@@ -71,7 +75,7 @@ module Koala
|
|
71
75
|
#
|
72
76
|
# @raise A subclass of Koala::Facebook::APIError if the subscription request failed.
|
73
77
|
def unsubscribe(object = nil, options = {})
|
74
|
-
|
78
|
+
api.graph_call(subscription_path, object ? {:object => object} : {}, "delete", options)
|
75
79
|
end
|
76
80
|
|
77
81
|
# List all active subscriptions for this application.
|
@@ -80,7 +84,7 @@ module Koala
|
|
80
84
|
#
|
81
85
|
# @return [Array] a list of active subscriptions
|
82
86
|
def list_subscriptions(options = {})
|
83
|
-
|
87
|
+
api.graph_call(subscription_path, {}, "get", options)
|
84
88
|
end
|
85
89
|
|
86
90
|
# As a security measure (to prevent DDoS attacks), Facebook sends a verification request to your server
|
@@ -129,12 +133,13 @@ module Koala
|
|
129
133
|
raise AppSecretNotDefinedError, "You must init RealtimeUpdates with your app secret in order to validate updates"
|
130
134
|
end
|
131
135
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
136
|
+
request_signature = headers['X-Hub-Signature'] || headers['HTTP_X_HUB_SIGNATURE']
|
137
|
+
return unless request_signature
|
138
|
+
|
139
|
+
signature_parts = request_signature.split("sha1=")
|
140
|
+
request_signature = signature_parts[1]
|
141
|
+
calculated_signature = OpenSSL::HMAC.hexdigest('sha1', @secret, body)
|
142
|
+
calculated_signature == request_signature
|
138
143
|
end
|
139
144
|
|
140
145
|
# The Facebook subscription management URL for your application.
|
data/lib/koala/test_users.rb
CHANGED
@@ -14,7 +14,6 @@ module Koala
|
|
14
14
|
#
|
15
15
|
# See http://developers.facebook.com/docs/test_users/.
|
16
16
|
class TestUsers
|
17
|
-
|
18
17
|
# The application API interface used to communicate with Facebook.
|
19
18
|
# @return [Koala::Facebook::API]
|
20
19
|
attr_reader :api
|
@@ -31,9 +30,10 @@ module Koala
|
|
31
30
|
#
|
32
31
|
# @raise ArgumentError if the application ID and one of the app access token or the secret are not provided.
|
33
32
|
def initialize(options = {})
|
34
|
-
@app_id = options[:app_id]
|
35
|
-
@app_access_token = options[:app_access_token]
|
36
|
-
@secret = options[:secret]
|
33
|
+
@app_id = options[:app_id] || Koala.config.app_id
|
34
|
+
@app_access_token = options[:app_access_token] || Koala.config.app_access_token
|
35
|
+
@secret = options[:secret] || Koala.config.app_secret
|
36
|
+
|
37
37
|
unless @app_id && (@app_access_token || @secret) # make sure we have what we need
|
38
38
|
raise ArgumentError, "Initialize must receive a hash with :app_id and either :app_access_token or :secret! (received #{options.inspect})"
|
39
39
|
end
|
@@ -146,11 +146,12 @@ module Koala
|
|
146
146
|
raise ArgumentError, "TestUsers#befriend requires hash arguments for both users with id and access_token"
|
147
147
|
end
|
148
148
|
|
149
|
-
u1_graph_api = API.new(user1_token)
|
150
|
-
u2_graph_api = API.new(user2_token)
|
149
|
+
u1_graph_api = API.new(user1_token, secret)
|
150
|
+
u2_graph_api = API.new(user2_token, secret)
|
151
151
|
|
152
|
-
|
153
|
-
|
152
|
+
# if we have a secret token, flag that we want the appsecret_proof to be generated
|
153
|
+
u1_graph_api.graph_call("#{user1_id}/friends/#{user2_id}", {}, "post", options.merge(appsecret_proof: !!secret)) &&
|
154
|
+
u2_graph_api.graph_call("#{user2_id}/friends/#{user1_id}", {}, "post", options.merge(appsecret_proof: !!secret))
|
154
155
|
end
|
155
156
|
|
156
157
|
# Create a network of test users, all of whom are friends and have the same permissions.
|
data/lib/koala/version.rb
CHANGED
data/lib/koala.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# useful tools
|
2
2
|
require 'digest/md5'
|
3
|
-
require '
|
3
|
+
require 'json'
|
4
4
|
|
5
5
|
# include koala modules
|
6
6
|
require 'koala/errors'
|
7
7
|
require 'koala/api'
|
8
|
+
require 'koala/api/graph_batch_api'
|
8
9
|
require 'koala/oauth'
|
9
10
|
require 'koala/realtime_updates'
|
10
11
|
require 'koala/test_users'
|
@@ -13,6 +14,7 @@ require 'koala/test_users'
|
|
13
14
|
require 'koala/http_service'
|
14
15
|
|
15
16
|
# miscellaneous
|
17
|
+
require 'koala/configuration'
|
16
18
|
require 'koala/utils'
|
17
19
|
require 'koala/version'
|
18
20
|
require 'ostruct'
|
@@ -36,14 +38,10 @@ module Koala
|
|
36
38
|
end
|
37
39
|
|
38
40
|
# Allows you to control various Koala configuration options.
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# (see HTTPService::DEFAULT_SERVERS) if you want to run requests through
|
42
|
-
# other servers.
|
43
|
-
# * api_version: controls which Facebook API version to use (v1.0, v2.0,
|
44
|
-
# etc)
|
41
|
+
# NOTE: this is not currently threadsafe.
|
42
|
+
# See Koala::Configuration.
|
45
43
|
def config
|
46
|
-
@config ||=
|
44
|
+
@config ||= Configuration.new
|
47
45
|
end
|
48
46
|
|
49
47
|
# Used for testing.
|
@@ -61,7 +59,7 @@ module Koala
|
|
61
59
|
|
62
60
|
# An convenenient alias to Koala.http_service.make_request.
|
63
61
|
def self.make_request(path, args, verb, options = {})
|
64
|
-
http_service.make_request(path, args, verb, options)
|
62
|
+
http_service.make_request(HTTPService::Request.new(path: path, args: args, verb: verb, options: options))
|
65
63
|
end
|
66
64
|
|
67
65
|
# we use Faraday as our main service, with mock as the other main one
|