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.
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