old_plaid 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/PUBLISHING.md +21 -0
- data/README.md +125 -0
- data/Rakefile +8 -0
- data/lib/old_plaid.rb +100 -0
- data/lib/old_plaid/config.rb +19 -0
- data/lib/old_plaid/connection.rb +109 -0
- data/lib/old_plaid/errors.rb +27 -0
- data/lib/old_plaid/models/account.rb +24 -0
- data/lib/old_plaid/models/category.rb +17 -0
- data/lib/old_plaid/models/exchange_token_response.rb +11 -0
- data/lib/old_plaid/models/info.rb +12 -0
- data/lib/old_plaid/models/institution.rb +22 -0
- data/lib/old_plaid/models/transaction.rb +24 -0
- data/lib/old_plaid/models/user.rb +189 -0
- data/lib/old_plaid/version.rb +3 -0
- data/old_plaid.gemspec +28 -0
- data/spec/old_plaid_spec.rb +263 -0
- data/spec/plaid/config_spec.rb +67 -0
- data/spec/plaid/connection_spec.rb +191 -0
- data/spec/plaid/error_spec.rb +10 -0
- data/spec/plaid/models/account_spec.rb +37 -0
- data/spec/plaid/models/category_spec.rb +16 -0
- data/spec/plaid/models/institution_spec.rb +19 -0
- data/spec/plaid/models/transaction_spec.rb +28 -0
- data/spec/plaid/models/user_spec.rb +172 -0
- data/spec/spec_helper.rb +14 -0
- metadata +170 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e23d2716fc03c0effd63bce96fc15cbb22e8eae1
|
4
|
+
data.tar.gz: 6151243d04e3526aede1dc2230ac7dbfd7a5c0f8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f3756351df4b41b7f3618a88b6a6d7bd06eac8145f2e8451c9f6722f4eba3f44eeb8438b85d9528d1c70fc29e244e859c8fd3cea35bec0e3a3378fddd87f2d2
|
7
|
+
data.tar.gz: f5c5ea2875da40efbee3755d9dd909ea7284f8c0e44e9fca9672d15143c874051c8e6bd7a092fa959d90a4ed7fa5ac12f5b3eac8b2e8d937b94fde9016dc7bb2
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Justin Crites
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/PUBLISHING.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Publishing
|
2
|
+
|
3
|
+
The module is published to the [rubygems.org][1] under the gem name [old_plaid][2].
|
4
|
+
|
5
|
+
The publishing process is handled by [rake][3].
|
6
|
+
|
7
|
+
After updating the package version, run:
|
8
|
+
|
9
|
+
```console
|
10
|
+
$ rake spec
|
11
|
+
$ rake build
|
12
|
+
$ rake release
|
13
|
+
```
|
14
|
+
|
15
|
+
See the [semantic versioning][4] guidelines to determine what level of release to publish.
|
16
|
+
|
17
|
+
[1]: https://rubygems.org
|
18
|
+
[2]: https://rubygems.org/gems/old_plaid
|
19
|
+
[3]: https://github.com/ruby/rake
|
20
|
+
[4]: http://semver.org
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# OldPlaid [![Build Status](https://travis-ci.org/plaid/plaid-ruby.svg?branch=release_v_1.0.0)](https://travis-ci.org/plaid/plaid-ruby) [![Gem Version](https://badge.fury.io/rb/plaid.svg)](http://badge.fury.io/rb/plaid)
|
2
|
+
|
3
|
+
Ruby bindings for the OldPlaid API
|
4
|
+
|
5
|
+
## Notes
|
6
|
+
|
7
|
+
This version is a beta version that contains failing tests for the new 'info' endpoint. While these have been tested individually on real accounts the tests here will fail with the test accounts supplied. These will be updated soon with test credentials.
|
8
|
+
|
9
|
+
Latest stable version: **1.7.1**
|
10
|
+
|
11
|
+
This version removes the need to use 'type' in each additional call.
|
12
|
+
|
13
|
+
**Warning: If you have been using any version < 1 please switch to the correct branch (V0.1.6). Installing without specifying a version from RubyGems results in V1.1 build. **
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'old_plaid'
|
21
|
+
```
|
22
|
+
|
23
|
+
And install
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it system wide as:
|
28
|
+
|
29
|
+
$ gem install old_plaid
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
Please read the great documentation at http://plaid.com/docs/ for more information.
|
34
|
+
|
35
|
+
### Configuring OldPlaid
|
36
|
+
Configure the gem with your customer id, secret key, and the environment path you would like to use.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
OldPlaid.config do |p|
|
40
|
+
p.customer_id = 'OldPlaid provided customer ID here'
|
41
|
+
p.secret = 'OldPlaid provided secret key here'
|
42
|
+
p.environment_location = 'URL for the development or production environment'
|
43
|
+
# i.e. 'https://tartan.plaid.com/' for development, or
|
44
|
+
# 'https://api.plaid.com/' for production
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
### Creating a new OldPlaid User
|
49
|
+
Authenticate a user to your desired level of api access (auth / connect).
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
user = OldPlaid.add_user('auth', 'plaid_test', 'plaid_good', 'wells')
|
53
|
+
```
|
54
|
+
|
55
|
+
If the authentication requires a pin, you can pass it in as the fifth argument:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
user = OldPlaid.add_user('auth', 'plaid_test', 'plaid_good', 'usaa', '1234')
|
59
|
+
```
|
60
|
+
|
61
|
+
To add options such as `login_only` or `webhooks`, use the sixth argument:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
user = OldPlaid.add_user('auth', 'plaid_test', 'plaid_good', 'wells', nil, { login_only: true, webhooks: 'https://example.org/callbacks/plaid')
|
65
|
+
```
|
66
|
+
|
67
|
+
### Restoring a OldPlaid User using an access token
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
user = OldPlaid.set_user('access_token')
|
71
|
+
```
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
user = OldPlaid.set_user('access_token', ['connect'])
|
75
|
+
```
|
76
|
+
|
77
|
+
### Exchanging a Link public_token for a OldPlaid access_token
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
OldPlaid.config do |p|
|
81
|
+
p.customer_id = 'test_id'
|
82
|
+
p.secret = 'test_secret'
|
83
|
+
p.environment_location = 'https://tartan.plaid.com'
|
84
|
+
end
|
85
|
+
|
86
|
+
# Exchange a Link public_token for a OldPlaid access_token
|
87
|
+
exchangeTokenResponse = OldPlaid.exchange_token('test,chase,connected')
|
88
|
+
# Optionally include an account_id
|
89
|
+
exchangeTokenResponse = OldPlaid.exchange_token('test,chase,connected', 'account_id')
|
90
|
+
|
91
|
+
# Use the API access_token to initialize a user
|
92
|
+
# Note: This example assumes you are using Link with the "auth" product
|
93
|
+
user = OldPlaid.set_user(exchangeTokenResponse.access_token, ['auth'])
|
94
|
+
|
95
|
+
# Retrieve the user's accounts
|
96
|
+
user.get('auth')
|
97
|
+
|
98
|
+
# Print the name of each account
|
99
|
+
user.accounts.each { |account| print account.meta['name'] + "\n"}
|
100
|
+
```
|
101
|
+
|
102
|
+
## Semantic Versioning
|
103
|
+
|
104
|
+
Methods marked with `API: public` are officially supported by the gem maintainers. Since
|
105
|
+
we are using semantic versioning (http://semver.org/spec/v2.0.0.html), the maintainers are
|
106
|
+
committed to backwards-compatibility support for these API calls when we update the Minor
|
107
|
+
version. So for example, going from version 1.4.x to 1.5.x will not change these public
|
108
|
+
API calls.
|
109
|
+
|
110
|
+
However, we may change these method signatures or even the gem architecture when updating
|
111
|
+
the Major number. For example, we have some breaking changes in mind with version 2.0
|
112
|
+
|
113
|
+
Methods marked with `API: semi-private` are used internally for consistency. While it is
|
114
|
+
possible to monkey-patch against them for your own use, the maintainers make no guarantees
|
115
|
+
on backwards compatibility.
|
116
|
+
|
117
|
+
## Learn More
|
118
|
+
|
119
|
+
Learn about the full functionality of the library on our [Wiki](https://github.com/plaid/plaid-ruby/wiki)
|
120
|
+
|
121
|
+
## Contribute
|
122
|
+
|
123
|
+
We highly encourage helping out with the gem. Either adding more tests, building new helper classes, fixing bugs, or anything to increase overall quality.
|
124
|
+
|
125
|
+
Learn more about best practices, submitting a pull request, and rules for the build on our [Wiki](https://github.com/plaid/plaid-ruby/wiki/Contribute!)
|
data/Rakefile
ADDED
data/lib/old_plaid.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'old_plaid/version'
|
2
|
+
require 'old_plaid/config'
|
3
|
+
require 'old_plaid/errors'
|
4
|
+
|
5
|
+
require 'old_plaid/models/user'
|
6
|
+
require 'old_plaid/models/institution'
|
7
|
+
require 'old_plaid/models/category'
|
8
|
+
require 'old_plaid/models/exchange_token_response'
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
module OldPlaid
|
13
|
+
autoload :Connection, 'old_plaid/connection'
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Configures the gem with the public, private, and environment vars
|
17
|
+
include Configure
|
18
|
+
|
19
|
+
# API: public
|
20
|
+
# Use this to create a new OldPlaid user
|
21
|
+
# Required parameters:
|
22
|
+
# api_level, username, password, type
|
23
|
+
# TODO: Rename this to something more descriptive for 2.0, such as 'create_user`
|
24
|
+
def add_user(api_level, username, password, type, pin = nil, options = nil)
|
25
|
+
payload = { username: username, password: password, type: type }
|
26
|
+
|
27
|
+
payload[:pin] = pin if pin
|
28
|
+
payload[:options] = options.is_a?(Hash) ? JSON.generate(options) : options if options
|
29
|
+
|
30
|
+
res = Connection.post(api_level, payload)
|
31
|
+
User.build(res, api_level)
|
32
|
+
end
|
33
|
+
|
34
|
+
# API: public
|
35
|
+
# Exchange a OldPlaid Link public_token for a OldPlaid access_token
|
36
|
+
# Required parameters:
|
37
|
+
# public_token
|
38
|
+
# account_id (optional)
|
39
|
+
def exchange_token(public_token, account_id = nil)
|
40
|
+
payload = { public_token: public_token }
|
41
|
+
# include the account id, if set
|
42
|
+
payload[:account_id] = account_id if account_id
|
43
|
+
|
44
|
+
res = Connection.post('exchange_token', payload)
|
45
|
+
ExchangeTokenResponse.new(res)
|
46
|
+
end
|
47
|
+
|
48
|
+
# API: public
|
49
|
+
# Use this to restore a user from OldPlaid based upon the access token
|
50
|
+
# TODO: Rename this to something more descriptive for 2.0, such as 'get_user'
|
51
|
+
def set_user(token, api_levels=[], institution_type=nil)
|
52
|
+
_user = User.new
|
53
|
+
_user.access_token = fully_qualified_token(token, institution_type)
|
54
|
+
_user.permissions = api_levels
|
55
|
+
api_levels.each { |l| _user.get(l) }
|
56
|
+
_user
|
57
|
+
end
|
58
|
+
|
59
|
+
# API: public
|
60
|
+
# Given an access code and query options, use this to get a dataset of
|
61
|
+
# transactions and accounts for # a given user. See /connect/get endpoint
|
62
|
+
#
|
63
|
+
# Returns a User object with accounts and transactions within
|
64
|
+
# the date range given
|
65
|
+
# Examples:
|
66
|
+
# OldPlaid.transactions 'test_wells', account: 'QPO8Jo8vdDHMepg41PBwckXm4KdK1yUdmXOwK'
|
67
|
+
def transactions(token, options = {})
|
68
|
+
_user = User.new
|
69
|
+
_user.access_token = token
|
70
|
+
_user.permit! 'connect'
|
71
|
+
|
72
|
+
# TODO: For 2.0, submit all data as JSON
|
73
|
+
options = JSON.generate(options) if options.kind_of?(Hash)
|
74
|
+
|
75
|
+
_user.get_connect(options: options)
|
76
|
+
_user
|
77
|
+
end
|
78
|
+
|
79
|
+
# API: public
|
80
|
+
# Returns the fully-qualified token based upon type
|
81
|
+
# Note: Don't see this documented in the OldPlaid API docs, need to investigate this
|
82
|
+
def fully_qualified_token(token, institution_type)
|
83
|
+
institution_type.nil? ? token : token + '_' + institution_type
|
84
|
+
end
|
85
|
+
|
86
|
+
# API: public
|
87
|
+
# Builds an institution object and returns when the institution details exist
|
88
|
+
def institution(id = nil)
|
89
|
+
res = Connection.get('institutions', id)
|
90
|
+
id.nil? ? Institution.all(res) : Institution.new(res)
|
91
|
+
end
|
92
|
+
|
93
|
+
# API: public
|
94
|
+
# Builds an category object and returns when the category details exist
|
95
|
+
def category(id = nil)
|
96
|
+
res = Connection.get('categories', id)
|
97
|
+
id.nil? ? Category.all(res) : Category.new(res)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module OldPlaid
|
2
|
+
module Configure
|
3
|
+
attr_accessor :customer_id, :secret, :environment_location
|
4
|
+
|
5
|
+
KEYS = [:customer_id, :secret, :environment_location]
|
6
|
+
|
7
|
+
def config
|
8
|
+
yield self
|
9
|
+
|
10
|
+
# Add trailing slash to api url if it is not present
|
11
|
+
if self.environment_location[-1] != '/'
|
12
|
+
self.environment_location += '/'
|
13
|
+
end
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module OldPlaid
|
6
|
+
class Connection
|
7
|
+
class << self
|
8
|
+
# API: semi-private
|
9
|
+
def post(path, options = {})
|
10
|
+
uri = build_uri(path)
|
11
|
+
options.merge!(client_id: OldPlaid.customer_id, secret: OldPlaid.secret)
|
12
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
13
|
+
http.use_ssl = true
|
14
|
+
request = Net::HTTP::Post.new(uri.path)
|
15
|
+
request.set_form_data(options)
|
16
|
+
res = http.request(request)
|
17
|
+
parse_response(res)
|
18
|
+
end
|
19
|
+
|
20
|
+
# API: semi-private
|
21
|
+
def get(path, id = nil)
|
22
|
+
uri = build_uri(path,id)
|
23
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
24
|
+
http.use_ssl = true
|
25
|
+
request = Net::HTTP::Get.new(uri.path)
|
26
|
+
res = http.request(request)
|
27
|
+
parse_get_response(res.body)
|
28
|
+
end
|
29
|
+
|
30
|
+
# API: semi-private
|
31
|
+
def secure_get(path, access_token, options = {})
|
32
|
+
uri = build_uri(path)
|
33
|
+
options.merge!({access_token:access_token})
|
34
|
+
req = Net::HTTP::Get.new(uri.path)
|
35
|
+
req.body = URI.encode_www_form(options) if options
|
36
|
+
req.content_type = 'application/x-www-form-urlencoded'
|
37
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
|
38
|
+
parse_response(res)
|
39
|
+
end
|
40
|
+
|
41
|
+
# API: semi-private
|
42
|
+
def patch(path, options = {})
|
43
|
+
uri = build_uri(path)
|
44
|
+
options.merge!(client_id: OldPlaid.customer_id, secret: OldPlaid.secret)
|
45
|
+
req = Net::HTTP::Patch.new(uri.path)
|
46
|
+
req.body = URI.encode_www_form(options) if options
|
47
|
+
req.content_type = 'application/x-www-form-urlencoded'
|
48
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
|
49
|
+
parse_response(res)
|
50
|
+
end
|
51
|
+
|
52
|
+
# API: semi-private
|
53
|
+
def delete(path, options = {})
|
54
|
+
uri = build_uri(path)
|
55
|
+
options.merge!(client_id: OldPlaid.customer_id, secret: OldPlaid.secret)
|
56
|
+
req = Net::HTTP::Delete.new(uri.path)
|
57
|
+
req.body = URI.encode_www_form(options) if options
|
58
|
+
req.content_type = 'application/x-www-form-urlencoded'
|
59
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
# API: semi-private
|
65
|
+
def build_uri(path, option = nil)
|
66
|
+
path = path + '/' + option unless option.nil?
|
67
|
+
URI.parse(OldPlaid.environment_location + path)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def parse_response(res)
|
73
|
+
# unfortunately, the JSON gem will raise an exception if the response is empty
|
74
|
+
raise OldPlaid::ServerError.new(res.code, res.msg, '') if res.body.to_s.length < 2
|
75
|
+
# we got a response from the server, so parse it
|
76
|
+
body = JSON.parse(res.body)
|
77
|
+
case res.code.delete('.').to_i
|
78
|
+
when 200 then body
|
79
|
+
when 201 then { msg: 'Requires further authentication', body: body}
|
80
|
+
when 400
|
81
|
+
raise OldPlaid::BadRequest.new(body['code'], body['message'], body['resolve'])
|
82
|
+
when 401
|
83
|
+
raise OldPlaid::Unauthorized.new(body['code'], body['message'], body['resolve'])
|
84
|
+
when 402
|
85
|
+
raise OldPlaid::RequestFailed.new(body['code'], body['message'], body['resolve'])
|
86
|
+
when 404
|
87
|
+
raise OldPlaid::NotFound.new(body['code'], body['message'], body['resolve'])
|
88
|
+
else
|
89
|
+
raise OldPlaid::ServerError.new(body['code'], body['message'], body['resolve'])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_get_response(res)
|
94
|
+
body = JSON.parse(res)
|
95
|
+
return body if body.kind_of?(Array)
|
96
|
+
|
97
|
+
case body['code']
|
98
|
+
when nil
|
99
|
+
body
|
100
|
+
when 1301, 1401, 1501, 1601
|
101
|
+
raise OldPlaid::NotFound.new(body['code'], body['message'], body['resolve'])
|
102
|
+
else
|
103
|
+
body
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|