dwolla-ruby 1.1.0 → 2.0.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 (53) hide show
  1. data/dwolla-ruby.gemspec +16 -21
  2. data/examples/accountInfo.rb +7 -7
  3. data/examples/balance.rb +5 -5
  4. data/examples/contacts.rb +4 -4
  5. data/examples/fundingSources.rb +4 -4
  6. data/examples/oauth.rb +6 -7
  7. data/examples/transactions.rb +32 -0
  8. data/lib/dwolla.rb +258 -37
  9. data/lib/dwolla/balance.rb +15 -0
  10. data/lib/dwolla/contacts.rb +22 -0
  11. data/lib/dwolla/errors/api_connection_error.rb +4 -0
  12. data/lib/dwolla/errors/api_error.rb +4 -0
  13. data/lib/dwolla/errors/authentication_error.rb +4 -0
  14. data/lib/dwolla/errors/dwolla_error.rb +20 -0
  15. data/lib/dwolla/errors/invalid_request_error.rb +10 -0
  16. data/lib/dwolla/errors/missing_parameter_error.rb +4 -0
  17. data/lib/dwolla/funding_sources.rb +65 -0
  18. data/lib/dwolla/json.rb +21 -0
  19. data/lib/dwolla/oauth.rb +43 -0
  20. data/lib/dwolla/offsite_gateway.rb +76 -0
  21. data/lib/dwolla/requests.rb +56 -0
  22. data/lib/dwolla/transactions.rb +60 -0
  23. data/lib/dwolla/users.rb +36 -0
  24. data/lib/dwolla/version.rb +1 -1
  25. metadata +37 -108
  26. data/Gemfile +0 -4
  27. data/examples/send.rb +0 -23
  28. data/lib/dwolla/client.rb +0 -56
  29. data/lib/dwolla/connection.rb +0 -47
  30. data/lib/dwolla/funding_source.rb +0 -18
  31. data/lib/dwolla/response/follow_redirects.rb +0 -44
  32. data/lib/dwolla/response/guard_server_error.rb +0 -32
  33. data/lib/dwolla/response/parse_json.rb +0 -27
  34. data/lib/dwolla/transaction.rb +0 -56
  35. data/lib/dwolla/user.rb +0 -121
  36. data/spec/dwolla/client_spec.rb +0 -51
  37. data/spec/dwolla/funding_source_spec.rb +0 -59
  38. data/spec/dwolla/response/follow_redirects_spec.rb +0 -38
  39. data/spec/dwolla/transaction_spec.rb +0 -212
  40. data/spec/dwolla/user_spec.rb +0 -292
  41. data/spec/dwolla_spec.rb +0 -19
  42. data/spec/fixtures/account_information.json +0 -13
  43. data/spec/fixtures/add_funding_source.json +0 -11
  44. data/spec/fixtures/balance.json +0 -5
  45. data/spec/fixtures/basic_information.json +0 -6
  46. data/spec/fixtures/contacts.json +0 -18
  47. data/spec/fixtures/error.json +0 -5
  48. data/spec/fixtures/register.json +0 -9
  49. data/spec/fixtures/request_transaction.json +0 -3
  50. data/spec/fixtures/send_transaction.json +0 -3
  51. data/spec/fixtures/sources.json +0 -13
  52. data/spec/spec_helper.rb +0 -10
  53. data/spec/support/helpers.rb +0 -29
data/dwolla-ruby.gemspec CHANGED
@@ -1,29 +1,24 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
2
  require "dwolla/version"
4
3
 
5
4
  Gem::Specification.new do |s|
