dwolla-ruby 1.1.0 → 2.0.0

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