koala 2.4.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +32 -0
  3. data/Gemfile +5 -3
  4. data/ISSUE_TEMPLATE +25 -0
  5. data/PULL_REQUEST_TEMPLATE +11 -0
  6. data/changelog.md +161 -4
  7. data/code_of_conduct.md +64 -12
  8. data/koala.gemspec +5 -1
  9. data/lib/koala/api/batch_operation.rb +3 -6
  10. data/lib/koala/api/{graph_api.rb → graph_api_methods.rb} +29 -104
  11. data/lib/koala/api/graph_batch_api.rb +112 -65
  12. data/lib/koala/api/graph_collection.rb +19 -12
  13. data/lib/koala/api/graph_error_checker.rb +4 -3
  14. data/lib/koala/api.rb +65 -26
  15. data/lib/koala/configuration.rb +56 -0
  16. data/lib/koala/errors.rb +22 -2
  17. data/lib/koala/http_service/request.rb +133 -0
  18. data/lib/koala/http_service/response.rb +6 -4
  19. data/lib/koala/http_service/uploadable_io.rb +0 -5
  20. data/lib/koala/http_service.rb +29 -76
  21. data/lib/koala/oauth.rb +8 -8
  22. data/lib/koala/realtime_updates.rb +26 -21
  23. data/lib/koala/test_users.rb +9 -8
  24. data/lib/koala/version.rb +1 -1
  25. data/lib/koala.rb +7 -9
  26. data/readme.md +83 -109
  27. data/spec/cases/api_spec.rb +176 -69
  28. data/spec/cases/configuration_spec.rb +11 -0
  29. data/spec/cases/error_spec.rb +16 -3
  30. data/spec/cases/graph_api_batch_spec.rb +75 -44
  31. data/spec/cases/graph_api_spec.rb +15 -29
  32. data/spec/cases/graph_collection_spec.rb +47 -34
  33. data/spec/cases/graph_error_checker_spec.rb +31 -2
  34. data/spec/cases/http_service/request_spec.rb +250 -0
  35. data/spec/cases/http_service/response_spec.rb +24 -0
  36. data/spec/cases/http_service_spec.rb +126 -286
  37. data/spec/cases/koala_spec.rb +7 -5
  38. data/spec/cases/oauth_spec.rb +41 -2
  39. data/spec/cases/realtime_updates_spec.rb +51 -13
  40. data/spec/cases/test_users_spec.rb +56 -2
  41. data/spec/cases/uploadable_io_spec.rb +31 -31
  42. data/spec/fixtures/cat.m4v +0 -0
  43. data/spec/fixtures/facebook_data.yml +4 -6
  44. data/spec/fixtures/mock_facebook_responses.yml +41 -78
  45. data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
  46. data/spec/integration/graph_collection_spec.rb +8 -5
  47. data/spec/spec_helper.rb +2 -2
  48. data/spec/support/graph_api_shared_examples.rb +152 -337
  49. data/spec/support/koala_test.rb +11 -13
  50. data/spec/support/mock_http_service.rb +11 -14
  51. data/spec/support/uploadable_io_shared_examples.rb +4 -4
  52. metadata +47 -48
  53. data/.autotest +0 -12
  54. data/.travis.yml +0 -17
  55. data/Guardfile +0 -6
  56. data/autotest/discover.rb +0 -1
  57. data/lib/koala/api/rest_api.rb +0 -135
  58. data/lib/koala/http_service/multipart_request.rb +0 -41
  59. data/spec/cases/multipart_request_spec.rb +0 -65
  60. 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
@@ -1,7 +1,8 @@
1
1
  require 'faraday'
2
- require 'koala/http_service/multipart_request'
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.use Koala::HTTPService::MultipartRequest
22
+ builder.request :multipart
22
23
  builder.request :url_encoded
23
24
  builder.adapter Faraday.default_adapter
24
25
  end
25
26
 
26
- # Default servers for Facebook. These are read into the config OpenStruct,
27
- # and can be overridden via Koala.config.
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 path the server path for this request
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(path, args, verb, options = {})
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}
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
- # 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
52
+ filtered_args = request.raw_args.dup.transform_keys(&:to_s)
90
53
 
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}"
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
- # set up our Faraday connection
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
- # remember, all non-GET requests are turned into POSTs -- see the the start of this method
105
- if verb == "post" && options[:format] == :json
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 = params.to_json
70
+ req.body = request.post_args.to_json
110
71
  req
111
72
  end
112
73
  else
113
- response = conn.send(verb, path, (verb == "post" ? params : {}))
74
+ response = conn.send(request.verb, request.path, request.post_args)
114
75
  end
115
76
 
116
- # Log URL information
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
- key_and_value[1] = MultiJson.dump(key_and_value[1]) unless key_and_value[1].is_a? String
134
- "#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
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 = MultiJson.load(response)
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 = MultiJson.load(base64_url_decode(encoded_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
- MultiJson.load(response_text)
264
- rescue MultiJson::LoadError
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
- # fetch the access token if we're provided a secret
34
- if @secret && !@app_access_token
35
- oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
36
- @app_access_token = oauth.get_app_access_token
37
- end
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
- @api = API.new(@app_access_token)
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
- @api.graph_call(subscription_path, args, 'post', options)
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
- @api.graph_call(subscription_path, object ? {:object => object} : {}, "delete", options)
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
- @api.graph_call(subscription_path, {}, "get", options)
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
- if request_signature = headers['X-Hub-Signature'] || headers['HTTP_X_HUB_SIGNATURE'] and
133
- signature_parts = request_signature.split("sha1=")
134
- request_signature = signature_parts[1]
135
- calculated_signature = OpenSSL::HMAC.hexdigest('sha1', @secret, body)
136
- calculated_signature == request_signature
137
- end
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.
@@ -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
- u1_graph_api.graph_call("#{user1_id}/friends/#{user2_id}", {}, "post", options) &&
153
- u2_graph_api.graph_call("#{user2_id}/friends/#{user1_id}", {}, "post", options)
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
@@ -1,3 +1,3 @@
1
1
  module Koala
2
- VERSION = "2.4.0"
2
+ VERSION = "3.5.0"
3
3
  end
data/lib/koala.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  # useful tools
2
2
  require 'digest/md5'
3
- require 'multi_json'
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
- # Notable options:
40
- # * server endpoints: you can override any or all the server endpoints
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 ||= OpenStruct.new(HTTPService::DEFAULT_SERVERS)
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