koala 2.5.0 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -2
- data/Gemfile +1 -1
- data/changelog.md +26 -0
- data/lib/koala/api/batch_operation.rb +3 -6
- data/lib/koala/api/graph_api.rb +6 -45
- data/lib/koala/api/graph_batch_api.rb +1 -2
- data/lib/koala/api/graph_collection.rb +1 -5
- data/lib/koala/api/graph_error_checker.rb +1 -1
- data/lib/koala/api.rb +3 -7
- data/lib/koala/errors.rb +1 -1
- data/lib/koala/http_service/multipart_request.rb +6 -10
- data/lib/koala/http_service/request.rb +139 -0
- data/lib/koala/http_service/response.rb +0 -4
- data/lib/koala/http_service/uploadable_io.rb +0 -4
- data/lib/koala/http_service.rb +16 -68
- data/lib/koala/oauth.rb +3 -3
- data/lib/koala/version.rb +1 -1
- data/lib/koala.rb +2 -1
- data/readme.md +5 -26
- data/spec/cases/api_spec.rb +1 -7
- data/spec/cases/graph_api_batch_spec.rb +12 -22
- data/spec/cases/graph_api_spec.rb +0 -19
- data/spec/cases/graph_collection_spec.rb +18 -18
- data/spec/cases/graph_error_checker_spec.rb +6 -1
- data/spec/cases/http_service/request_spec.rb +240 -0
- data/spec/cases/http_service_spec.rb +102 -296
- data/spec/cases/koala_spec.rb +6 -1
- data/spec/cases/oauth_spec.rb +1 -1
- data/spec/cases/test_users_spec.rb +4 -1
- data/spec/cases/uploadable_io_spec.rb +31 -31
- data/spec/fixtures/mock_facebook_responses.yml +0 -37
- data/spec/spec_helper.rb +2 -2
- data/spec/support/graph_api_shared_examples.rb +6 -142
- data/spec/support/koala_test.rb +6 -6
- data/spec/support/mock_http_service.rb +6 -6
- data/spec/support/uploadable_io_shared_examples.rb +4 -4
- metadata +7 -7
- data/lib/koala/api/rest_api.rb +0 -135
- data/spec/support/rest_api_shared_examples.rb +0 -168
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04714e9f9ae4e70420567406530119f6560518d1
|
4
|
+
data.tar.gz: 92ec819da43149fc5de98f6ec931afc6736c8199
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51df761c7444da9dfb2c78b1fc30216b6fb3e5463c8e3bda322cae0f01e5e6fde5eecd62fc63f81527d25277972ff8ec00db71ca56aae9322bcfa626484e2470
|
7
|
+
data.tar.gz: f0545dd4651b30877186dd1f9bf3abe921a73a73f778980434536d4ad7923e17085fa64df53f7f449986d4fe5c460e08e6ceba605ddcc4a70de90c1ed21881c7
|
data/.travis.yml
CHANGED
@@ -6,12 +6,14 @@ rvm:
|
|
6
6
|
- 2.0
|
7
7
|
- 2.1
|
8
8
|
- 2.2
|
9
|
-
- 2.3.
|
9
|
+
- 2.3.1
|
10
10
|
# Rubinius is failing due to segfaults on Travis (and takes significantly longer to run)
|
11
11
|
# those builds will be restored later
|
12
12
|
# jruby
|
13
|
-
- jruby-19mode
|
13
|
+
# - jruby-19mode
|
14
14
|
bundler_args: --without development
|
15
15
|
addons:
|
16
16
|
code_climate:
|
17
17
|
repo_token: 7af99d9225b4c14640f9ec3cb2e24d2f7103ac49417b0bd989188fb6c25f2909
|
18
|
+
after_success:
|
19
|
+
- bundle exec codeclimate-test-reporter
|
data/Gemfile
CHANGED
data/changelog.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
v3.0.0
|
2
|
+
======
|
3
|
+
|
4
|
+
Key breaking changes:
|
5
|
+
|
6
|
+
* HTTPService.make_request now requires an HTTPService::Request object (Koala.make_request does
|
7
|
+
not)
|
8
|
+
* HTTPService behavior *should not* change, but in edge cases might. (If so, please let me know.)
|
9
|
+
* Empty response bodies in batch API calls will raise a JSON parse error rather than returning nil
|
10
|
+
|
11
|
+
Removed features:
|
12
|
+
|
13
|
+
* Removed support for the Rest API, since Facebook removed support for it (#568)
|
14
|
+
* Removed support for FQL, which Facebook removed on August 8, 2016 (#569)
|
15
|
+
* Removed legacy duplication of serveral constants in the Koala module (#569)
|
16
|
+
|
17
|
+
Internal improvements:
|
18
|
+
|
19
|
+
* Completely rewrote HTTPService.make_request and several others, extracting most logic into
|
20
|
+
HTTPService::Request (#566)
|
21
|
+
* Use the more secure JSON.parse instead of JSON.load (thanks, lautis!) (#567)
|
22
|
+
|
23
|
+
Testing improvements:
|
24
|
+
|
25
|
+
* Fixed a bunch of failing specs
|
26
|
+
|
1
27
|
v2.5.0
|
2
28
|
======
|
3
29
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'koala/api'
|
2
|
+
require 'koala/api/graph_batch_api'
|
2
3
|
|
3
4
|
module Koala
|
4
5
|
module Facebook
|
@@ -65,13 +66,13 @@ module Koala
|
|
65
66
|
def process_binary_args
|
66
67
|
# collect binary files
|
67
68
|
@args.each_pair do |key, value|
|
68
|
-
if UploadableIO.binary_content?(value)
|
69
|
+
if HTTPService::UploadableIO.binary_content?(value)
|
69
70
|
@files ||= {}
|
70
71
|
# we use a class-level counter to ensure unique file identifiers across multiple batch operations
|
71
72
|
# (this is thread safe, since we just care about uniqueness)
|
72
73
|
# so remove the file from the original hash and add it to the file store
|
73
74
|
id = "op#{identifier}_file#{@files.keys.length}"
|
74
|
-
@files[id] = @args.delete(key).is_a?(UploadableIO) ? value : UploadableIO.new(value)
|
75
|
+
@files[id] = @args.delete(key).is_a?(HTTPService::UploadableIO) ? value : HTTPService::UploadableIO.new(value)
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -81,9 +82,5 @@ module Koala
|
|
81
82
|
end
|
82
83
|
end
|
83
84
|
end
|
84
|
-
|
85
|
-
# @private
|
86
|
-
# legacy support for when BatchOperation lived directly under Koala::Facebook
|
87
|
-
BatchOperation = GraphBatchAPI::BatchOperation
|
88
85
|
end
|
89
86
|
end
|
data/lib/koala/api/graph_api.rb
CHANGED
@@ -359,45 +359,6 @@ module Koala
|
|
359
359
|
# except to support cases where the Facebook API requires non-standard input
|
360
360
|
# such as JSON-encoding arguments, posts directly to objects, etc.
|
361
361
|
|
362
|
-
# Make an FQL query.
|
363
|
-
# Convenience method equivalent to get_object("fql", :q => query).
|
364
|
-
#
|
365
|
-
# @param query the FQL query to perform
|
366
|
-
# @param args (see #get_object)
|
367
|
-
# @param options (see #get_object)
|
368
|
-
# @param block (see Koala::Facebook::API#api)
|
369
|
-
#
|
370
|
-
# @return the result of the FQL query.
|
371
|
-
def fql_query(query, args = {}, options = {}, &block)
|
372
|
-
get_object("fql", args.merge(:q => query), options, &block)
|
373
|
-
end
|
374
|
-
|
375
|
-
# Make an FQL multiquery.
|
376
|
-
# This method simplifies the result returned from multiquery into a more logical format.
|
377
|
-
#
|
378
|
-
# @param queries a hash of query names => FQL queries
|
379
|
-
# @param args (see #get_object)
|
380
|
-
# @param options (see #get_object)
|
381
|
-
# @param block (see Koala::Facebook::API#api)
|
382
|
-
#
|
383
|
-
# @example
|
384
|
-
# @api.fql_multiquery({
|
385
|
-
# "query1" => "select post_id from stream where source_id = me()",
|
386
|
-
# "query2" => "select fromid from comment where post_id in (select post_id from #query1)"
|
387
|
-
# })
|
388
|
-
# # returns {"query1" => [obj1, obj2, ...], "query2" => [obj3, ...]}
|
389
|
-
# # instead of [{"name":"query1", "fql_result_set":[]},{"name":"query2", "fql_result_set":[]}]
|
390
|
-
#
|
391
|
-
# @return a hash of FQL results keyed to the appropriate query
|
392
|
-
def fql_multiquery(queries = {}, args = {}, options = {}, &block)
|
393
|
-
resolved_results = if results = get_object("fql", args.merge(:q => JSON.dump(queries)), options)
|
394
|
-
# simplify the multiquery result format
|
395
|
-
results.inject({}) {|outcome, data| outcome[data["name"]] = data["fql_result_set"]; outcome}
|
396
|
-
end
|
397
|
-
|
398
|
-
block ? block.call(resolved_results) : resolved_results
|
399
|
-
end
|
400
|
-
|
401
362
|
# Get a page's access token, allowing you to act as the page.
|
402
363
|
# Convenience method for @api.get_object(page_id, :fields => "access_token").
|
403
364
|
#
|
@@ -463,13 +424,13 @@ module Koala
|
|
463
424
|
# Those methods use get_page to request another set of results from Facebook.
|
464
425
|
#
|
465
426
|
# @note You'll rarely need to use this method unless you're using Sinatra or another non-Rails framework
|
466
|
-
# (see {Koala::Facebook::GraphCollection GraphCollection} for more information).
|
427
|
+
# (see {Koala::Facebook::API::GraphCollection GraphCollection} for more information).
|
467
428
|
#
|
468
429
|
# @param params an array of arguments to graph_call
|
469
|
-
# as returned by {Koala::Facebook::GraphCollection.parse_page_url}.
|
430
|
+
# as returned by {Koala::Facebook::API::GraphCollection.parse_page_url}.
|
470
431
|
# @param block (see Koala::Facebook::API#api)
|
471
432
|
#
|
472
|
-
# @return Koala::Facebook::GraphCollection the appropriate page of results (an empty array if there are none)
|
433
|
+
# @return Koala::Facebook::API::GraphCollection the appropriate page of results (an empty array if there are none)
|
473
434
|
def get_page(params, &block)
|
474
435
|
graph_call(*params, &block)
|
475
436
|
end
|
@@ -529,7 +490,7 @@ module Koala
|
|
529
490
|
# @yield response when making a batch API call, you can pass in a block
|
530
491
|
# that parses the results, allowing for cleaner code.
|
531
492
|
# The block's return value is returned in the batch results.
|
532
|
-
# See the code for {#get_picture}
|
493
|
+
# See the code for {#get_picture} for examples.
|
533
494
|
# (Not needed in regular calls; you'll probably rarely use this.)
|
534
495
|
#
|
535
496
|
# @raise [Koala::Facebook::APIError] if Facebook returns an error
|
@@ -544,7 +505,7 @@ module Koala
|
|
544
505
|
end
|
545
506
|
|
546
507
|
# turn this into a GraphCollection if it's pageable
|
547
|
-
result = GraphCollection.evaluate(result, self)
|
508
|
+
result = API::GraphCollection.evaluate(result, self)
|
548
509
|
|
549
510
|
# now process as appropriate for the given call (get picture header, etc.)
|
550
511
|
post_processing ? post_processing.call(result) : result
|
@@ -573,7 +534,7 @@ module Koala
|
|
573
534
|
fb_expected_arg_name = method == "photos" ? :url : :file_url
|
574
535
|
args.merge!(fb_expected_arg_name => media_args.first)
|
575
536
|
else
|
576
|
-
args["source"] = Koala::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
|
537
|
+
args["source"] = Koala::HTTPService::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
|
577
538
|
end
|
578
539
|
|
579
540
|
[target_id, method, args, options]
|
@@ -75,7 +75,7 @@ module Koala
|
|
75
75
|
raw_result = error
|
76
76
|
else
|
77
77
|
# (see note in regular api method about JSON parsing)
|
78
|
-
body = JSON.
|
78
|
+
body = JSON.parse("[#{call_result['body'].to_s}]")[0]
|
79
79
|
|
80
80
|
# Get the HTTP component they want
|
81
81
|
raw_result = case batch_op.http_options[:http_component]
|
@@ -101,7 +101,6 @@ module Koala
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
105
104
|
end
|
106
105
|
end
|
107
106
|
end
|
@@ -23,7 +23,7 @@ module Koala
|
|
23
23
|
# @param api the Graph {Koala::Facebook::API API} instance to use to make calls
|
24
24
|
# (usually the API that made the original call).
|
25
25
|
#
|
26
|
-
# @return [Koala::Facebook::GraphCollection] an initialized GraphCollection
|
26
|
+
# @return [Koala::Facebook::API::GraphCollection] an initialized GraphCollection
|
27
27
|
# whose paging, summary, raw_response, and api attributes are populated.
|
28
28
|
def initialize(response, api)
|
29
29
|
super response["data"]
|
@@ -113,9 +113,5 @@ module Koala
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
end
|
116
|
-
|
117
|
-
# @private
|
118
|
-
# legacy support for when GraphCollection lived directly under Koala::Facebook
|
119
|
-
GraphCollection = API::GraphCollection
|
120
116
|
end
|
121
117
|
end
|
data/lib/koala/api.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# graph_batch_api and legacy are required at the bottom, since they depend on API being defined
|
2
2
|
require 'koala/api/graph_api'
|
3
|
-
require 'koala/api/
|
3
|
+
require 'koala/api/graph_collection'
|
4
4
|
require 'openssl'
|
5
5
|
|
6
6
|
module Koala
|
@@ -23,13 +23,11 @@ module Koala
|
|
23
23
|
attr_reader :access_token, :app_secret
|
24
24
|
|
25
25
|
include GraphAPIMethods
|
26
|
-
include RestAPIMethods
|
27
26
|
|
28
27
|
# Makes a request to the appropriate Facebook API.
|
29
28
|
# @note You'll rarely need to call this method directly.
|
30
29
|
#
|
31
30
|
# @see GraphAPIMethods#graph_call
|
32
|
-
# @see RestAPIMethods#rest_call
|
33
31
|
#
|
34
32
|
# @param path the server path for this request (leading / is prepended if not present)
|
35
33
|
# @param args arguments to be sent to Facebook
|
@@ -85,9 +83,9 @@ module Koala
|
|
85
83
|
else
|
86
84
|
# parse the body as JSON and run it through the error checker (if provided)
|
87
85
|
# Note: Facebook sometimes sends results like "true" and "false", which are valid[RFC7159]
|
88
|
-
# but unsupported by Ruby's stdlib[RFC4627] and cause JSON.
|
86
|
+
# but unsupported by Ruby's stdlib[RFC4627] and cause JSON.parse to fail -- so we account for
|
89
87
|
# that by wrapping the result in []
|
90
|
-
JSON.
|
88
|
+
JSON.parse("[#{result.body.to_s}]")[0]
|
91
89
|
end
|
92
90
|
end
|
93
91
|
|
@@ -117,5 +115,3 @@ module Koala
|
|
117
115
|
end
|
118
116
|
end
|
119
117
|
end
|
120
|
-
|
121
|
-
require 'koala/api/graph_batch_api'
|
data/lib/koala/errors.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
|
3
|
-
module Koala
|
3
|
+
module Koala
|
4
4
|
module HTTPService
|
5
5
|
class MultipartRequest < Faraday::Request::Multipart
|
6
6
|
# Facebook expects nested parameters to be passed in a certain way
|
@@ -8,15 +8,15 @@ module Koala
|
|
8
8
|
# Faraday needs two changes to make that work:
|
9
9
|
# 1) [] need to be escaped (e.g. params[foo]=bar ==> params%5Bfoo%5D=bar)
|
10
10
|
# 2) such messages need to be multipart-encoded
|
11
|
-
|
11
|
+
|
12
12
|
self.mime_type = 'multipart/form-data'.freeze
|
13
|
-
|
13
|
+
|
14
14
|
def process_request?(env)
|
15
15
|
# if the request values contain any hashes or arrays, multipart it
|
16
16
|
super || !!(env[:body].respond_to?(:values) && env[:body].values.find {|v| v.is_a?(Hash) || v.is_a?(Array)})
|
17
|
-
end
|
18
|
-
|
19
|
-
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
20
|
def process_params(params, prefix = nil, pieces = nil, &block)
|
21
21
|
params.inject(pieces || []) do |all, (key, value)|
|
22
22
|
key = "#{prefix}%5B#{key}%5D" if prefix
|
@@ -34,8 +34,4 @@ module Koala
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
|
-
# @private
|
39
|
-
# legacy support for when MultipartRequest lived directly under Koala
|
40
|
-
MultipartRequest = HTTPService::MultipartRequest
|
41
37
|
end
|
@@ -0,0 +1,139 @@
|
|
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: nil, args: {}, verb: nil, options: {})
|
18
|
+
# we still support Ruby 2.0 so we can't use required keyword arguments
|
19
|
+
raise ArgumentError, "Missing required argument verb" unless verb
|
20
|
+
raise ArgumentError, "Missing required argument path" unless path
|
21
|
+
|
22
|
+
@raw_path = path
|
23
|
+
@raw_args = args
|
24
|
+
@raw_verb = verb
|
25
|
+
@raw_options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
# 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.
|
29
|
+
#
|
30
|
+
# @return one of get or post
|
31
|
+
def verb
|
32
|
+
["get", "post"].include?(raw_verb) ? raw_verb : "post"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Determines the path to be requested on Facebook, incorporating an API version if specified.
|
36
|
+
#
|
37
|
+
# @return the original path, with API version if appropriate.
|
38
|
+
def path
|
39
|
+
# if an api_version is specified and the path does not already contain
|
40
|
+
# one, prepend it to the path
|
41
|
+
api_version = raw_options[:api_version] || Koala.config.api_version
|
42
|
+
if api_version && !path_contains_api_version?
|
43
|
+
begins_with_slash = raw_path[0] == "/"
|
44
|
+
divider = begins_with_slash ? "" : "/"
|
45
|
+
"/#{api_version}#{divider}#{raw_path}"
|
46
|
+
else
|
47
|
+
raw_path
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Determines any arguments to be sent in a POST body.
|
52
|
+
#
|
53
|
+
# @return {} for GET; the provided args for POST; those args with the method parameter for
|
54
|
+
# other values
|
55
|
+
def post_args
|
56
|
+
if raw_verb == "get"
|
57
|
+
{}
|
58
|
+
elsif raw_verb == "post"
|
59
|
+
args
|
60
|
+
else
|
61
|
+
args.merge(method: raw_verb)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_args
|
66
|
+
raw_verb == "get" ? args : {}
|
67
|
+
end
|
68
|
+
|
69
|
+
# Calculates a set of request options to pass to Faraday.
|
70
|
+
#
|
71
|
+
# @return a hash combining GET parameters (if appropriate), default options, and
|
72
|
+
# any specified for the request.
|
73
|
+
def options
|
74
|
+
# figure out our options for this request
|
75
|
+
add_ssl_options(
|
76
|
+
# for GETs, we pass the params to Faraday to encode
|
77
|
+
{params: get_args}.merge(HTTPService.http_options).merge(raw_options)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Whether or not this request should use JSON.
|
82
|
+
#
|
83
|
+
# @return true or false
|
84
|
+
def json?
|
85
|
+
raw_options[:format] == :json
|
86
|
+
end
|
87
|
+
|
88
|
+
# The address of the appropriate Facebook server.
|
89
|
+
#
|
90
|
+
# @return a complete server address with protocol
|
91
|
+
def server
|
92
|
+
uri = "#{options[:use_ssl] ? "https" : "http"}://#{Koala.config.graph_server}"
|
93
|
+
# if we want to use the beta tier or the video server, make those substitutions as
|
94
|
+
# appropriate
|
95
|
+
replace_server_component(
|
96
|
+
replace_server_component(uri, options[:video], Koala.config.video_replace),
|
97
|
+
options[:beta],
|
98
|
+
Koala.config.beta_replace
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
# The arguments to include in the request.
|
105
|
+
def args
|
106
|
+
raw_args.inject({}) do |hash, (key, value)|
|
107
|
+
# Resolve UploadableIOs into data Facebook can work with
|
108
|
+
hash.merge(key => value.is_a?(UploadableIO) ? value.to_upload_io : value)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_ssl_options(opts)
|
113
|
+
# require https if there's a token
|
114
|
+
return opts unless raw_args["access_token"]
|
115
|
+
|
116
|
+
{
|
117
|
+
use_ssl: true,
|
118
|
+
ssl: {verify: true}.merge(opts[:ssl] || {})
|
119
|
+
}.merge(opts)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Determines whether a given path already contains an API version.
|
123
|
+
#
|
124
|
+
# @param path the URL path.
|
125
|
+
#
|
126
|
+
# @return true or false accordingly.
|
127
|
+
def path_contains_api_version?
|
128
|
+
# looks for "/$MAJOR[.$MINOR]/" in the path
|
129
|
+
match = /^\/?(v\d+(?:\.\d+)?)\//.match(raw_path)
|
130
|
+
!!(match && match[1])
|
131
|
+
end
|
132
|
+
|
133
|
+
def replace_server_component(host, condition_met, replacement)
|
134
|
+
return host unless condition_met
|
135
|
+
host.gsub(Koala.config.host_path_matcher, replacement)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/koala/http_service.rb
CHANGED
@@ -2,6 +2,7 @@ require 'faraday'
|
|
2
2
|
require 'koala/http_service/multipart_request'
|
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
|
@@ -28,7 +29,6 @@ module Koala
|
|
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
32
|
# certain Facebook services (beta, video) require you to access different
|
33
33
|
# servers. If you're using your own servers, for instance, for a proxy,
|
34
34
|
# you can change both the matcher and the replacement values.
|
@@ -40,81 +40,36 @@ module Koala
|
|
40
40
|
:beta_replace => '.beta.facebook'
|
41
41
|
}
|
42
42
|
|
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
43
|
# Makes a request directly to Facebook.
|
60
44
|
# @note You'll rarely need to call this method directly.
|
61
45
|
#
|
62
46
|
# @see Koala::Facebook::API#api
|
63
47
|
# @see Koala::Facebook::GraphAPIMethods#graph_call
|
64
|
-
# @see Koala::Facebook::RestAPIMethods#rest_call
|
65
48
|
#
|
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)
|
49
|
+
# @param request a Koala::HTTPService::Request object
|
72
50
|
#
|
73
51
|
# @raise an appropriate connection error if unable to make the request to Facebook
|
74
52
|
#
|
75
53
|
# @return [Koala::HTTPService::Response] a response object representing the results from Facebook
|
76
|
-
def self.make_request(
|
77
|
-
# if the verb isn't get or post, send it as a post argument with a method param
|
78
|
-
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
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}
|
82
|
-
|
83
|
-
# figure out our options for this request
|
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
|
90
|
-
|
91
|
-
# if an api_version is specified and the path does not already contain
|
92
|
-
# one, prepend it to the path
|
93
|
-
api_version = request_options[:api_version] || Koala.config.api_version
|
94
|
-
if api_version && !path_contains_api_version?(path)
|
95
|
-
begins_with_slash = path[0] == "/"
|
96
|
-
divider = begins_with_slash ? "" : "/"
|
97
|
-
path = "/#{api_version}#{divider}#{path}"
|
98
|
-
end
|
99
|
-
|
54
|
+
def self.make_request(request)
|
100
55
|
# set up our Faraday connection
|
101
|
-
|
102
|
-
conn = Faraday.new(server(request_options), faraday_options(request_options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
|
56
|
+
conn = Faraday.new(request.server, faraday_options(request.options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
|
103
57
|
|
104
|
-
|
105
|
-
|
58
|
+
if request.verb == "post" && request.json?
|
59
|
+
# JSON requires a bit more handling
|
60
|
+
# remember, all non-GET requests are turned into POSTs, so this covers everything but GETs
|
106
61
|
response = conn.post do |req|
|
107
|
-
req.path = path
|
62
|
+
req.path = request.path
|
108
63
|
req.headers["Content-Type"] = "application/json"
|
109
|
-
req.body =
|
64
|
+
req.body = request.post_args.to_json
|
110
65
|
req
|
111
66
|
end
|
112
67
|
else
|
113
|
-
response = conn.send(verb, path,
|
68
|
+
response = conn.send(request.verb, request.path, request.post_args)
|
114
69
|
end
|
115
70
|
|
116
71
|
# Log URL information
|
117
|
-
Koala::Utils.debug "#{verb.upcase}: #{path} params: #{
|
72
|
+
Koala::Utils.debug "#{request.verb.upcase}: #{request.path} params: #{request.raw_args.inspect}"
|
118
73
|
Koala::HTTPService::Response.new(response.status.to_i, response.body, response.headers)
|
119
74
|
end
|
120
75
|
|
@@ -130,21 +85,14 @@ module Koala
|
|
130
85
|
# @return the appropriately-encoded string
|
131
86
|
def self.encode_params(param_hash)
|
132
87
|
((param_hash || {}).sort_by{|k, v| k.to_s}.collect do |key_and_value|
|
133
|
-
|
134
|
-
|
88
|
+
value = key_and_value[1]
|
89
|
+
unless value.is_a? String
|
90
|
+
value = value.to_json
|
91
|
+
end
|
92
|
+
"#{key_and_value[0].to_s}=#{CGI.escape value}"
|
135
93
|
end).join("&")
|
136
94
|
end
|
137
95
|
|
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
96
|
private
|
149
97
|
|
150
98
|
def self.faraday_options(options)
|
data/lib/koala/oauth.rb
CHANGED
@@ -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 = JSON.
|
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 = JSON.
|
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,7 +260,7 @@ module Koala
|
|
260
260
|
end
|
261
261
|
|
262
262
|
def parse_access_token(response_text)
|
263
|
-
JSON.
|
263
|
+
JSON.parse(response_text)
|
264
264
|
rescue JSON::ParserError
|
265
265
|
response_text.split("&").inject({}) do |hash, bit|
|
266
266
|
key, value = bit.split("=")
|
data/lib/koala/version.rb
CHANGED
data/lib/koala.rb
CHANGED
@@ -5,6 +5,7 @@ require 'json'
|
|
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'
|
@@ -61,7 +62,7 @@ module Koala
|
|
61
62
|
|
62
63
|
# An convenenient alias to Koala.http_service.make_request.
|
63
64
|
def self.make_request(path, args, verb, options = {})
|
64
|
-
http_service.make_request(path, args, verb, options)
|
65
|
+
http_service.make_request(HTTPService::Request.new(path: path, args: args, verb: verb, options: options))
|
65
66
|
end
|
66
67
|
|
67
68
|
# we use Faraday as our main service, with mock as the other main one
|