databasedotcom 1.0.9 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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