koala 2.4.0 → 3.5.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.
- 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
|