databasedotcom 1.0.9 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/databasedotcom/client.rb +89 -50
- data/lib/databasedotcom/version.rb +1 -1
- metadata +2 -2
@@ -11,6 +11,8 @@ module Databasedotcom
|
|
11
11
|
attr_accessor :client_secret
|
12
12
|
# The OAuth access token in use by the client
|
13
13
|
attr_accessor :oauth_token
|
14
|
+
# The OAuth refresh token in use by the client
|
15
|
+
attr_accessor :refresh_token
|
14
16
|
# The base URL to the authenticated user's SalesForce instance
|
15
17
|
attr_accessor :instance_url
|
16
18
|
# If true, print API debugging information to stdout. Defaults to false.
|
@@ -79,7 +81,7 @@ module Databasedotcom
|
|
79
81
|
#
|
80
82
|
# * If _options_ contains the keys <tt>:username</tt> and <tt>:password</tt>, those credentials are used to authenticate. In this case, the value of <tt>:password</tt> may need to include a concatenated security token, if required by your Salesforce org
|
81
83
|
# * If _options_ contains the key <tt>:provider</tt>, it is assumed to be the hash returned by Omniauth from a successful web-based OAuth2 authentication
|
82
|
-
# * If _options_ contains the keys <tt>:token</tt> and <tt>:instance_url</tt>, those are assumed to be a valid OAuth2 token and instance URL for a Salesforce account, obtained from an external source
|
84
|
+
# * If _options_ contains the keys <tt>:token</tt> and <tt>:instance_url</tt>, those are assumed to be a valid OAuth2 token and instance URL for a Salesforce account, obtained from an external source. _options_ may also optionally contain the key <tt>:refresh_token</tt>
|
83
85
|
#
|
84
86
|
# Raises SalesForceError if an error occurs
|
85
87
|
def authenticate(options = nil)
|
@@ -93,19 +95,20 @@ module Databasedotcom
|
|
93
95
|
result = req.post(path, "")
|
94
96
|
log_response(result)
|
95
97
|
raise SalesForceError.new(result) unless result.is_a?(Net::HTTPOK)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
self.oauth_token = json["access_token"]
|
98
|
+
self.username = user
|
99
|
+
self.password = pass
|
100
|
+
parse_auth_response(result.body)
|
100
101
|
elsif options.is_a?(Hash)
|
101
102
|
if options.has_key?("provider")
|
102
103
|
@user_id = options["extra"]["user_hash"]["user_id"] rescue nil
|
103
104
|
self.instance_url = options["credentials"]["instance_url"]
|
104
105
|
self.oauth_token = options["credentials"]["token"]
|
106
|
+
self.refresh_token = options["credentials"]["refresh_token"]
|
105
107
|
else
|
106
108
|
raise ArgumentError unless options.has_key?(:token) && options.has_key?(:instance_url)
|
107
109
|
self.instance_url = options[:instance_url]
|
108
110
|
self.oauth_token = options[:token]
|
111
|
+
self.refresh_token = options[:refresh_token]
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
@@ -262,15 +265,9 @@ module Databasedotcom
|
|
262
265
|
# +Authorization+ header is automatically included, as are any additional headers specified in _headers_. Returns the HTTPResult if it is of type
|
263
266
|
# HTTPSuccess- raises SalesForceError otherwise.
|
264
267
|
def http_get(path, parameters={}, headers={})
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
encoded_path = [URI.escape(path), path_parameters.empty? ? nil : path_parameters].compact.join('?')
|
269
|
-
log_request(encoded_path)
|
270
|
-
result = req.get(encoded_path, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
271
|
-
log_response(result)
|
272
|
-
raise SalesForceError.new(result) unless result.is_a?(Net::HTTPSuccess)
|
273
|
-
result
|
268
|
+
with_encoded_path_and_checked_response(path, parameters) do |encoded_path|
|
269
|
+
https_request.get(encoded_path, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
270
|
+
end
|
274
271
|
end
|
275
272
|
|
276
273
|
|
@@ -278,45 +275,27 @@ module Databasedotcom
|
|
278
275
|
# +Authorization+ header is automatically included, as are any additional headers specified in _headers_. Returns the HTTPResult if it is of type
|
279
276
|
# HTTPSuccess- raises SalesForceError otherwise.
|
280
277
|
def http_delete(path, parameters={}, headers={})
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
encoded_path = [URI.escape(path), path_parameters.empty? ? nil : path_parameters].compact.join('?')
|
285
|
-
log_request(encoded_path)
|
286
|
-
result = req.delete(encoded_path, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
287
|
-
log_response(result)
|
288
|
-
raise SalesForceError.new(result) unless result.is_a?(Net::HTTPNoContent)
|
289
|
-
result
|
278
|
+
with_encoded_path_and_checked_response(path, parameters, {:expected_result_class => Net::HTTPNoContent}) do |encoded_path|
|
279
|
+
https_request.delete(encoded_path, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
280
|
+
end
|
290
281
|
end
|
291
282
|
|
292
283
|
# Performs an HTTP POST request to the specified path (relative to self.instance_url). The body of the request is taken from _data_.
|
293
284
|
# Query parameters are included from _parameters_. The required +Authorization+ header is automatically included, as are any additional
|
294
285
|
# headers specified in _headers_. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
|
295
286
|
def http_post(path, data=nil, parameters={}, headers={})
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
encoded_path = [URI.escape(path), path_parameters.empty? ? nil : path_parameters].compact.join('?')
|
300
|
-
log_request(encoded_path, data)
|
301
|
-
result = req.post(encoded_path, data, {"Content-Type" => data ? "application/json" : "text/plain", "Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
302
|
-
log_response(result)
|
303
|
-
raise SalesForceError.new(result) unless result.is_a?(Net::HTTPSuccess)
|
304
|
-
result
|
287
|
+
with_encoded_path_and_checked_response(path, parameters, {:data => data}) do |encoded_path|
|
288
|
+
https_request.post(encoded_path, data, {"Content-Type" => data ? "application/json" : "text/plain", "Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
289
|
+
end
|
305
290
|
end
|
306
291
|
|
307
292
|
# Performs an HTTP PATCH request to the specified path (relative to self.instance_url). The body of the request is taken from _data_.
|
308
293
|
# Query parameters are included from _parameters_. The required +Authorization+ header is automatically included, as are any additional
|
309
294
|
# headers specified in _headers_. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
|
310
295
|
def http_patch(path, data=nil, parameters={}, headers={})
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
encoded_path = [URI.escape(path), path_parameters.empty? ? nil : path_parameters].compact.join('?')
|
315
|
-
log_request(encoded_path, data)
|
316
|
-
result = req.send_request("PATCH", encoded_path, data, {"Content-Type" => data ? "application/json" : "text/plain", "Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
317
|
-
log_response(result)
|
318
|
-
raise SalesForceError.new(result) unless result.is_a?(Net::HTTPSuccess)
|
319
|
-
result
|
296
|
+
with_encoded_path_and_checked_response(path, parameters, {:data => data}) do |encoded_path|
|
297
|
+
https_request.send_request("PATCH", encoded_path, data, {"Content-Type" => data ? "application/json" : "text/plain", "Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))
|
298
|
+
end
|
320
299
|
end
|
321
300
|
|
322
301
|
# Performs an HTTP POST request to the specified path (relative to self.instance_url), using Content-Type multiplart/form-data.
|
@@ -324,19 +303,72 @@ module Databasedotcom
|
|
324
303
|
# +Authorization+ header is automatically included, as are any additional headers specified in _headers_.
|
325
304
|
# Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
|
326
305
|
def http_multipart_post(path, parts, parameters={}, headers={})
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
encoded_path = [URI.escape(path), path_parameters.empty? ? nil : path_parameters].compact.join('?')
|
331
|
-
log_request(encoded_path)
|
332
|
-
result = req.request(Net::HTTP::Post::Multipart.new(encoded_path, parts, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers)))
|
333
|
-
log_response(result)
|
334
|
-
raise SalesForceError.new(result) unless result.is_a?(Net::HTTPSuccess)
|
335
|
-
result
|
306
|
+
with_encoded_path_and_checked_response(path, parameters) do |encoded_path|
|
307
|
+
https_request.request(Net::HTTP::Post::Multipart.new(encoded_path, parts, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers)))
|
308
|
+
end
|
336
309
|
end
|
337
310
|
|
338
311
|
private
|
339
312
|
|
313
|
+
def with_encoded_path_and_checked_response(path, parameters, opts = {})
|
314
|
+
ensure_expected_response(opts[:expected_result_class]) do
|
315
|
+
with_logging(encode_path_with_params(path, parameters), opts[:data]) do |encoded_path|
|
316
|
+
yield(encoded_path)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def with_logging(encoded_path, optional_data = nil)
|
322
|
+
log_request(encoded_path, optional_data)
|
323
|
+
response = yield encoded_path
|
324
|
+
log_response(response)
|
325
|
+
response
|
326
|
+
end
|
327
|
+
|
328
|
+
def ensure_expected_response(expected_result_class)
|
329
|
+
yield.tap do |response|
|
330
|
+
unless response.is_a?(expected_result_class || Net::HTTPSuccess)
|
331
|
+
if response.is_a?(Net::HTTPUnauthorized)
|
332
|
+
if self.refresh_token
|
333
|
+
with_encoded_path_and_checked_response("/services/oauth2/token", { :grant_type => "refresh_token", :refresh_token => self.refresh_token, :client_id => self.client_id, :client_secret => self.client_secret}) do |encoded_path|
|
334
|
+
response = https_request(self.host).post(encoded_path, nil)
|
335
|
+
if response.is_a?(Net::HTTPOK)
|
336
|
+
parse_auth_response(response.body)
|
337
|
+
end
|
338
|
+
response
|
339
|
+
end
|
340
|
+
elsif self.username && self.password
|
341
|
+
with_encoded_path_and_checked_response("/services/oauth2/token", { :grant_type => "password", :username => self.username, :password => self.password, :client_id => self.client_id, :client_secret => self.client_secret}) do |encoded_path|
|
342
|
+
response = https_request(self.host).post(encoded_path, nil)
|
343
|
+
if response.is_a?(Net::HTTPOK)
|
344
|
+
parse_auth_response(response.body)
|
345
|
+
end
|
346
|
+
response
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
if response.is_a?(Net::HTTPSuccess)
|
351
|
+
response = yield
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
raise SalesForceError.new(response) unless response.is_a?(expected_result_class || Net::HTTPSuccess)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def https_request(host=nil)
|
361
|
+
Net::HTTP.new(host || URI.parse(self.instance_url).host, 443).tap{|n| n.use_ssl = true }
|
362
|
+
end
|
363
|
+
|
364
|
+
def encode_path_with_params(path, parameters={})
|
365
|
+
[URI.escape(path), encode_parameters(parameters)].reject{|el| el.empty?}.join('?')
|
366
|
+
end
|
367
|
+
|
368
|
+
def encode_parameters(parameters={})
|
369
|
+
(parameters || {}).collect { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
|
370
|
+
end
|
371
|
+
|
340
372
|
def log_request(path, data=nil)
|
341
373
|
puts "***** REQUEST: #{path.include?(':') ? path : URI.join(self.instance_url, path)}#{data ? " => #{data}" : ''}" if self.debugging
|
342
374
|
end
|
@@ -430,5 +462,12 @@ module Databasedotcom
|
|
430
462
|
def user_and_pass?(options)
|
431
463
|
(self.username && self.password) || (options && options[:username] && options[:password])
|
432
464
|
end
|
465
|
+
|
466
|
+
def parse_auth_response(body)
|
467
|
+
json = JSON.parse(body)
|
468
|
+
@user_id = json["id"].match(/\/([^\/]+)$/)[1] rescue nil
|
469
|
+
self.instance_url = json["instance_url"]
|
470
|
+
self.oauth_token = json["access_token"]
|
471
|
+
end
|
433
472
|
end
|
434
473
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: databasedotcom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.0
|
5
|
+
version: 1.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Glenn Gillen, Danny Burkes & Richard Zhao
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-09-
|
13
|
+
date: 2011-09-22 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: multipart-post
|