dwolla_v2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +164 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/dwolla_v2.gemspec +29 -0
  12. data/lib/dwolla_v2.rb +50 -0
  13. data/lib/dwolla_v2/auth.rb +58 -0
  14. data/lib/dwolla_v2/client.rb +72 -0
  15. data/lib/dwolla_v2/error.rb +37 -0
  16. data/lib/dwolla_v2/errors/access_denied_error.rb +4 -0
  17. data/lib/dwolla_v2/errors/bad_request_error.rb +4 -0
  18. data/lib/dwolla_v2/errors/expired_access_token_error.rb +4 -0
  19. data/lib/dwolla_v2/errors/forbidden_error.rb +4 -0
  20. data/lib/dwolla_v2/errors/invalid_access_token_error.rb +4 -0
  21. data/lib/dwolla_v2/errors/invalid_account_status_error.rb +4 -0
  22. data/lib/dwolla_v2/errors/invalid_application_status_error.rb +4 -0
  23. data/lib/dwolla_v2/errors/invalid_client_error.rb +4 -0
  24. data/lib/dwolla_v2/errors/invalid_credentials_error.rb +4 -0
  25. data/lib/dwolla_v2/errors/invalid_grant_error.rb +4 -0
  26. data/lib/dwolla_v2/errors/invalid_request_error.rb +4 -0
  27. data/lib/dwolla_v2/errors/invalid_resource_state_error.rb +4 -0
  28. data/lib/dwolla_v2/errors/invalid_scope_error.rb +4 -0
  29. data/lib/dwolla_v2/errors/invalid_scopes_error.rb +4 -0
  30. data/lib/dwolla_v2/errors/invalid_version_error.rb +4 -0
  31. data/lib/dwolla_v2/errors/method_not_allowed_error.rb +4 -0
  32. data/lib/dwolla_v2/errors/not_found_error.rb +4 -0
  33. data/lib/dwolla_v2/errors/request_timeout_error.rb +4 -0
  34. data/lib/dwolla_v2/errors/server_error.rb +4 -0
  35. data/lib/dwolla_v2/errors/temporarily_unavailable_error.rb +4 -0
  36. data/lib/dwolla_v2/errors/unauthorized_client_error.rb +4 -0
  37. data/lib/dwolla_v2/errors/unsupported_grant_type_error.rb +4 -0
  38. data/lib/dwolla_v2/errors/unsupported_response_type_error.rb +4 -0
  39. data/lib/dwolla_v2/errors/validation_error.rb +4 -0
  40. data/lib/dwolla_v2/middleware/handle_errors.rb +13 -0
  41. data/lib/dwolla_v2/middleware/symbolize_response_body.rb +13 -0
  42. data/lib/dwolla_v2/portal.rb +12 -0
  43. data/lib/dwolla_v2/response.rb +24 -0
  44. data/lib/dwolla_v2/token.rb +72 -0
  45. data/lib/dwolla_v2/util.rb +19 -0
  46. data/lib/dwolla_v2/version.rb +3 -0
  47. metadata +173 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 12cdebfad904523e346289a3e5dad7372c765a4a
