koala 3.1.0 → 3.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/Gemfile +2 -1
- data/changelog.md +29 -1
- data/koala.gemspec +2 -1
- data/lib/koala/api/graph_error_checker.rb +1 -1
- data/lib/koala/api.rb +16 -2
- data/lib/koala/configuration.rb +3 -0
- data/lib/koala/errors.rb +21 -1
- data/lib/koala/http_service/uploadable_io.rb +0 -1
- data/lib/koala/http_service.rb +2 -2
- data/lib/koala/version.rb +1 -1
- data/readme.md +31 -0
- data/spec/cases/api_spec.rb +77 -0
- data/spec/cases/error_spec.rb +16 -3
- data/spec/cases/graph_api_batch_spec.rb +1 -1
- data/spec/cases/graph_error_checker_spec.rb +19 -1
- data/spec/cases/http_service_spec.rb +5 -10
- data/spec/support/koala_test.rb +3 -3
- metadata +21 -9
- data/lib/koala/http_service/multipart_request.rb +0 -37
- data/spec/cases/multipart_request_spec.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3709b2644f9f0259e68e181d629754ffe3ba0213322cfb3bad0d369ad04543c
|
4
|
+
data.tar.gz: 7c3e3760d2ee7958b199713c7308f291552ee80a7badddc9ea9434a71cb024a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a22e1b9de96408d3273816150d5e0d55768f72b8b48a93ea276b7d2dc5d35f45de38cb8aad847345faf9c6997d7d0f19d21f177882cfb024e472e8681c9bbd2d
|
7
|
+
data.tar.gz: 5d66a1c10d8bd3d8153eb8faa02ee7ae901aae7321141d12f39abaeb33b6193cea2e3c7215b813942b714965d6048abda867f1d269de39dbdfc0bc137f3a0dc6
|
data/.github/workflows/test.yml
CHANGED
data/Gemfile
CHANGED
@@ -10,10 +10,11 @@ group :development, :test do
|
|
10
10
|
gem "psych", '< 4.0.0' # safe_load signature not compatible with older rubies
|
11
11
|
gem "rake"
|
12
12
|
gem "typhoeus" unless defined? JRUBY_VERSION
|
13
|
+
gem 'faraday-typhoeus' unless defined? JRUBY_VERSION
|
13
14
|
end
|
14
15
|
|
15
16
|
group :test do
|
16
|
-
gem "rspec",
|
17
|
+
gem "rspec", "~> 3.0", "< 3.10" # resrict rspec version until https://github.com/rspec/rspec-support/pull/537 gets merged
|
17
18
|
gem "vcr", github: 'vcr/vcr', ref: '8ced6c96e01737a418cd270e0382a8c2c6d85f7f' # needs https://github.com/vcr/vcr/pull/907 for ruby 3.1
|
18
19
|
gem "webmock"
|
19
20
|
gem "simplecov"
|
data/changelog.md
CHANGED
@@ -15,7 +15,35 @@ Testing improvements:
|
|
15
15
|
|
16
16
|
Others:
|
17
17
|
|
18
|
-
v3.
|
18
|
+
v3.3.0 (2022-09-27)
|
19
|
+
======
|
20
|
+
|
21
|
+
Updated features:
|
22
|
+
|
23
|
+
* Removed restriction on faraday < 2 ([#666](https://github.com/arsduo/koala/pull/666))
|
24
|
+
|
25
|
+
Internal improvements:
|
26
|
+
|
27
|
+
* Remove multipart hack and use default faraday multipart middleware ([#664](https://github.com/arsduo/koala/pull/664))
|
28
|
+
|
29
|
+
Testing improvements:
|
30
|
+
|
31
|
+
* Fix tests with ruby-head ([#674](https://github.com/arsduo/koala/pull/674))
|
32
|
+
* Keep supported rubies (non EOL) for CI ([#675](https://github.com/arsduo/koala/pull/675))
|
33
|
+
|
34
|
+
v3.2.0 (2022-05-27)
|
35
|
+
======
|
36
|
+
|
37
|
+
New features:
|
38
|
+
|
39
|
+
* Exposes limiting headers(`x-business-use-case-usage, x-ad-account-usage, x-app-usage`) to APIError ([#668](https://github.com/arsduo/koala/pull/668))
|
40
|
+
* Add `rate_limit_hook` configuration to get rate limiting headers (`x-business-use-case-usage, x-ad-account-usage, x-app-usage`) ([#670](https://github.com/arsduo/koala/pull/670))
|
41
|
+
|
42
|
+
Testing improvements:
|
43
|
+
|
44
|
+
* Fix builds for ruby 3.x
|
45
|
+
|
46
|
+
v3.1.0 (2022-01-18)
|
19
47
|
======
|
20
48
|
|
21
49
|
New features:
|
data/koala.gemspec
CHANGED
@@ -23,7 +23,8 @@ Gem::Specification.new do |gem|
|
|
23
23
|
|
24
24
|
gem.required_ruby_version = '>= 2.1'
|
25
25
|
|
26
|
-
gem.add_runtime_dependency("faraday"
|
26
|
+
gem.add_runtime_dependency("faraday")
|
27
|
+
gem.add_runtime_dependency("faraday-multipart")
|
27
28
|
gem.add_runtime_dependency("addressable")
|
28
29
|
gem.add_runtime_dependency("json", ">= 1.8")
|
29
30
|
gem.add_runtime_dependency("rexml")
|
@@ -17,7 +17,7 @@ module Koala
|
|
17
17
|
|
18
18
|
# Facebook can return debug information in the response headers -- see
|
19
19
|
# https://developers.facebook.com/docs/graph-api/using-graph-api#bugdebug
|
20
|
-
DEBUG_HEADERS = [
|
20
|
+
DEBUG_HEADERS = %w[x-fb-debug x-fb-rev x-fb-trace-id x-business-use-case-usage x-ad-account-usage x-app-usage]
|
21
21
|
|
22
22
|
def error_if_appropriate
|
23
23
|
if http_status >= 400
|
data/lib/koala/api.rb
CHANGED
@@ -13,14 +13,16 @@ module Koala
|
|
13
13
|
# signed by default, unless you pass appsecret_proof:
|
14
14
|
# false as an option to the API call. (See
|
15
15
|
# https://developers.facebook.com/docs/graph-api/securing-requests/)
|
16
|
+
# @param [Block] rate_limit_hook block called with limits received in facebook response headers
|
16
17
|
# @note If no access token is provided, you can only access some public information.
|
17
18
|
# @return [Koala::Facebook::API] the API client
|
18
|
-
def initialize(access_token = Koala.config.access_token, app_secret = Koala.config.app_secret)
|
19
|
+
def initialize(access_token = Koala.config.access_token, app_secret = Koala.config.app_secret, rate_limit_hook = Koala.config.rate_limit_hook)
|
19
20
|
@access_token = access_token
|
20
21
|
@app_secret = app_secret
|
22
|
+
@rate_limit_hook = rate_limit_hook
|
21
23
|
end
|
22
24
|
|
23
|
-
attr_reader :access_token, :app_secret
|
25
|
+
attr_reader :access_token, :app_secret, :rate_limit_hook
|
24
26
|
|
25
27
|
include GraphAPIMethods
|
26
28
|
|
@@ -58,6 +60,18 @@ module Koala
|
|
58
60
|
API::GraphCollection.evaluate(response, self)
|
59
61
|
end
|
60
62
|
|
63
|
+
if rate_limit_hook
|
64
|
+
limits = %w(x-business-use-case-usage x-ad-account-usage x-app-usage).each_with_object({}) do |key, hash|
|
65
|
+
value = response.headers.fetch(key, nil)
|
66
|
+
next unless value
|
67
|
+
hash[key] = JSON.parse(response.headers[key])
|
68
|
+
rescue JSON::ParserError => e
|
69
|
+
Koala::Utils.logger.error("#{e.class}: #{e.message} while parsing #{key} = #{value}")
|
70
|
+
end
|
71
|
+
|
72
|
+
rate_limit_hook.call(limits) if limits.keys.any?
|
73
|
+
end
|
74
|
+
|
61
75
|
# now process as appropriate for the given call (get picture header, etc.)
|
62
76
|
post_processing ? post_processing.call(desired_data) : desired_data
|
63
77
|
end
|
data/lib/koala/configuration.rb
CHANGED
@@ -31,6 +31,9 @@ class Koala::Configuration
|
|
31
31
|
# Whether or not to mask tokens
|
32
32
|
attr_accessor :mask_tokens
|
33
33
|
|
34
|
+
# Called with the info for the rate limits in the response header
|
35
|
+
attr_accessor :rate_limit_hook
|
36
|
+
|
34
37
|
# Certain Facebook services (beta, video) require you to access different
|
35
38
|
# servers. If you're using your own servers, for instance, for a proxy,
|
36
39
|
# you can change both the matcher (what value to change when updating the URL) and the
|
data/lib/koala/errors.rb
CHANGED
@@ -23,7 +23,10 @@ module Koala
|
|
23
23
|
:fb_error_user_title,
|
24
24
|
:fb_error_trace_id,
|
25
25
|
:fb_error_debug,
|
26
|
-
:fb_error_rev
|
26
|
+
:fb_error_rev,
|
27
|
+
:fb_buc_usage,
|
28
|
+
:fb_ada_usage,
|
29
|
+
:fb_app_usage
|
27
30
|
|
28
31
|
# Create a new API Error
|
29
32
|
#
|
@@ -66,6 +69,9 @@ module Koala
|
|
66
69
|
self.fb_error_trace_id = error_info["x-fb-trace-id"]
|
67
70
|
self.fb_error_debug = error_info["x-fb-debug"]
|
68
71
|
self.fb_error_rev = error_info["x-fb-rev"]
|
72
|
+
self.fb_buc_usage = json_parse_for(error_info, "x-business-use-case-usage")
|
73
|
+
self.fb_ada_usage = json_parse_for(error_info, "x-ad-account-usage")
|
74
|
+
self.fb_app_usage = json_parse_for(error_info, "x-app-usage")
|
69
75
|
|
70
76
|
error_array = []
|
71
77
|
%w(type code error_subcode message error_user_title error_user_msg x-fb-trace-id).each do |key|
|
@@ -82,6 +88,20 @@ module Koala
|
|
82
88
|
|
83
89
|
super(message)
|
84
90
|
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# refs: https://developers.facebook.com/docs/graph-api/overview/rate-limiting/#headers
|
95
|
+
# NOTE: The header will contain a JSON-formatted string that describes current application rate limit usage.
|
96
|
+
def json_parse_for(error_info, key)
|
97
|
+
string = error_info[key]
|
98
|
+
return if string.nil?
|
99
|
+
|
100
|
+
JSON.parse(string)
|
101
|
+
rescue JSON::ParserError => e
|
102
|
+
Koala::Utils.logger.error("#{e.class}: #{e.message} while parsing #{key} = #{string}")
|
103
|
+
nil
|
104
|
+
end
|
85
105
|
end
|
86
106
|
|
87
107
|
# Facebook returned an invalid response body
|
data/lib/koala/http_service.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
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
5
|
require 'koala/http_service/request'
|
@@ -19,7 +19,7 @@ module Koala
|
|
19
19
|
# We encode requests in a Facebook-compatible multipart request,
|
20
20
|
# and use whichever adapter has been configured for this application.
|
21
21
|
DEFAULT_MIDDLEWARE = Proc.new do |builder|
|
22
|
-
builder.
|
22
|
+
builder.request :multipart
|
23
23
|
builder.request :url_encoded
|
24
24
|
builder.adapter Faraday.default_adapter
|
25
25
|
end
|
data/lib/koala/version.rb
CHANGED
data/readme.md
CHANGED
@@ -177,6 +177,37 @@ Koala::Facebook::RealtimeUpdates.meet_challenge(params, your_verify_token)
|
|
177
177
|
```
|
178
178
|
For more information about meet_challenge and the RealtimeUpdates class, check out the Real-Time Updates page on the wiki.
|
179
179
|
|
180
|
+
Rate limits
|
181
|
+
-----------
|
182
|
+
|
183
|
+
We support Facebook rate limit informations as defined here: [https://developers.facebook.com/docs/graph-api/overview/rate-limiting/](https://developers.facebook.com/docs/graph-api/overview/rate-limiting/)
|
184
|
+
|
185
|
+
The information is available either via the `Facebook::APIError`:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
error.fb_buc_usage
|
189
|
+
error.fb_ada_usage
|
190
|
+
error.fb_app_usage
|
191
|
+
```
|
192
|
+
|
193
|
+
Or with the rate_limit_hook:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
# App level configuration
|
197
|
+
|
198
|
+
Koala.configure do |config|
|
199
|
+
config.rate_limit_hook = ->(limits) {
|
200
|
+
limits["x-app-usage"] # {"call_count"=>0, "total_cputime"=>0, "total_time"=>0}
|
201
|
+
limits["x-ad-account-usage"] # {"acc_id_util_pct"=>9.67}
|
202
|
+
limits["x-business-use-case-usage"] # {"123456789012345"=>[{"type"=>"messenger", "call_count"=>1, "total_cputime"=>1, "total_time"=>1, "estimated_time_to_regain_access"=>0}]}
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# Per API configuration
|
207
|
+
|
208
|
+
Koala::Facebook::API.new('', '', ->(limits) {})
|
209
|
+
```
|
210
|
+
|
180
211
|
Test Users
|
181
212
|
----------
|
182
213
|
|
data/spec/cases/api_spec.rb
CHANGED
@@ -282,4 +282,81 @@ describe "Koala::Facebook::API" do
|
|
282
282
|
expect(@service.graph_call('anything')).to be_falsey
|
283
283
|
end
|
284
284
|
end
|
285
|
+
|
286
|
+
describe "Rate limit hook" do
|
287
|
+
it "is called when x-business-use-case-usage header is present" do
|
288
|
+
api = Koala::Facebook::API.new('', '', ->(limits) {
|
289
|
+
expect(limits["x-business-use-case-usage"]).to eq({"123456789012345"=>[{"type"=>"messenger", "call_count"=>1, "total_cputime"=>1, "total_time"=>1, "estimated_time_to_regain_access"=>0}]})
|
290
|
+
})
|
291
|
+
|
292
|
+
result = {"a" => 2}
|
293
|
+
response = Koala::HTTPService::Response.new(200, result.to_json, { "x-business-use-case-usage" => "{\"123456789012345\":[{\"type\":\"messenger\",\"call_count\":1,\"total_cputime\":1,\"total_time\":1,\"estimated_time_to_regain_access\":0}]}" })
|
294
|
+
allow(Koala).to receive(:make_request).and_return(response)
|
295
|
+
|
296
|
+
api.graph_call('anything')
|
297
|
+
end
|
298
|
+
|
299
|
+
it "is called when x-ad-account-usage header is present" do
|
300
|
+
api = Koala::Facebook::API.new('', '', ->(limits) {
|
301
|
+
expect(limits["x-ad-account-usage"]).to eq({"acc_id_util_pct"=>9.67})
|
302
|
+
})
|
303
|
+
|
304
|
+
result = {"a" => 2}
|
305
|
+
response = Koala::HTTPService::Response.new(200, result.to_json, { "x-ad-account-usage" => "{\"acc_id_util_pct\":9.67}" })
|
306
|
+
allow(Koala).to receive(:make_request).and_return(response)
|
307
|
+
|
308
|
+
api.graph_call('anything')
|
309
|
+
end
|
310
|
+
|
311
|
+
it "is called when x-app-usage header is present" do
|
312
|
+
api = Koala::Facebook::API.new('', '', ->(limits) {
|
313
|
+
expect(limits["x-app-usage"]).to eq({"call_count"=>0, "total_cputime"=>0, "total_time"=>0})
|
314
|
+
})
|
315
|
+
|
316
|
+
result = {"a" => 2}
|
317
|
+
response = Koala::HTTPService::Response.new(200, result.to_json, { "x-app-usage" => "{\"call_count\":0,\"total_cputime\":0,\"total_time\":0}" })
|
318
|
+
allow(Koala).to receive(:make_request).and_return(response)
|
319
|
+
|
320
|
+
api.graph_call('anything')
|
321
|
+
end
|
322
|
+
|
323
|
+
it "isn't called if none of the rate limit header is present" do
|
324
|
+
rate_limit_hook_called = false
|
325
|
+
|
326
|
+
api = Koala::Facebook::API.new('', '', ->(limits) {
|
327
|
+
rate_limit_hook_called = true
|
328
|
+
})
|
329
|
+
|
330
|
+
result = {"a" => 2}
|
331
|
+
response = Koala::HTTPService::Response.new(200, result.to_json, {})
|
332
|
+
allow(Koala).to receive(:make_request).and_return(response)
|
333
|
+
|
334
|
+
api.graph_call('anything')
|
335
|
+
|
336
|
+
expect(rate_limit_hook_called).to be(false)
|
337
|
+
end
|
338
|
+
|
339
|
+
it "isn't called if no rate limit hook is defined" do
|
340
|
+
api = Koala::Facebook::API.new('', '', ->(limits) {
|
341
|
+
#noop
|
342
|
+
})
|
343
|
+
|
344
|
+
result = {"a" => 2}
|
345
|
+
response = Koala::HTTPService::Response.new(200, result.to_json, { "x-ad-account-usage" => "{\"acc_id_util_pct\"9.67}"})
|
346
|
+
allow(Koala).to receive(:make_request).and_return(response)
|
347
|
+
|
348
|
+
expect(Koala::Utils.logger).to receive(:error).with(/JSON::ParserError:.*unexpected token at '{"acc_id_util_pct"9.67}' while parsing x-ad-account-usage = {"acc_id_util_pct"9.67}/)
|
349
|
+
api.graph_call('anything')
|
350
|
+
end
|
351
|
+
|
352
|
+
it "logs an error if the rate limit header can't be properly parsed" do
|
353
|
+
api = Koala::Facebook::API.new('', '', nil)
|
354
|
+
|
355
|
+
result = {"a" => 2}
|
356
|
+
response = Koala::HTTPService::Response.new(200, result.to_json, {})
|
357
|
+
allow(Koala).to receive(:make_request).and_return(response)
|
358
|
+
|
359
|
+
api.graph_call('anything')
|
360
|
+
end
|
361
|
+
end
|
285
362
|
end
|
data/spec/cases/error_spec.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
BUC_USAGE_JSON = "{\"123456789012345\":[{\"type\":\"messenger\",\"call_count\":1,\"total_cputime\":1,\"total_time\":1,\"estimated_time_to_regain_access\":0}]}"
|
4
|
+
ADA_USAGE_JSON = "{\"acc_id_util_pct\":9.67}"
|
5
|
+
APP_USAGE_JSON = "{\"call_count\":0,\"total_cputime\":0,\"total_time\":0}"
|
6
|
+
|
3
7
|
describe Koala::Facebook::APIError do
|
4
8
|
it "is a Koala::KoalaError" do
|
5
9
|
expect(Koala::Facebook::APIError.new(nil, nil)).to be_a(Koala::KoalaError)
|
@@ -32,7 +36,10 @@ describe Koala::Facebook::APIError do
|
|
32
36
|
'error_user_title' => 'error user title',
|
33
37
|
'x-fb-trace-id' => 'fb trace id',
|
34
38
|
'x-fb-debug' => 'fb debug token',
|
35
|
-
'x-fb-rev' => 'fb revision'
|
39
|
+
'x-fb-rev' => 'fb revision',
|
40
|
+
'x-business-use-case-usage' => BUC_USAGE_JSON,
|
41
|
+
'x-ad-account-usage' => ADA_USAGE_JSON,
|
42
|
+
'x-app-usage' => APP_USAGE_JSON
|
36
43
|
}
|
37
44
|
Koala::Facebook::APIError.new(400, '', error_info)
|
38
45
|
}
|
@@ -46,7 +53,10 @@ describe Koala::Facebook::APIError do
|
|
46
53
|
:fb_error_user_title => 'error user title',
|
47
54
|
:fb_error_trace_id => 'fb trace id',
|
48
55
|
:fb_error_debug => 'fb debug token',
|
49
|
-
:fb_error_rev => 'fb revision'
|
56
|
+
:fb_error_rev => 'fb revision',
|
57
|
+
:fb_buc_usage => JSON.parse(BUC_USAGE_JSON),
|
58
|
+
:fb_ada_usage => JSON.parse(ADA_USAGE_JSON),
|
59
|
+
:fb_app_usage => JSON.parse(APP_USAGE_JSON)
|
50
60
|
}.each_pair do |accessor, value|
|
51
61
|
it "sets #{accessor} to #{value}" do
|
52
62
|
expect(error.send(accessor)).to eq(value)
|
@@ -76,7 +86,10 @@ describe Koala::Facebook::APIError do
|
|
76
86
|
:fb_error_code => 1,
|
77
87
|
:fb_error_subcode => 'subcode',
|
78
88
|
:fb_error_user_msg => 'error user message',
|
79
|
-
:fb_error_user_title => 'error user title'
|
89
|
+
:fb_error_user_title => 'error user title',
|
90
|
+
:fb_buc_usage => nil,
|
91
|
+
:fb_ada_usage => nil,
|
92
|
+
:fb_app_usage => nil
|
80
93
|
}.each_pair do |accessor, value|
|
81
94
|
expect(error.send(accessor)).to eq(value)
|
82
95
|
end
|
@@ -593,7 +593,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
|
|
593
593
|
hash_including(@other_access_token_args.dup),
|
594
594
|
anything,
|
595
595
|
anything
|
596
|
-
).and_return(Koala::HTTPService::Response.new(200, "",
|
596
|
+
).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
597
597
|
|
598
598
|
# Page the collection
|
599
599
|
app_event_types.next_page
|
@@ -11,7 +11,10 @@ module Koala
|
|
11
11
|
expect(GraphErrorChecker::DEBUG_HEADERS).to match_array([
|
12
12
|
"x-fb-rev",
|
13
13
|
"x-fb-debug",
|
14
|
-
"x-fb-trace-id"
|
14
|
+
"x-fb-trace-id",
|
15
|
+
"x-business-use-case-usage",
|
16
|
+
"x-ad-account-usage",
|
17
|
+
"x-app-usage"
|
15
18
|
])
|
16
19
|
end
|
17
20
|
|
@@ -84,10 +87,25 @@ module Koala
|
|
84
87
|
"x-fb-debug" => double("fb debug"),
|
85
88
|
"x-fb-rev" => double("fb rev"),
|
86
89
|
"x-fb-trace-id" => double("fb trace id"),
|
90
|
+
"x-business-use-case-usage" => { 'a' => 1, 'b' => 2 }.to_json,
|
91
|
+
"x-ad-account-usage" => { 'c' => 3, 'd' => 4 }.to_json,
|
92
|
+
"x-app-usage" => { 'e' => 5, 'f' => 6 }.to_json
|
87
93
|
)
|
88
94
|
expect(error.fb_error_trace_id).to eq(headers["x-fb-trace-id"])
|
89
95
|
expect(error.fb_error_debug).to eq(headers["x-fb-debug"])
|
90
96
|
expect(error.fb_error_rev).to eq(headers["x-fb-rev"])
|
97
|
+
expect(error.fb_buc_usage).to eq({ 'a' => 1, 'b' => 2 })
|
98
|
+
expect(error.fb_ada_usage).to eq({ 'c' => 3, 'd' => 4 })
|
99
|
+
expect(error.fb_app_usage).to eq({ 'e' => 5, 'f' => 6 })
|
100
|
+
end
|
101
|
+
|
102
|
+
it "logs if one of the FB debug headers can't be parsed" do
|
103
|
+
headers.merge!(
|
104
|
+
"x-app-usage" => '{invalid:json}'
|
105
|
+
)
|
106
|
+
|
107
|
+
expect(Koala::Utils.logger).to receive(:error).with(/JSON::ParserError:.*unexpected token at '{invalid:json}' while parsing x-app-usage = {invalid:json}/)
|
108
|
+
expect(error.fb_app_usage).to eq(nil)
|
91
109
|
end
|
92
110
|
|
93
111
|
context "it returns an AuthenticationError" do
|
@@ -39,8 +39,7 @@ describe Koala::HTTPService do
|
|
39
39
|
|
40
40
|
it "adds the right default middleware" do
|
41
41
|
Koala::HTTPService::DEFAULT_MIDDLEWARE.call(builder)
|
42
|
-
expect(builder.requests).to eq([:url_encoded])
|
43
|
-
expect(builder.uses).to eq([Koala::HTTPService::MultipartRequest])
|
42
|
+
expect(builder.requests).to eq([:multipart, :url_encoded])
|
44
43
|
expect(builder.adapters).to eq([Faraday.default_adapter])
|
45
44
|
end
|
46
45
|
end
|
@@ -194,18 +193,16 @@ describe Koala::HTTPService do
|
|
194
193
|
|
195
194
|
it "uses the default builder block if HTTPService.faraday_middleware block is not defined" do
|
196
195
|
block = Proc.new { |builder|
|
197
|
-
builder.
|
196
|
+
builder.request :multipart
|
198
197
|
builder.request :url_encoded
|
199
|
-
builder.use Koala::HTTPService::MultipartRequest
|
200
198
|
}
|
201
199
|
stub_const("Koala::HTTPService::DEFAULT_MIDDLEWARE", block)
|
202
200
|
allow(Koala::HTTPService).to receive(:faraday_middleware).and_return(nil)
|
203
201
|
|
204
202
|
expect_any_instance_of(Faraday::Connection).to receive(:get) do |instance|
|
205
203
|
expect(instance.builder.handlers).to eq([
|
206
|
-
|
204
|
+
Faraday::Multipart::Middleware,
|
207
205
|
Faraday::Request::UrlEncoded,
|
208
|
-
Koala::HTTPService::MultipartRequest
|
209
206
|
])
|
210
207
|
mock_http_response
|
211
208
|
end
|
@@ -215,17 +212,15 @@ describe Koala::HTTPService do
|
|
215
212
|
|
216
213
|
it "uses the defined HTTPService.faraday_middleware block if defined" do
|
217
214
|
block = Proc.new { |builder|
|
218
|
-
builder.
|
215
|
+
builder.request :multipart
|
219
216
|
builder.request :url_encoded
|
220
|
-
builder.use Koala::HTTPService::MultipartRequest
|
221
217
|
}
|
222
218
|
expect(Koala::HTTPService).to receive(:faraday_middleware).and_return(block)
|
223
219
|
|
224
220
|
expect_any_instance_of(Faraday::Connection).to receive(:get) do |instance|
|
225
221
|
expect(instance.builder.handlers).to eq([
|
226
|
-
|
222
|
+
Faraday::Multipart::Middleware,
|
227
223
|
Faraday::Request::UrlEncoded,
|
228
|
-
Koala::HTTPService::MultipartRequest
|
229
224
|
])
|
230
225
|
mock_http_response
|
231
226
|
end
|
data/spec/support/koala_test.rb
CHANGED
@@ -238,11 +238,11 @@ module KoalaTest
|
|
238
238
|
# JRuby doesn't support typhoeus on Travis
|
239
239
|
unless defined? JRUBY_VERSION
|
240
240
|
require adapter
|
241
|
-
require
|
241
|
+
require "faraday/#{adapter}"
|
242
242
|
Faraday.default_adapter = adapter.to_sym
|
243
243
|
end
|
244
|
-
rescue
|
245
|
-
puts "Unable to load adapter #{adapter}, using Net::HTTP."
|
244
|
+
rescue => e
|
245
|
+
puts "Unable to load adapter #{adapter}, using Net::HTTP. #{e.class} #{e.message}"
|
246
246
|
ensure
|
247
247
|
@adapter_activation_attempted = true
|
248
248
|
end
|
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: koala
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Koppel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday-multipart
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
25
32
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: addressable
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -101,7 +115,6 @@ files:
|
|
101
115
|
- lib/koala/configuration.rb
|
102
116
|
- lib/koala/errors.rb
|
103
117
|
- lib/koala/http_service.rb
|
104
|
-
- lib/koala/http_service/multipart_request.rb
|
105
118
|
- lib/koala/http_service/request.rb
|
106
119
|
- lib/koala/http_service/response.rb
|
107
120
|
- lib/koala/http_service/uploadable_io.rb
|
@@ -123,7 +136,6 @@ files:
|
|
123
136
|
- spec/cases/http_service_spec.rb
|
124
137
|
- spec/cases/koala_spec.rb
|
125
138
|
- spec/cases/koala_test_spec.rb
|
126
|
-
- spec/cases/multipart_request_spec.rb
|
127
139
|
- spec/cases/oauth_spec.rb
|
128
140
|
- spec/cases/realtime_updates_spec.rb
|
129
141
|
- spec/cases/test_users_spec.rb
|
@@ -165,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
177
|
- !ruby/object:Gem::Version
|
166
178
|
version: '0'
|
167
179
|
requirements: []
|
168
|
-
rubygems_version: 3.0.
|
180
|
+
rubygems_version: 3.4.0.dev
|
169
181
|
signing_key:
|
170
182
|
specification_version: 4
|
171
183
|
summary: A lightweight, flexible library for Facebook with support for the Graph API,
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
|
3
|
-
module Koala
|
4
|
-
module HTTPService
|
5
|
-
class MultipartRequest < Faraday::Request::Multipart
|
6
|
-
# Facebook expects nested parameters to be passed in a certain way
|
7
|
-
# Based on our testing (https://github.com/arsduo/koala/issues/125),
|
8
|
-
# Faraday needs two changes to make that work:
|
9
|
-
# 1) [] need to be escaped (e.g. params[foo]=bar ==> params%5Bfoo%5D=bar)
|
10
|
-
# 2) such messages need to be multipart-encoded
|
11
|
-
|
12
|
-
self.mime_type = 'multipart/form-data'.freeze
|
13
|
-
|
14
|
-
def process_request?(env)
|
15
|
-
# if the request values contain any hashes or arrays, multipart it
|
16
|
-
super || !!(env[:body].respond_to?(:values) && env[:body].values.find {|v| v.is_a?(Hash) || v.is_a?(Array)})
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
def process_params(params, prefix = nil, pieces = nil, &block)
|
21
|
-
params.inject(pieces || []) do |all, (key, value)|
|
22
|
-
key = "#{prefix}%5B#{key}%5D" if prefix
|
23
|
-
|
24
|
-
case value
|
25
|
-
when Array
|
26
|
-
values = value.inject([]) { |a,v| a << [nil, v] }
|
27
|
-
process_params(values, key, all, &block)
|
28
|
-
when Hash
|
29
|
-
process_params(value, key, all, &block)
|
30
|
-
else
|
31
|
-
all << block.call(key, value)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Koala::HTTPService::MultipartRequest do
|
4
|
-
it "is a subclass of Faraday::Request::Multipart" do
|
5
|
-
expect(Koala::HTTPService::MultipartRequest.superclass).to eq(Faraday::Request::Multipart)
|
6
|
-
end
|
7
|
-
|
8
|
-
it "defines mime_type as multipart/form-data" do
|
9
|
-
expect(Koala::HTTPService::MultipartRequest.mime_type).to eq('multipart/form-data')
|
10
|
-
end
|
11
|
-
|
12
|
-
describe "#process_request?" do
|
13
|
-
before :each do
|
14
|
-
@env = Faraday::Env.new
|
15
|
-
@multipart = Koala::HTTPService::MultipartRequest.new
|
16
|
-
allow(@multipart).to receive(:request_type).and_return("")
|
17
|
-
end
|
18
|
-
|
19
|
-
# no way to test the call to super, unfortunately
|
20
|
-
it "returns true if env[:body] is a hash with at least one hash in its values" do
|
21
|
-
@env[:body] = {:a => {:c => 2}}
|
22
|
-
expect(@multipart.process_request?(@env)).to be_truthy
|
23
|
-
end
|
24
|
-
|
25
|
-
it "returns true if env[:body] is a hash with at least one array in its values" do
|
26
|
-
@env[:body] = {:a => [:c, 2]}
|
27
|
-
expect(@multipart.process_request?(@env)).to be_truthy
|
28
|
-
end
|
29
|
-
|
30
|
-
it "returns true if env[:body] is a hash with mixed objects in its values" do
|
31
|
-
@env[:body] = {:a => [:c, 2], :b => {:e => :f}}
|
32
|
-
expect(@multipart.process_request?(@env)).to be_truthy
|
33
|
-
end
|
34
|
-
|
35
|
-
it "returns false if env[:body] is a string" do
|
36
|
-
@env[:body] = "my body"
|
37
|
-
expect(@multipart.process_request?(@env)).to be_falsey
|
38
|
-
end
|
39
|
-
|
40
|
-
it "returns false if env[:body] is a hash without an array or hash value" do
|
41
|
-
@env[:body] = {:a => 3}
|
42
|
-
expect(@multipart.process_request?(@env)).to be_falsey
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "#process_params" do
|
47
|
-
before :each do
|
48
|
-
@parent = Faraday::Request::Multipart.new
|
49
|
-
@multipart = Koala::HTTPService::MultipartRequest.new
|
50
|
-
@block = lambda {|k, v| "#{k}=#{v}"}
|
51
|
-
end
|
52
|
-
|
53
|
-
it "is identical to the parent for requests without a prefix" do
|
54
|
-
hash = {:a => 2, :c => "3"}
|
55
|
-
expect(@multipart.process_params(hash, &@block)).to eq(@parent.process_params(hash, &@block))
|
56
|
-
end
|
57
|
-
|
58
|
-
it "replaces encodes [ and ] if the request has a prefix" do
|
59
|
-
hash = {:a => 2, :c => "3"}
|
60
|
-
prefix = "foo"
|
61
|
-
# process_params returns an array
|
62
|
-
expect(@multipart.process_params(hash, prefix, &@block).join("&")).to eq(@parent.process_params(hash, prefix, &@block).join("&").gsub(/\[/, "%5B").gsub(/\]/, "%5D"))
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|