dwolla_v2 0.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.
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: []