6
- s.name = "dwolla-ruby"
7
- s.version = Dwolla::VERSION
8
- s.authors = ["Michael Schonfeld"]
9
- s.email = ["michael@dwolla.com"]
10
- s.homepage = "https://github.com/dwolla/dwolla-ruby"
11
- s.summary = %q{Official Ruby Wrapper for Dwolla's API}
12
- s.description = %q{Official Ruby Wrapper for Dwolla's API}
5
+ s.name = "dwolla-ruby"
6
+ s.version = Dwolla::VERSION
7
+ s.authors = ["Michael Schonfeld"]
8
+ s.email = ["michael@dwolla.com"]
9
+ s.homepage = "https://github.com/dwolla/dwolla-ruby"
10
+ s.summary = %q{Official Ruby Wrapper for Dwolla's API}
11
+ s.description = %q{Official Ruby Wrapper for Dwolla's API. Completely re-written based on Stripe's Ruby Bindings.}
13
12
 
14
- s.rubyforge_project = "dwolla-ruby"
13
+ s.rubyforge_project = "dwolla-ruby"
15
14
 
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
15
+ s.files = `git ls-files`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = %w{lib}
20
18
 
21
- s.add_dependency 'faraday', '= 0.7.6'
22
- s.add_dependency 'multi_json', '~> 1.3'
19
+ s.add_dependency('rest-client', '~> 1.4')
20
+ s.add_dependency('multi_json', '>= 1.0.4', '< 2')
21
+ s.add_dependency('addressable', '>= 2')
23
22
 
24
- s.add_development_dependency 'bundler'
25
- s.add_development_dependency 'rake'
26
- s.add_development_dependency 'rspec'
27
- s.add_development_dependency 'webmock'
28
- s.add_development_dependency 'simplecov'
23
+ s.add_development_dependency('rake')
29
24
  end
@@ -7,25 +7,25 @@ require 'dwolla'
7
7
  require '_keys.rb'
8
8
 
9
9
  # Instantiate a new Dwolla User client
10
- # And, Sseed a previously generated access token
11
- DwollaClient = Dwolla::Client.new($apiKey, $apiSecret)
12
- DwollaUser = Dwolla::User.me($token)
13
-
10
+ # And, seed a previously generated access token
11
+ Dwolla::token = @token
12
+ Dwolla::api_key = @api_key
13
+ Dwolla::api_secret = @api_secret
14
14
 
15
15
  # EXAMPLE 1:
16
16
  # Fetch account information for the
17
17
  # account associated with the provided
18
18
  # OAuth token
19
- pp DwollaUser.fetch
19
+ pp Dwolla::Users.get
20
20
 
21
21
 
22
22
  # EXAMPLE 2:
23
23
  # Fetch basic account information
24
24
  # for a given Dwolla ID
25
- pp DwollaClient.user('812-626-8794')
25
+ pp Dwolla::Users.get('812-626-8794')
26
26
 
27
27
 
28
28
  # EXAMPLE 3:
29
29
  # Fetch basic account information
30
30
  # for a given Email address
31
- pp DwollaClient.user('michael@dwolla.com')
31
+ pp Dwolla::Users.get('michael@dwolla.com')
data/examples/balance.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  # Include the Dwolla gem
2
2
  require 'rubygems'
3
3
  require 'pp'
4
- require '../lib/dwolla'
4
+ require 'dwolla'
5
5
 
6
6
  # Include any required keys
7
- require_relative '_keys.rb'
7
+ require '_keys.rb'
8
8
 
9
9
  # Instantiate a new Dwolla User client
10
10
  # And, seed a previously generated access token
11
- DwollaUser = Dwolla::User.me($token)
11
+ Dwolla::token = @token
12
12
 
13
13
 
14
14
  # EXAMPLE 1:
15
15
  # Get the balance of the authenticated user
16
- balance = DwollaUser.balance
17
- pp balance
16
+ balance = Dwolla::Balance.get
17
+ pp balance
data/examples/contacts.rb CHANGED
@@ -7,15 +7,15 @@ require 'dwolla'
7
7
  require '_keys.rb'
8
8
 
9
9
  # Instantiate a new Dwolla User client
10
- # And, Sseed a previously generated access token
11
- DwollaUser = Dwolla::User.me($token)
10
+ # And, seed a previously generated access token
11
+ Dwolla::token = $token
12
12
 
13
13
 
14
14
  # EXAMPLE 1:
15
15
  # Fetch last 10 contacts from the
16
16
  # account associated with the provided
17
17
  # OAuth token
18
- contacts = DwollaUser.contacts()
18
+ contacts = Dwolla::Contacts.get
19
19
  pp contacts
20
20
 
21
21
 
@@ -23,5 +23,5 @@ pp contacts
23
23
  # Search through the contacts of the
24
24
  # account associated with the provided
25
25
  # OAuth token
26
- contacts = DwollaUser.contacts(:search => 'Ben')
26
+ contacts = Dwolla::Contacts.get({:search => 'Ben'})
27
27
  pp contacts
@@ -7,20 +7,20 @@ require 'dwolla'
7
7
  require '_keys.rb'
8
8
 
9
9
  # Instantiate a new Dwolla User client
10
- # And, Sseed a previously generated access token
11
- DwollaUser = Dwolla::User.me($token)
10
+ # And, seed a previously generated access token
11
+ Dwolla::token = $token
12
12
 
13
13
 
14
14
  # EXAMPLE 1:
15
15
  # Fetch all funding sources for the
16
16
  # account associated with the provided
17
17
  # OAuth token
18
- sources = DwollaUser.funding_sources()
18
+ sources = Dwolla::FundingSources.get
19
19
  pp sources
20
20
 
21
21
 
22
22
  # EXAMPLE 2:
23
23
  # Fetch detailed information for the
24
24
  # funding source with a specific ID
25
- source = DwollaUser.funding_source('pJRq4tK38fiAeQ8xo2iH9Q==')
25
+ source = Dwolla::FundingSources.get('pJRq4tK38fiAeQ8xo2iH9Q==')
26
26
  pp source
data/examples/oauth.rb CHANGED
@@ -2,24 +2,23 @@
2
2
  require 'rubygems'
3
3
  require 'pp'
4
4
  require 'sinatra'
5
- require '../lib/dwolla'
5
+ require 'dwolla'
6
6
 
7
7
  # Include any required keys
8
- require './_keys.rb'
8
+ require '_keys.rb'
9
9
 
10
10
  # Instantiate a new Dwolla User client
11
- # And, Sseed a previously generated access token
12
- DwollaClient = Dwolla::Client.new($apiKey, $apiSecret)
11
+ Dwolla::api_key = @api_key
12
+ Dwolla::api_secret = @api_secret
13
13
 
14
14
  # Constants...
15
15
  redirect_uri = 'http://localhost:4567/oauth_return'
16
16
 
17
-
18
17
  # STEP 1:
19
18
  # Create an authentication URL
20
19
  # that the user will be redirected to
21
20
  get '/' do
22
- authUrl = DwollaClient.auth_url(redirect_uri)
21
+ authUrl = Dwolla::OAuth.get_auth_url(redirect_uri)
23
22
  "To begin the OAuth process, send the user off to <a href=\"#{authUrl}\">#{authUrl}</a>"
24
23
  end
25
24
 
@@ -30,6 +29,6 @@ end
30
29
  # a never-expiring OAuth access token
31
30
  get '/oauth_return' do
32
31
  code = params['code']
33
- token = DwollaClient.request_token(code, redirect_uri)
32
+ token = Dwolla::OAuth.get_token(code, redirect_uri)
34
33
  "Your never-expiring OAuth access token is: <b>#{token}</b>"
35
34
  end
@@ -0,0 +1,32 @@
1
+ # Include the Dwolla gem
2
+ require 'rubygems'
3
+ require 'pp'
4
+ require 'dwolla'
5
+
6
+ # Include any required keys
7
+ require '_keys.rb'
8
+
9
+ # Instantiate a new Dwolla User client
10
+ # And, seed a previously generated access token
11
+ Dwolla::token = $token
12
+
13
+
14
+ # EXAMPLE 1:
15
+ # Send money ($1.00) to a Dwolla ID
16
+ transactionId = Dwolla::Transactions.send({:destinationId => '812-626-8794', :amount => 1.00, :pin => $pin})
17
+ pp transactionId
18
+
19
+ # EXAMPLE 2:
20
+ # Send money ($1.00) to an email address, with a note
21
+ transactionId = Dwolla::Transactions.send({:destinationId => '812-626-8794', :destinationType => 'Email', :amount => 1.00, :pin => $pin, :notes => 'Everyone loves getting money'})
22
+ pp transactionId
23
+
24
+ # EXAMPLE 3:
25
+ # Get details about all recent transactions
26
+ transactions = Dwolla::Transactions.get
27
+ pp transactions
28
+
29
+ # EXAMPLE 4:
30
+ # Get details about a certain Transaction
31
+ transactionId = Dwolla::Transactions.get(transactionId)
32
+ pp transactionId
data/lib/dwolla.rb CHANGED
@@ -1,54 +1,275 @@
1
1
  # Dwolla Ruby API Wrapper
2
- # API spec at http://developers.dwolla.com
3
- require 'rubygems'
4
- require 'faraday'
2
+ # Heavily based off Stripe's Ruby Gem
3
+ # API spec at https://developers.dwolla.com
4
+ require 'openssl'
5
+ require 'rest_client'
5
6
  require 'multi_json'
7
+ require 'addressable/uri'
6
8
 
7
9
  # Version
8
- require "dwolla/version"
9
-
10
- # API operations
11
- require "dwolla/client"
12
- require "dwolla/transaction"
13
- require "dwolla/funding_source"
14
- require "dwolla/user"
10
+ require 'dwolla/version'
15
11
 
16
12
  # Resources
17
- require "dwolla/connection"
18
- require "dwolla/response/parse_json"
19
- require "dwolla/response/follow_redirects"
20
- require "dwolla/response/guard_server_error"
13
+ require 'dwolla/json'
14
+ require 'dwolla/transactions'
15
+ require 'dwolla/requests'
16
+ require 'dwolla/contacts'
17
+ require 'dwolla/users'
18
+ require 'dwolla/balance'
19
+ require 'dwolla/funding_sources'
20
+ require 'dwolla/oauth'
21
+ # require 'dwolla/offsite_gateway' // Needs more work
21
22
 
22
23
  # Errors
23
- require "dwolla/exceptions"
24
+ require 'dwolla/errors/dwolla_error'
25
+ require 'dwolla/errors/api_connection_error'
26
+ require 'dwolla/errors/api_error'
27
+ require 'dwolla/errors/missing_parameter_error'
28
+ require 'dwolla/errors/authentication_error'
29
+ require 'dwolla/errors/invalid_request_error'
24
30
 
25
31
  module Dwolla
26
- def self.endpoint=(endpoint)
27
- @@endpoint = endpoint
28
- end
32
+ @@api_key = nil
33
+ @@api_secret = nil
34
+ @@token = nil
35
+ @@api_base = 'https://www.dwolla.com/oauth/rest'
36
+ @@verify_ssl_certs = true
37
+ @@api_version = nil
38
+ @@debug = false
39
+
40
+ def self.api_key=(api_key)
41
+ @@api_key = api_key
42
+ end
43
+
44
+ def self.api_key
45
+ @@api_key
46
+ end
47
+
48
+ def self.api_secret=(api_secret)
49
+ @@api_secret = api_secret
50
+ end
51
+
52
+ def self.api_secret
53
+ @@api_secret
54
+ end
55
+
56
+ def self.debug
57
+ @@debug
58
+ end
59
+
60
+ def self.debug=(debug)
61
+ @@debug = debug
62
+ end
63
+
64
+ def self.api_version=(api_version)
65
+ @@api_version = api_version
66
+ end
67
+
68
+ def self.api_version
69
+ @@api_version
70
+ end
71
+
72
+ def self.verify_ssl_certs=(verify_ssl_certs)
73
+ @@verify_ssl_certs = verify_ssl_certs
74
+ end
75
+
76
+ def self.verify_ssl_certs
77
+ @@verify_ssl_certs
78
+ end
79
+
80
+ def self.token=(token)
81
+ @@token = token
82
+ end
83
+
84
+ def self.token
85
+ @@token
86
+ end
87
+
88
+ def self.endpoint_url(endpoint)
89
+ @@api_base + endpoint
90
+ end
91
+
92
+ def self.request(method, url, params={}, headers={}, oauth=true, parse_response=true, custom_url=false)
93
+ if oauth
94
+ raise AuthenticationError.new('No OAuth Token Provided.') unless token
95
+ params = {
96
+ :oauth_token => token
97
+ }.merge(params)
98
+ else
99
+ raise AuthenticationError.new('No App Key & Secret Provided.') unless (api_key && api_secret)
100
+ params = {
101
+ :client_id => api_key,
102
+ :client_secret => api_secret
103
+ }.merge(params)
104
+ end
105
+
106
+ if !verify_ssl_certs
107
+ $stderr.puts "WARNING: Running without SSL cert verification."
108
+ else
109
+ ssl_opts = {
110
+ :use_ssl => true
111
+ }
112
+ end
113
+
114
+ uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
115
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
116
+ ua = {
117
+ :bindings_version => Dwolla::VERSION,
118
+ :lang => 'ruby',
119
+ :lang_version => lang_version,
120
+ :platform => RUBY_PLATFORM,
121
+ :publisher => 'dwolla',
122
+ :uname => uname
123
+ }
124
+
125
+ url = self.endpoint_url(url) unless custom_url
126
+
127
+ case method.to_s.downcase.to_sym
128
+ when :get
129
+ # Make params into GET parameters
130
+ if params && params.count > 0
131
+ uri = Addressable::URI.new
132
+ uri.query_values = params
133
+ url += '?' + uri.query
134
+ end
135
+ payload = nil
136
+ else
137
+ payload = ''
138
+ end
139
+
140
+ begin
141
+ headers = { :x_dwolla_client_user_agent => Dwolla::JSON.dump(ua) }.merge(headers)
142
+ rescue => e
143
+ headers = {
144
+ :x_dwolla_client_raw_user_agent => ua.inspect,
145
+ :error => "#{e} (#{e.class})"
146
+ }.merge(headers)
147
+ end
148
+
149
+ headers = {
150
+ :user_agent => "Dwolla Ruby API Wrapper/#{Dwolla::VERSION}",
151
+ :content_type => 'application/json'
152
+ }.merge(headers)
153
+
154
+ if self.api_version
155
+ headers[:dwolla_version] = self.api_version
156
+ end
157
+
158
+ opts = {
159
+ :method => method,
160
+ :url => url,
161
+ :headers => headers,
162
+ :open_timeout => 30,
163
+ :payload => payload,
164
+ :timeout => 80
165
+ }.merge(ssl_opts)
166
+
167
+ if self.debug
168
+ puts "Firing request with options and headers:"
169
+ puts opts
170
+ puts headers
171
+ end
172
+
173
+ begin
174
+ response = execute_request(opts)
175
+ rescue SocketError => e
176
+ self.handle_restclient_error(e)
177
+ rescue NoMethodError => e
178
+ # Work around RestClient bug
179
+ if e.message =~ /\WRequestFailed\W/
180
+ e = APIConnectionError.new('Unexpected HTTP response code')
181
+ self.handle_restclient_error(e)
182
+ else
183
+ raise
184
+ end
185
+ rescue RestClient::ExceptionWithResponse => e
186
+ if rcode = e.http_code and rbody = e.http_body
187
+ self.handle_api_error(rcode, rbody)
188
+ else
189
+ self.handle_restclient_error(e)
190
+ end
191
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
192
+ self.handle_restclient_error(e)
193
+ end
194
+
195
+ rbody = response.body
196
+ rcode = response.code
197
+
198
+ resp = self.extract_json(rbody, rcode)
199
+
200
+ if parse_response
201
+ return self.parse_response(resp)
202
+ else
203
+ return resp
204
+ end
205
+ end
206
+
207
+ private
208
+
209
+ def self.execute_request(opts)
210
+ RestClient::Request.execute(opts)
211
+ end
212
+
213
+ def self.extract_json(rbody, rcode)
214
+ begin
215
+ resp = Dwolla::JSON.load(rbody)
216
+ rescue MultiJson::DecodeError
217
+ raise APIError.new("There was an error parsing Dwolla's API response: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
218
+ end
219
+
220
+ return resp
221
+ end
222
+
223
+ def self.parse_response(resp)
224
+ raise APIError.new(resp['Message']) unless resp['Success']
225
+
226
+ return resp['Response']
227
+ end
228
+
229
+ def self.handle_api_error(rcode, rbody)
230
+ begin
231
+ error_obj = Dwolla::JSON.load(rbody)
232
+ error = error_obj[:error] or raise DwollaError.new # escape from parsing
233
+ rescue MultiJson::DecodeError, DwollaError
234
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
235
+ end
29
236
 
30
- def self.endpoint
31
- @@endpoint
32
- end
237
+ case rcode
238
+ when 400, 404 then
239
+ raise invalid_request_error(error, rcode, rbody, error_obj)
240
+ when 401
241
+ raise authentication_error(error, rcode, rbody, error_obj)
242
+ else
243
+ raise api_error(error, rcode, rbody, error_obj)
244
+ end
245
+ end
33
246
 
34
- def self.user_agent=(user_agent)
35
- @@user_agent = user_agent
36
- end
247
+ def self.invalid_request_error(error, rcode, rbody, error_obj)
248
+ InvalidRequestError.new(error[:message], error[:param], rcode, rbody, error_obj)
249
+ end
37
250
 
38
- def self.user_agent
39
- @@user_agent
40
- end
251
+ def self.authentication_error(error, rcode, rbody, error_obj)
252
+ AuthenticationError.new(error[:message], rcode, rbody, error_obj)
253
+ end
41
254
 
42
- def self.debugging?
43
- !!@@debug
44
- end
255
+ def self.api_error(error, rcode, rbody, error_obj)
256
+ APIError.new(error[:message], rcode, rbody, error_obj)
257
+ end
45
258
 
46
- def self.debug=(debug)
47
- @@debug = debug
48
- end
259
+ def self.handle_restclient_error(e)
260
+ case e
261
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
262
+ message = "Could not connect to Dwolla (#{@@api_base}). Please check your internet connection and try again. If this problem persists, you should check Dwolla's service status at https://twitter.com/Dwolla, or let us know at support@Dwolla.com."
263
+ when RestClient::SSLCertificateNotVerified
264
+ message = "Could not verify Dwolla's SSL certificate. If this problem persists, let us know at support@dwolla.com."
265
+ when SocketError
266
+ message = "Unexpected error communicating when trying to connect to Dwolla. If this problem persists, let us know at support@dwolla.com."
267
+ else
268
+ message = "Unexpected error communicating with Dwolla. If this problem persists, let us know at support@dwolla.com."
269
+ end
49
270
 
50
- self.debug = false
51
- self.user_agent = "Dwolla Ruby Wrapper"
52
- self.endpoint = "https://www.dwolla.com/oauth/rest"
53
- end
271
+ message += "\n\n(Network error: #{e.message})"
54
272
 
273
+ raise APIConnectionError.new(message)
274
+ end
275
+ end