databasedotcom 1.0.9 → 1.1.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.
- 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
|