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.
@@ -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
- json = JSON.parse(result.body)
97
- @user_id = json["id"].match(/\/([^\/]+)$/)[1] rescue nil
98
- self.instance_url = json["instance_url"]
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
- req = Net::HTTP.new(URI.parse(self.instance_url).host, 443)
266
- req.use_ssl = true
267
- path_parameters = (parameters || {}).collect { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
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
- req = Net::HTTP.new(URI.parse(self.instance_url).host, 443)
282
- req.use_ssl = true
283
- path_parameters = (parameters || {}).collect { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
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
- req = Net::HTTP.new(URI.parse(self.instance_url).host, 443)
297
- req.use_ssl = true
298
- path_parameters = (parameters || {}).collect { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
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
- req = Net::HTTP.new(URI.parse(self.instance_url).host, 443)
312
- req.use_ssl = true
313
- path_parameters = (parameters || {}).collect { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
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
- req = Net::HTTP.new(URI.parse(self.instance_url).host, 443)
328
- req.use_ssl = true
329
- path_parameters = (parameters || {}).collect { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
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
@@ -1,3 +1,3 @@
1
1
  module Databasedotcom
2
- VERSION = "1.0.9"
2
+ VERSION = "1.1.0"
3
3
  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.9
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-11 00:00:00 Z
13
+ date: 2011-09-22 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: multipart-post