4
+ data.tar.gz: 9238497f4896c30556a6e276eef2b7174e6d0455
5
+ SHA512:
6
+ metadata.gz: 69d58601f8b95ecbcb187f3cd85f3a4e7fb7ac03f4abde266adbb868055c801cc04725de4d3101ada58de9d536028de8a2a44936d09c70ffdac84540cd059725
7
+ data.tar.gz: 400ec01a2cc61f0496ba3f307aa62280a9172a6652b00392de2f7e5ee40242a22ee7bcc7e8153972556980d0af9cf4c5092e7056bb0a29b7d8a8ef217c61c3f4
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.7
6
+ - 2.2.0
7
+ - ruby-head
8
+ - rbx-2
9
+ - jruby
10
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dwolla_v2.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Stephen Ausman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,164 @@
1
+ # DwollaV2
2
+
3
+ ![Build Status](https://travis-ci.org/Dwolla/dwolla-v2-ruby.svg)
4
+
5
+ Dwolla V2 Ruby client. For the V1 Ruby client see [Dwolla/dwolla-ruby](https://github.com/Dwolla/dwolla-ruby).
6
+
7
+ [API Documentation](https://docsv2.dwolla.com)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'dwolla_v2', '~> 0.1'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install dwolla_v2
24
+
25
+ ## Usage
26
+
27
+ #### Creating a client
28
+
29
+ ```ruby
30
+ $dwolla = DwollaV2::Client.new(id: "CLIENT_ID", secret: "CLIENT_SECRET") do |optional_config|
31
+ optional_config.environment = :sandbox
32
+ optional_config.on_grant do |token|
33
+ YourTokenData.create! token
34
+ end
35
+ optional_config.faraday do |faraday|
36
+ faraday.response :logger
37
+ faraday.adapter Faraday.default_adapter
38
+ end
39
+ end
40
+ ```
41
+
42
+ #### Authorization
43
+
44
+ Get an application token:
45
+
46
+ ```ruby
47
+ $dwolla.auths.client scope: "ManagerCustomers|Funding"
48
+ ```
49
+
50
+ Get an account token:
51
+
52
+ ```ruby
53
+ class YourAuthController < ApplicationController
54
+ def authorize
55
+ redirect_to auth.url
56
+ end
57
+
58
+ def callback
59
+ token = auth.callback params
60
+ session[:account_id] = token.account_id
61
+ end
62
+
63
+ private
64
+
65
+ def auth
66
+ $dwolla.auths.new redirect_uri: "https://yoursite.com/callback",
67
+ scope: "ManagerCustomers|Funding"
68
+ end
69
+ end
70
+ ```
71
+
72
+ Refresh a token:
73
+
74
+ ```ruby
75
+ token = $dwolla.auths.refresh expired_token
76
+ ```
77
+
78
+ Initialize a token:
79
+
80
+ ```ruby
81
+ token_data = YourTokenData.find_by account_id: "ACCOUNT_ID"
82
+ token = $dwolla.tokens.new token_data
83
+ ```
84
+
85
+ #### Making requests
86
+
87
+ ```ruby
88
+ token.get "/resource", foo: "bar"
89
+ token.post "/resource", foo: "bar"
90
+ token.post "/resource", foo: Faraday.UploadIO.new("/path/to/bar.png", "image/png")
91
+ token.put "/resource", foo: "bar"
92
+ token.put "/resource", foo: Faraday.UploadIO.new("/path/to/bar.png", "image/png")
93
+ token.delete "/resource"
94
+ ```
95
+
96
+ In parallel:
97
+
98
+ ```ruby
99
+ foo, bar = nil
100
+
101
+ token.in_parallel do
102
+ foo = token.get "/foo" # => nil
103
+ bar = token.get "/bar" # => nil
104
+ end
105
+
106
+ foo # => { ... }
107
+ bar # => { ... }
108
+ ```
109
+
110
+ Accessing response headers:
111
+
112
+ ```ruby
113
+ customer = token.post "/customers", customer_params
114
+ customer = token.get customer.headers[:location]
115
+ ```
116
+
117
+ #### Errors
118
+
119
+ All errors inherit from `DwollaV2::Error`
120
+
121
+ OAuth errors have `error`, `error_description`, and `error_uri` attributes.
122
+
123
+ Dwolla API errors have `code`, `message`, `_links`, and `_embedded` attributes.
124
+
125
+ **Error list:**
126
+
127
+ - `DwollaV2::AccessDeniedError`
128
+ - `DwollaV2::InvalidCredentialsError`
129
+ - `DwollaV2::NotFoundError`
130
+ - `DwollaV2::BadRequestError`
131
+ - `DwollaV2::InvalidGrantError`
132
+ - `DwollaV2::RequestTimeoutError`
133
+ - `DwollaV2::ExpiredAccessTokenError`
134
+ - `DwollaV2::InvalidRequestError`
135
+ - `DwollaV2::ServerError`
136
+ - `DwollaV2::ForbiddenError`
137
+ - `DwollaV2::InvalidResourceStateError`
138
+ - `DwollaV2::TemporarilyUnavailableError`
139
+ - `DwollaV2::InvalidAccessTokenError`
140
+ - `DwollaV2::InvalidScopeError`
141
+ - `DwollaV2::UnauthorizedClientError`
142
+ - `DwollaV2::InvalidAccount_statusError`
143
+ - `DwollaV2::InvalidScopesError`
144
+ - `DwollaV2::UnsupportedGrantTypeError`
145
+ - `DwollaV2::InvalidApplicationStatusError`
146
+ - `DwollaV2::InvalidVersionError`
147
+ - `DwollaV2::UnsupportedResponseTypeError`
148
+ - `DwollaV2::InvalidClientError`
149
+ - `DwollaV2::MethodNotAllowedError`
150
+ - `DwollaV2::ValidationError`
151
+
152
+ ## Development
153
+
154
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
155
+
156
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
157
+
158
+ ## Contributing
159
+
160
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Dwolla/dwolla-v2-ruby.
161
+
162
+ ## License
163
+
164
+ The gem is available as open source under the terms of the [MIT License](https://github.com/Dwolla/dwolla-v2-ruby).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dwolla_v2"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "dwolla_v2/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dwolla_v2"
8
+ spec.version = DwollaV2::VERSION
9
+ spec.authors = ["Stephen Ausman"]
10
+ spec.email = ["stephen@dwolla.com"]
11
+
12
+ spec.summary = "Dwolla V2 Ruby client"
13
+ spec.description = "Dwolla V2 Ruby client"
14
+ spec.homepage = "https://github.com/Dwolla/dwolla-v2-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "webmock", "~> 1.22"
26
+
27
+ spec.add_dependency "faraday", "~> 0.9"
28
+ spec.add_dependency "faraday_middleware", "~> 0.10"
29
+ end
@@ -0,0 +1,50 @@
1
+ require "base64"
2
+ require "uri"
3
+ require "json"
4
+ require "forwardable"
5
+
6
+ require "faraday"
7
+ require "faraday_middleware"
8
+
9
+ require "dwolla_v2/version"
10
+ require "dwolla_v2/client"
11
+ require "dwolla_v2/portal"
12
+ require "dwolla_v2/auth"
13
+ require "dwolla_v2/token"
14
+ require "dwolla_v2/response"
15
+ require "dwolla_v2/error"
16
+ require "dwolla_v2/util"
17
+
18
+ require "dwolla_v2/middleware/symbolize_response_body"
19
+ require "dwolla_v2/middleware/handle_errors"
20
+
21
+ # OAuth errors https://tools.ietf.org/html/rfc6749
22
+ require "dwolla_v2/errors/invalid_request_error"
23
+ require "dwolla_v2/errors/invalid_client_error"
24
+ require "dwolla_v2/errors/invalid_grant_error"
25
+ require "dwolla_v2/errors/invalid_scope_error"
26
+ require "dwolla_v2/errors/unauthorized_client_error"
27
+ require "dwolla_v2/errors/access_denied_error"
28
+ require "dwolla_v2/errors/unsupported_response_type_error"
29
+ require "dwolla_v2/errors/server_error"
30
+ require "dwolla_v2/errors/temporarily_unavailable_error"
31
+ require "dwolla_v2/errors/unsupported_grant_type_error"
32
+
33
+ # Dwolla errors https://docsv2.dwolla.com/#errors
34
+ require "dwolla_v2/errors/bad_request_error"
35
+ require "dwolla_v2/errors/validation_error"
36
+ require "dwolla_v2/errors/invalid_credentials_error"
37
+ require "dwolla_v2/errors/invalid_access_token_error"
38
+ require "dwolla_v2/errors/expired_access_token_error"
39
+ require "dwolla_v2/errors/invalid_account_status_error"
40
+ require "dwolla_v2/errors/invalid_application_status_error"
41
+ require "dwolla_v2/errors/invalid_scopes_error"
42
+ require "dwolla_v2/errors/forbidden_error"
43
+ require "dwolla_v2/errors/invalid_resource_state_error"
44
+ require "dwolla_v2/errors/not_found_error"
45
+ require "dwolla_v2/errors/method_not_allowed_error"
46
+ require "dwolla_v2/errors/invalid_version_error"
47
+ require "dwolla_v2/errors/request_timeout_error"
48
+
49
+ module DwollaV2
50
+ end
@@ -0,0 +1,58 @@
1
+ module DwollaV2
2
+ class Auth
3
+ attr_reader :client, :redirect_uri, :scope, :state
4
+
5
+ def self.client client, params = {}
6
+ request_token client, {:grant_type => :client_credentials}.merge(params)
7
+ end
8
+
9
+ def self.refresh client, token, params = {}
10
+ raise ArgumentError.new "invalid refresh_token" unless token[:refresh_token].is_a? String
11
+ request_token client, {:grant_type => :refresh_token, :refresh_token => token[:refresh_token]}.merge(params)
12
+ end
13
+
14
+ def initialize client, params = {}
15
+ @client = client
16
+ @redirect_uri = params[:redirect_uri]
17
+ @scope = params[:scope]
18
+ @state = params[:state]
19
+ freeze
20
+ end
21
+
22
+ def url
23
+ "#{client.auth_url}?#{URI.encode_www_form(query)}"
24
+ end
25
+
26
+ def callback params
27
+ raise ArgumentError.new "state does not match" if params[:state] != state
28
+ Error.raise! params if params[:error]
29
+ raise ArgumentError.new "code is required" unless params[:code].is_a? String
30
+ params = {:code => params[:code], :redirect_uri => redirect_uri}.reject {|k,v| v.nil? }
31
+ self.class.request_token client, {:grant_type => :authorization_code}.merge(params)
32
+ end
33
+
34
+ private
35
+
36
+ def query
37
+ {
38
+ :response_type => :code,
39
+ :client_id => client.id,
40
+ :redirect_uri => redirect_uri,
41
+ :scope => scope,
42
+ :state => state
43
+ }.reject {|k,v| v.nil? }
44
+ end
45
+
46
+ def self.request_token client, params
47
+ res = client.conn.post client.token_url, params
48
+ res_body = Util.deep_symbolize_keys res.body
49
+ if res_body[:error]
50
+ Error.raise! res_body
51
+ else
52
+ token = Token.new client, res_body
53
+ client.on_grant.call token unless client.on_grant.nil?
54
+ token
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,72 @@
1
+ module DwollaV2
2
+ class Client
3
+ ENVIRONMENTS = {
4
+ :default => {
5
+ :auth_url => "https://www.dwolla.com/oauth/v2/authenticate",
6
+ :token_url => "https://www.dwolla.com/oauth/v2/token",
7
+ :api_url => "https://api.dwolla.com"
8
+ },
9
+ :sandbox => {
10
+ :auth_url => "https://uat.dwolla.com/oauth/v2/authenticate",
11
+ :token_url => "https://uat.dwolla.com/oauth/v2/token",
12
+ :api_url => "https://api-uat.dwolla.com"
13
+ }
14
+ }
15
+
16
+ attr_reader :id, :secret, :auths, :tokens
17
+
18
+ def initialize opts
19
+ raise ArgumentError.new "id is required" unless opts[:id].is_a? String
20
+ raise ArgumentError.new "secret is required" unless opts[:secret].is_a? String
21
+ @id = opts[:id]
22
+ @secret = opts[:secret]
23
+ yield self if block_given?
24
+ conn
25
+ @auths = Portal.new self, Auth
26
+ @tokens = Portal.new self, Token
27
+ freeze
28
+ end
29
+
30
+ def environment= env
31
+ raise ArgumentError.new "invalid environment" unless ENVIRONMENTS.has_key? env
32
+ @environment = env
33
+ end
34
+
35
+ def environment env = nil
36
+ self.environment = env unless env.nil?
37
+ @environment || :default
38
+ end
39
+
40
+ def on_grant &callback
41
+ @on_grant = callback if callback
42
+ @on_grant
43
+ end
44
+
45
+ def faraday &block
46
+ @faraday = block if block
47
+ @faraday
48
+ end
49
+
50
+ def conn
51
+ @conn ||= Faraday.new do |f|
52
+ f.request :basic_auth, id, secret
53
+ f.request :url_encoded
54
+ f.response :json, :content_type => /\bjson$/
55
+ faraday.call(f) if faraday
56
+ f.adapter Faraday.default_adapter unless faraday
57
+ end
58
+ end
59
+
60
+ def auth_url
61
+ ENVIRONMENTS[environment][:auth_url]
62
+ end
63
+
64
+ def token_url
65
+ ENVIRONMENTS[environment][:token_url]
66
+ end
67
+
68
+ def api_url
69
+ ENVIRONMENTS[environment][:api_url]
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,37 @@
1
+ module DwollaV2
2
+ class Error < StandardError
3
+ attr_reader :error, :error_description, :error_uri, :code, :message, :_links, :_embedded
4
+
5
+ def self.raise! error
6
+ raise self.new unless error.is_a? Hash
7
+ if klass = error_class(error[:error] || error[:code])
8
+ raise klass.new error
9
+ else
10
+ raise self.new error
11
+ end
12
+ end
13
+
14
+ def initialize params = {}
15
+ @error = params[:error]
16
+ @error_description = params[:error_description]
17
+ @error_uri = params[:error_uri]
18
+ @code = params[:code]
19
+ @message = params[:message]
20
+ @_links = params[:_links]
21
+ @_embedded = params[:_embedded]
22
+ end
23
+
24
+ def to_s
25
+ [:error, :error_description, :error_uri, :code, :message, :_links, :_embedded]
26
+ .map {|a| "#{a}: \"#{public_send(a)}\"" if public_send(a) }
27
+ .compact
28
+ .join ", "
29
+ end
30
+
31
+ private
32
+
33
+ def self.error_class error_code
34
+ DwollaV2.const_get "#{Util.classify(error_code).chomp("Error")}Error" rescue false
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class AccessDeniedError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class BadRequestError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class ExpiredAccessTokenError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class ForbiddenError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidAccessTokenError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidAccountStatusError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidApplicationStatusError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidClientError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidCredentialsError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidGrantError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidRequestError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidResourceStateError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidScopeError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidScopesError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class InvalidVersionError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class MethodNotAllowedError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class NotFoundError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class RequestTimeoutError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class ServerError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class TemporarilyUnavailableError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class UnauthorizedClientError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class UnsupportedGrantTypeError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class UnsupportedResponseTypeError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DwollaV2
2
+ class ValidationError < Error
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ module DwollaV2
2
+ class HandleErrors
3
+ def initialize app
4
+ @app = app
5
+ end
6
+
7
+ def call request_env
8
+ @app.call(request_env).on_complete do |response_env|
9
+ Error.raise!(response_env.body) if response_env.status >= 400
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module DwollaV2
2
+ class SymbolizeResponseBody
3
+ def initialize app
4
+ @app = app
5
+ end
6
+
7
+ def call request_env
8
+ @app.call(request_env).on_complete do |response_env|
9
+ response_env.body = Util.deep_symbolize_keys(response_env.body)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module DwollaV2
2
+ class Portal
3
+ def initialize parent, klass
4
+ @parent = parent
5
+ @klass = klass
6
+ end
7
+
8
+ def method_missing method, *args, &block
9
+ @klass.public_send method, @parent, *args, &block
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module DwollaV2
2
+ class Response
3
+ extend Forwardable
4
+
5
+ DO_NOT_FORWARD = [:method_missing, :object_id, :__send__]
6
+
7
+ delegate instance_methods.reject {|m| DO_NOT_FORWARD.include?(m) } => :response_body
8
+ delegate [:status, :headers] => :@response
9
+
10
+ def initialize response
11
+ @response = response
12
+ end
13
+
14
+ def method_missing method, *args, &block
15
+ response_body.send method, *args, &block
16
+ end
17
+
18
+ private
19
+
20
+ def response_body
21
+ @response.body
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,72 @@
1
+ module DwollaV2
2
+ class Token
3
+ extend Forwardable
4
+
5
+ HTTP_METHODS = [:get, :post, :put, :patch, :delete]
6
+
7
+ attr_reader :client, :access_token, :refresh_token, :expires_in, :scope, :app_id, :account_id
8
+
9
+ delegate [:in_parallel] => :@conn
10
+
11
+ def initialize client, params
12
+ @client = client
13
+ @access_token = params[:access_token]
14
+ @refresh_token = params[:refresh_token]
15
+ @expires_in = params[:expires_in]
16
+ @scope = params[:scope]
17
+ @app_id = params[:app_id]
18
+ @account_id = params[:account_id]
19
+ conn
20
+ freeze
21
+ end
22
+
23
+ def [] key
24
+ instance_variable_get :"@#{key}"
25
+ end
26
+
27
+ def stringify_keys
28
+ {
29
+ "access_token" => access_token,
30
+ "refresh_token" => refresh_token,
31
+ "expires_in" => expires_in,
32
+ "scope" => scope,
33
+ "app_id" => app_id,
34
+ "account_id" => account_id
35
+ }.reject {|k,v| v.nil? }
36
+ end
37
+
38
+ HTTP_METHODS.each do |method|
39
+ define_method(method) do |path, params = nil|
40
+ full_url = self.class.full_url client, path
41
+ Response.new conn.public_send(method, full_url, params)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def conn
48
+ @conn ||= Faraday.new do |f|
49
+ f.authorization :Bearer, access_token if access_token
50
+ f.headers[:accept] = "application/vnd.dwolla.v1.hal+json"
51
+ f.request :multipart
52
+ f.request :json
53
+ f.use HandleErrors
54
+ f.use SymbolizeResponseBody
55
+ f.response :json, :content_type => /\bjson$/
56
+ client.faraday.call(f) if client.faraday
57
+ f.adapter Faraday.default_adapter unless client.faraday
58
+ end
59
+ end
60
+
61
+ def self.full_url client, path
62
+ path = path[:_links][:self][:href] if path.is_a? Hash
63
+ if path.start_with? client.api_url
64
+ path
65
+ elsif path.start_with? "/"
66
+ client.api_url + path
67
+ else
68
+ "#{client.api_url}/#{path}"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module DwollaV2
2
+ module Util
3
+ def self.deep_symbolize_keys obj
4
+ if obj.is_a? Hash
5
+ Hash[obj.map{|k,v| [k.to_sym, deep_symbolize_keys(v)] }]
6
+ elsif obj.is_a? Array
7
+ obj.map {|i| deep_symbolize_keys(i) }
8
+ else
9
+ obj
10
+ end
11
+ end
12
+
13
+ def self.classify str
14
+ str.split("_").map do |i|
15
+ i.sub(/^(.)/) { $1.capitalize }
16
+ end.join
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module DwollaV2
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dwolla_v2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Ausman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.22'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.22'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.9'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday_middleware
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ description: Dwolla V2 Ruby client
98
+ email:
99
+ - stephen@dwolla.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - bin/console
112
+ - bin/setup
113
+ - dwolla_v2.gemspec
114
+ - lib/dwolla_v2.rb
115
+ - lib/dwolla_v2/auth.rb
116
+ - lib/dwolla_v2/client.rb
117
+ - lib/dwolla_v2/error.rb
118
+ - lib/dwolla_v2/errors/access_denied_error.rb
119
+ - lib/dwolla_v2/errors/bad_request_error.rb
120
+ - lib/dwolla_v2/errors/expired_access_token_error.rb
121
+ - lib/dwolla_v2/errors/forbidden_error.rb
122
+ - lib/dwolla_v2/errors/invalid_access_token_error.rb
123
+ - lib/dwolla_v2/errors/invalid_account_status_error.rb
124
+ - lib/dwolla_v2/errors/invalid_application_status_error.rb
125
+ - lib/dwolla_v2/errors/invalid_client_error.rb
126
+ - lib/dwolla_v2/errors/invalid_credentials_error.rb
127
+ - lib/dwolla_v2/errors/invalid_grant_error.rb
128
+ - lib/dwolla_v2/errors/invalid_request_error.rb
129
+ - lib/dwolla_v2/errors/invalid_resource_state_error.rb
130
+ - lib/dwolla_v2/errors/invalid_scope_error.rb
131
+ - lib/dwolla_v2/errors/invalid_scopes_error.rb
132
+ - lib/dwolla_v2/errors/invalid_version_error.rb
133
+ - lib/dwolla_v2/errors/method_not_allowed_error.rb
134
+ - lib/dwolla_v2/errors/not_found_error.rb
135
+ - lib/dwolla_v2/errors/request_timeout_error.rb
136
+ - lib/dwolla_v2/errors/server_error.rb
137
+ - lib/dwolla_v2/errors/temporarily_unavailable_error.rb
138
+ - lib/dwolla_v2/errors/unauthorized_client_error.rb
139
+ - lib/dwolla_v2/errors/unsupported_grant_type_error.rb
140
+ - lib/dwolla_v2/errors/unsupported_response_type_error.rb
141
+ - lib/dwolla_v2/errors/validation_error.rb
142
+ - lib/dwolla_v2/middleware/handle_errors.rb
143
+ - lib/dwolla_v2/middleware/symbolize_response_body.rb
144
+ - lib/dwolla_v2/portal.rb
145
+ - lib/dwolla_v2/response.rb
146
+ - lib/dwolla_v2/token.rb
147
+ - lib/dwolla_v2/util.rb
148
+ - lib/dwolla_v2/version.rb
149
+ homepage: https://github.com/Dwolla/dwolla-v2-ruby
150
+ licenses:
151
+ - MIT
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.5.1
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Dwolla V2 Ruby client
173
+ test_files: []