plaid 0.1.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e809fa56df8552695b93076d9d4e657301214dce
4
- data.tar.gz: 599f6ceeb4e92f61fe31a93e28babac8726a067d
3
+ metadata.gz: 177a3e175a0defda0b9303805fe7f1f841d161d6
4
+ data.tar.gz: addfdce9ab4abe67eb4fa0478a83e56e5e09172e
5
5
  SHA512:
6
- metadata.gz: 491571f86e7ff9f2bd61e0cc58e4088a79dcc92a118c69686863296882dfe5c5f0d3a3d57e477d4c48cc1e76d049e5a0571aafac08ab8f2129cfebda35373468
7
- data.tar.gz: 50d6b0fabe1074af7a13590b038192d29bcef0846e4717f305fbaa6077a7382811c7fdf76e101aa0f6b717c7a43efd56cded725cac97604d4e2e4d6de1f21bdc
6
+ metadata.gz: 578a30e11a1c222c77a8c8cc6d5877400cd77d25cca5d898ade5e2f2fc5092d2fb248c874676999ab134911804724c7a23e3ef96af53b755056427c71cabe92c
7
+ data.tar.gz: e0e2213f052cb3641f715603ee0991cb24ee1edae76c5d913ecc3aabcddaf6bd7be5b10cd4841c4aeceff5209b6477a48080529ab12faaa25b35a2b9f525d674
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in plaid.gemspec
4
+ gemspec
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/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Plaid
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'plaid'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install plaid
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/plaid/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/lib/plaid.rb CHANGED
@@ -1,20 +1,43 @@
1
+ require 'plaid/version'
1
2
  require 'plaid/config'
2
- require 'plaid/call'
3
- require 'plaid/customer'
4
- require 'rest_client'
3
+ require 'plaid/util'
4
+
5
+ require 'plaid/auth'
6
+ require 'plaid/user/user'
7
+ require 'plaid/institution/institution'
8
+ require 'plaid/category/category'
9
+
5
10
  module Plaid
11
+ # Define an instance of the gem thus responding with one customer at a time
6
12
  class << self
13
+ # Include the SDK methods
14
+
15
+ # Configures the gem with the public, private, and environment vars
7
16
  include Plaid::Configure
8
17
 
9
- # Defined when a user exists with a unique access_token. Ex: Plaid.customer.get_transactions
10
- def customer
11
- @customer = Plaid::Customer.new
18
+ # Include the utility classes used throughout the gem
19
+ include Plaid::Util
20
+
21
+ # Includes the method to authenticate the user. Defined in auth.rb
22
+ include Plaid::Auth
23
+
24
+ # Builds the user object and returns on successful authentication
25
+ def user(res)
26
+ @user = Plaid::User.new
27
+ @user.new(res)
28
+ end
29
+
30
+ # Builds an institution object and returns when the institution details exist
31
+ def institution(res)
32
+ @institution = Plaid::Institution.new
33
+ @institution.new(res)
12
34
  end
13
35
 
14
- # Defined for generic calls without access_tokens required. Ex: Plaid.call.add_accounts(username,password,type)
15
- def call
16
- @call = Plaid::Call.new
36
+ # Builds an institution object and returns when the category details exist
37
+ def category(res)
38
+ @category = Plaid::Category.new
39
+ @category.new(res)
17
40
  end
18
41
 
19
42
  end
20
- end
43
+ end
data/lib/plaid/auth.rb ADDED
@@ -0,0 +1,12 @@
1
+ module Plaid
2
+ module Auth
3
+ def auth(api_level,username,password,type)
4
+ begin
5
+ res = self.post(api_level,username,password,type)
6
+ self.user(res)
7
+ rescue => e
8
+ error_handler(e)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ require 'plaid/util'
2
+ module Plaid
3
+ class Category
4
+ include Plaid::Util
5
+
6
+ attr_accessor(:type, :hierarchy, :id)
7
+
8
+ # Returns an instantiated category object, or an array of all categories
9
+ def new(id=nil)
10
+ res = get('categories',id)
11
+ id.nil? ? cat = instantiate_all_categories(res) : cat = instantiate_one_category(res)
12
+ cat
13
+ end
14
+
15
+ def instantiate_all_categories(res)
16
+ cat_array = []
17
+ res['category'].each do |cat|
18
+ @category = Category.new
19
+ cat_array << @category.build_category(cat)
20
+ end
21
+ cat_array
22
+ end
23
+
24
+ def instantiate_one_category(res)
25
+ @category = Category.new
26
+ @category.build_category(res)
27
+ end
28
+
29
+ protected
30
+
31
+ def build_category(cat)
32
+ self.type = cat['type'], self.hierarchy = cat['hierarchy'], self.id = cat['id']
33
+ end
34
+
35
+ end
36
+ end
data/lib/plaid/config.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Plaid
2
2
  module Configure
3
- attr_writer :customer_id, :secret
3
+ attr_writer :customer_id, :secret, :environment_location
4
4
 
5
- KEYS = [:customer_id, :secret]
5
+ KEYS = [:customer_id, :secret, :environment_location]
6
6
 
7
7
  def config
8
8
  yield self
@@ -10,4 +10,4 @@ module Plaid
10
10
  end
11
11
 
12
12
  end
13
- end
13
+ end
@@ -0,0 +1,36 @@
1
+ require 'plaid/util'
2
+ module Plaid
3
+ class Institution
4
+ include Plaid::Util
5
+
6
+ attr_accessor(:id, :name, :type, :has_mfa, :mfa)
7
+
8
+ # Returns an instantiated category object, or an array of all categories
9
+ def new(id=nil)
10
+ res = get('institutions',id)
11
+ id.nil? ? cat = instantiate_all_institutions(res) : cat = instantiate_one_institution(res)
12
+ cat
13
+ end
14
+
15
+ def instantiate_all_institutions(res)
16
+ inst_array = []
17
+ res['institution'].each do |inst|
18
+ @institution = Institution.new
19
+ inst_array << @institution.build_institution(inst)
20
+ end
21
+ inst_array
22
+ end
23
+
24
+ def instantiate_one_institution(res)
25
+ @category = Institution.new
26
+ @category.build_institution(res)
27
+ end
28
+
29
+ protected
30
+
31
+ def build_institution(cat)
32
+ self.id = cat['id'], self.name = cat['name'], self.type = cat['type'], self.has_mfa = cat['has_mfa'], self.mfa = cat['mfa']
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ require 'plaid/util'
2
+ module Plaid
3
+ class Account
4
+ include Plaid::Util
5
+ # Define vars for user accounts
6
+ attr_accessor(:available_balance, :current_balance, :institution_type, :meta, :transactions, :numbers, :name)
7
+
8
+ # Instantiate a new account with the results of the successful API call
9
+ # Build an array of nested transactions, and return self if successful
10
+ def new(res)
11
+ begin
12
+ self.name = res['name'], self.available_balance = res['balance']['available'], self.current_balance = res['balance']['current'], self.institution_type = res['institution_type']
13
+ self.meta = res['meta'] if res['meta']
14
+ res['numbers'] ? self.numbers = res['numbers'] : self.numbers = 'Upgrade user to access routing information for this account'
15
+ rescue => e
16
+ error_handler(e)
17
+ else
18
+ self
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'plaid/util'
2
+ module Plaid
3
+ class Transaction
4
+ include Plaid::Util
5
+ # Define vars for user accounts
6
+ attr_accessor(:id, :account, :amount, :name, :meta, :location, :pending, :score, :type, :category, :category_id)
7
+
8
+ # Instantiate a new account with the results of the successful API call
9
+ # Build an array of nested transactions, and return self if successful
10
+ def new(res)
11
+ begin
12
+ self.id = res['_id'], self.account = res['_account'], self.amount = res['amount'], self.name = res['name'], self.meta = res['meta'], self.location = res['location'], self.pending = res['pending'], self.score = res['score'], self.type = res['type'], self.category = res['category'], self.category_id = res['category_id']
13
+ rescue => e
14
+ error_handler(e)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'account/account'
2
+ require_relative 'transaction/transaction'
3
+ require 'plaid/util'
4
+ module Plaid
5
+ class User
6
+ include Plaid::Util
7
+
8
+ # Define user vars
9
+ attr_accessor(:accounts, :transactions, :access_token)
10
+
11
+ def initialize
12
+ self.accounts = []
13
+ self.transactions = []
14
+ self.access_token = ''
15
+ end
16
+
17
+ # Instantiate a new user with the results of the successful API call
18
+ # Build an array of nested accounts, and return self if successful
19
+ def new(res)
20
+ begin
21
+ self.access_token = res['access_token']
22
+ if res['msg'].nil?
23
+ res['accounts'].each do |account|
24
+ self.accounts << new_account(account)
25
+ end if res['accounts']
26
+ res['transactions'].each do |transaction|
27
+ self.transactions << new_transaction(transaction)
28
+ end if res['transactions']
29
+ else
30
+ self.accounts = res.msg, self.transactions = res.msg
31
+ end
32
+ rescue => e
33
+ error_handler(e)
34
+ else
35
+ self
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ # Instantiate and build a new account object, return this to the accounts array
42
+ def new_account(account)
43
+ @account = Account.new
44
+ @account.new(account)
45
+ end
46
+
47
+ # Instantiate and build a new account object, return this to the accounts array
48
+ def new_transaction(transaction)
49
+ @transaction = Transaction.new
50
+ @transaction.new(transaction)
51
+ end
52
+
53
+ end
54
+ end
data/lib/plaid/util.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'uri'
4
+ module Plaid
5
+ module Util
6
+
7
+ def post(path,username,password,type,options={})
8
+ uri = build_uri(path)
9
+ res = Net::HTTP.post_form(uri, {client_id: self.instance_variable_get(:'@customer_id') ,secret: self.instance_variable_get(:'@secret'), username: username, password: password, type: type})
10
+ parse_response(res)
11
+ end
12
+
13
+ def get(path,id=nil)
14
+ uri = build_uri(path,id)
15
+ res = Net::HTTP.get(uri)
16
+ parse_response(res)
17
+ end
18
+
19
+ def error_handler(err,res=nil)
20
+ case err
21
+ when 'Bad Request'
22
+ raise 'The request was malformed. Did you check the API docs?'
23
+ when 'Unauthorized'
24
+ raise 'Access denied: Try using the correct credentials.'
25
+ when 'Request Failed'
26
+ raise 'Request Failed'
27
+ when 'Not Found'
28
+ raise 'Not Found'
29
+ else
30
+ raise err
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def build_uri(path,id=nil)
37
+ id ? URI.parse(self.instance_variable_get(:'@environment_location') + path + id) :
38
+ URI.parse(self.instance_variable_get(:'@environment_location') + path)
39
+ end
40
+
41
+ private
42
+
43
+ def parse_response(res)
44
+ body = JSON.parse(res.body)
45
+ case res.code
46
+ when '200'
47
+ return body
48
+ when '201'
49
+ return { msg: 'Requires further authentication', body: body}
50
+ when '400'
51
+ error_handler('Bad Request',res)
52
+ when '401'
53
+ error_handler('Unauthorized',res)
54
+ when '402'
55
+ if body['code'] == 1205
56
+ return { msg: 'User account is locked', body: body }
57
+ else
58
+ error_handler('Request Failed',res)
59
+ end
60
+ when '404'
61
+ error_handler('Not Found',res)
62
+ else
63
+ error_handler('Server Error',res)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ module Plaid
2
+ VERSION = '1.0.0'
3
+ end
data/plaid.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'plaid/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'plaid'
7
+ spec.version = Plaid::VERSION
8
+ spec.authors = ['Justin Crites']
9
+ spec.email = ['crites.justin@gmail.com']
10
+ spec.summary = 'Ruby bindings for Plaid'
11
+ spec.description = 'Ruby gem wrapper for the Plaid API. Read more at the homepage, the wiki, or the plaid documentation.'
12
+ spec.homepage = 'https://github.com/plaid/plaid-ruby'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.7'
21
+ spec.add_development_dependency 'rake', '~> 10.0'
22
+ spec.add_development_dependency 'rspec', '~>3.1'
23
+ end
@@ -0,0 +1,252 @@
1
+ require 'spec_helper.rb'
2
+ ########## Plaid specs ##########
3
+ describe Plaid do
4
+ # Configuration specs - used in gem configuration
5
+ describe '.config' do
6
+ context 'has valid dev keys' do
7
+ Plaid.config do |p|
8
+ p.customer_id = 'test_id'
9
+ p.secret = 'test_secret'
10
+ p.environment_location = 'https://tartan.plaid.com/'
11
+ end
12
+ res = Plaid.auth('connect','plaid_test','plaid_good','wells')
13
+ it { expect(res).to be instance_of Plaid::User }
14
+ end
15
+
16
+ context 'has valid production keys' do
17
+ Plaid.config do |p|
18
+ p.customer_id = 'test_id'
19
+ p.secret = 'test_secret'
20
+ p.environment_location = 'https://api.plaid.com/'
21
+ end
22
+ #TODO: Test production level credentials
23
+ res = Plaid.auth('connect','plaid_test','plaid_good','wells')
24
+ it { expect(res).to raise_error }
25
+ end
26
+
27
+ context 'has invalid dev keys' do
28
+ Plaid.config do |p|
29
+ p.customer_id = 'test_id'
30
+ p.secret = 'test_bad'
31
+ p.environment_location = 'https://tartan.plaid.com/'
32
+ end
33
+ it { expect(Plaid.auth('connect','plaid_test','plaid_good','wells')).to raise_error }
34
+ end
35
+
36
+ context 'has invalid production keys' do
37
+ Plaid.config do |p|
38
+ p.customer_id = 'test_id'
39
+ p.secret = 'test_bad'
40
+ p.environment_location = 'https://api.plaid.com/'
41
+ end
42
+ it { expect(Plaid.auth('connect','plaid_test','plaid_good','wells')).to raise_error }
43
+ end
44
+ end
45
+
46
+ # Authentication flow specs - returns Plaid::User
47
+ # TODO: Abstract the config from each section with the result in passing tests
48
+ describe '.auth' do
49
+
50
+ context 'has correct credentials for single factor auth, authenticates to the connect path' do
51
+ Plaid.config do |p|
52
+ p.customer_id = 'test_id'
53
+ p.secret = 'test_secret'
54
+ p.environment_location = 'https://tartan.plaid.com/'
55
+ end
56
+ user = Plaid.auth('connect','plaid_test','plaid_good','wells')
57
+ it { expect(user.accounts.blank?).to be_false }
58
+ end
59
+
60
+ context 'has correct credentials for single factor auth, authenticates to the auth path' do
61
+ Plaid.config do |p|
62
+ p.customer_id = 'test_id'
63
+ p.secret = 'test_secret'
64
+ p.environment_location = 'https://tartan.plaid.com/'
65
+ end
66
+ user = Plaid.auth('auth','plaid_test','plaid_good','wells')
67
+ it { expect(user.accounts[0].numbers.nil?).to be_false }
68
+ end
69
+
70
+ context 'has correct username, but incorrect password for single factor auth under auth path' do
71
+ Plaid.config do |p|
72
+ p.customer_id = 'test_id'
73
+ p.secret = 'test_secret'
74
+ p.environment_location = 'https://tartan.plaid.com/'
75
+ end
76
+ it { expect(Plaid.auth('auth','plaid_test','plaid_bad','wells')).to raise_error }
77
+ end
78
+
79
+ context 'has incorrect username under auth path' do
80
+ Plaid.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
+ it { expect(Plaid.auth('auth','plaid_bad','plaid_bad','wells')).to raise_error }
86
+ end
87
+
88
+ context 'has correct username, but incorrect password for single factor auth under connect path' do
89
+ Plaid.config do |p|
90
+ p.customer_id = 'test_id'
91
+ p.secret = 'test_secret'
92
+ p.environment_location = 'https://tartan.plaid.com/'
93
+ end
94
+ it { expect(Plaid.auth('connect','plaid_test','plaid_bad','wells')).to raise_error }
95
+ end
96
+
97
+ context 'has incorrect username under connect path' do
98
+ Plaid.config do |p|
99
+ p.customer_id = 'test_id'
100
+ p.secret = 'test_secret'
101
+ p.environment_location = 'https://tartan.plaid.com/'
102
+ end
103
+ it { expect(Plaid.auth('connect','plaid_bad','plaid_bad','wells')).to raise_error }
104
+ end
105
+
106
+ context 'has to enter MFA credentials' do
107
+ Plaid.config do |p|
108
+ p.customer_id = 'test_id'
109
+ p.secret = 'test_secret'
110
+ p.environment_location = 'https://tartan.plaid.com/'
111
+ end
112
+ user = Plaid.auth('connect','plaid_selections', 'plaid_good','wells')
113
+ it { expect(user.accounts).to eq 'Requires further authentication' }
114
+ end
115
+
116
+ context 'enters correct information with locked account' do
117
+ Plaid.config do |p|
118
+ p.customer_id = 'test_id'
119
+ p.secret = 'test_secret'
120
+ p.environment_location = 'https://tartan.plaid.com/'
121
+ end
122
+ user = Plaid.auth('connect','plaid_selections', 'plaid_locked','wells')
123
+ it { expect(user.accounts).to eq 'User account is locked' }
124
+ end
125
+ end
126
+
127
+ =begin
128
+ TODO: Finish up these tests
129
+ # Institution specs
130
+ describe Plaid::Institution do
131
+
132
+ context 'when institution is found' do
133
+ Plaid.config do |p|
134
+ p.customer_id = 'test_id'
135
+ p.secret = 'test_secret'
136
+ p.environment_location = 'https://tartan.plaid.com/'
137
+ end
138
+ institution = Plaid.institution('amex')
139
+ it { expect(institution).to be instance_of Plaid::Institution }
140
+ end
141
+
142
+ context 'when institution is not found' do
143
+ Plaid.config do |p|
144
+ p.customer_id = 'test_id'
145
+ p.secret = 'test_secret'
146
+ p.environment_location = 'https://tartan.plaid.com/'
147
+ end
148
+ it { expect(Plaid.institution('dumb_bank')).to raise_error }
149
+ end
150
+ end
151
+
152
+ # Category specs
153
+ describe Plaid::Category do
154
+
155
+ context 'when category is found' do
156
+ Plaid.config do |p|
157
+ p.customer_id = 'test_id'
158
+ p.secret = 'test_secret'
159
+ p.environment_location = 'https://tartan.plaid.com/'
160
+ end
161
+ category = Plaid.category('17001013')
162
+ it { expect(category).to be instance_of Plaid::Category }
163
+ end
164
+
165
+ context 'when category is not found' do
166
+ Plaid.config do |p|
167
+ p.customer_id = 'test_id'
168
+ p.secret = 'test_secret'
169
+ p.environment_location = 'https://tartan.plaid.com/'
170
+ end
171
+ it { expect(Plaid.category('dumb_cat')).to raise_error }
172
+ end
173
+
174
+ end
175
+ end
176
+
177
+ ########## Plaid instantiated user specs ##########
178
+
179
+ describe Plaid::User do
180
+ subject(:success_user) { Plaid.auth('connect','plaid_test','plaid_good','wells') }
181
+ subject(:mfa_user) { Plaid.auth('connect','plaid_selections', 'plaid_good','wells') }
182
+
183
+ # MFA specs - after user is instantiated,
184
+ describe '#mfa_authentication' do
185
+ context 'has to enter another round of MFA credentials' do
186
+ res = user.mfa_authenticaiton('again')
187
+ expect(res).to eq 'Another round requested'
188
+ end
189
+
190
+ context 'enters correct credentials for MFA auth and authenticates' do
191
+ user.mfa_authentication('tomato')
192
+ expect(user.accounts).to be_truthy
193
+ end
194
+
195
+ context 'enters incorrect credentials for MFA auth' do
196
+ res = user.mfa_authentication('bad')
197
+ expect(res).to eq 'Incorrect answer to MFA'
198
+ end
199
+ end
200
+
201
+ # Upgrade specs - either pass or fails
202
+ describe '#upgrade' do
203
+ context 'auth upgrade is successful' do
204
+ user.upgrade('auth')
205
+ expect(user.auth).to be true
206
+ end
207
+
208
+ context 'auth upgrade failed' do
209
+ user.upgrade('auth')
210
+ expect(user.auth).to be false
211
+ end
212
+
213
+ context 'connect upgrade is successful' do
214
+ user.upgrade('connect')
215
+ expect(user.auth).to be true
216
+ end
217
+
218
+ context 'connect upgrade failed' do
219
+ user.upgrade('connect')
220
+ expect(user.auth).to be false
221
+ end
222
+ end
223
+
224
+ # Auth specs
225
+ describe '#auth' do
226
+ context 'has access and returns accounts' do
227
+ auth = user.auth
228
+ expect(auth).to be true
229
+ expect(user.accounts).to be_truthy
230
+ end
231
+
232
+ context 'does not have access to auth' do
233
+ auth = user.auth
234
+ expect(auth).to be false
235
+ end
236
+ end
237
+
238
+ # Connect specs
239
+ describe '#connect' do
240
+ context 'has access and returns accounts' do
241
+ expect(user.connect).to be true
242
+ expect(user.transactions).to be_truthy
243
+ end
244
+
245
+ context 'does not have access to auth' do
246
+ expect(user.connect).to be false
247
+ end
248
+ end
249
+
250
+ =end
251
+
252
+ end
@@ -0,0 +1,4 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'plaid'
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plaid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Crites
8
- - Gamble McAdam
9
- - Rahul Ramakrishnan
10
8
  autorequire:
11
9
  bindir: bin
12
10
  cert_chain: []
13
- date: 2014-04-11 00:00:00.000000000 Z
11
+ date: 2015-01-22 00:00:00.000000000 Z
14
12
  dependencies:
15
13
  - !ruby/object:Gem::Dependency
16
- name: rest-client
14
+ name: bundler
17
15
  requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ">="
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- version: '0'
29
- - !ruby/object:Gem::Dependency
30
- name: json
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: '0'
36
- type: :runtime
19
+ version: '1.7'
20
+ type: :development
37
21
  prerelease: false
38
22
  version_requirements: !ruby/object:Gem::Requirement
39
23
  requirements:
40
- - - ">="
24
+ - - "~>"
41
25
  - !ruby/object:Gem::Version
42
- version: '0'
26
+ version: '1.7'
43
27
  - !ruby/object:Gem::Dependency
44
28
  name: rake
45
29
  requirement: !ruby/object:Gem::Requirement
46
30
  requirements:
47
- - - ">="
31
+ - - "~>"
48
32
  - !ruby/object:Gem::Version
49
- version: '0'
33
+ version: '10.0'
50
34
  type: :development
51
35
  prerelease: false
52
36
  version_requirements: !ruby/object:Gem::Requirement
53
37
  requirements:
54
- - - ">="
38
+ - - "~>"
55
39
  - !ruby/object:Gem::Version
56
- version: '0'
40
+ version: '10.0'
57
41
  - !ruby/object:Gem::Dependency
58
42
  name: rspec
59
43
  requirement: !ruby/object:Gem::Requirement
60
44
  requirements:
61
- - - ">="
45
+ - - "~>"
62
46
  - !ruby/object:Gem::Version
63
- version: '0'
47
+ version: '3.1'
64
48
  type: :development
65
49
  prerelease: false
66
50
  version_requirements: !ruby/object:Gem::Requirement
67
51
  requirements:
68
- - - ">="
52
+ - - "~>"
69
53
  - !ruby/object:Gem::Version
70
- version: '0'
71
- description: Ruby Gem wrapper for Plaid API.
72
- email: justin@guavatext.com
54
+ version: '3.1'
55
+ description: Ruby gem wrapper for the Plaid API. Read more at the homepage, the wiki,
56
+ or the plaid documentation.
57
+ email:
58
+ - crites.justin@gmail.com
73
59
  executables: []
74
60
  extensions: []
75
61
  extra_rdoc_files: []
76
62
  files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
77
68
  - lib/plaid.rb
78
- - lib/plaid/call.rb
69
+ - lib/plaid/auth.rb
70
+ - lib/plaid/category/category.rb
79
71
  - lib/plaid/config.rb
80
- - lib/plaid/customer.rb
72
+ - lib/plaid/institution/institution.rb
73
+ - lib/plaid/user/account/account.rb
74
+ - lib/plaid/user/transaction/transaction.rb
75
+ - lib/plaid/user/user.rb
76
+ - lib/plaid/util.rb
77
+ - lib/plaid/version.rb
78
+ - plaid.gemspec
79
+ - spec/plaid_spec.rb
80
+ - spec/spec_helper.rb
81
81
  homepage: https://github.com/plaid/plaid-ruby
82
82
  licenses:
83
83
  - MIT
@@ -101,5 +101,7 @@ rubyforge_project:
101
101
  rubygems_version: 2.2.2
102
102
  signing_key:
103
103
  specification_version: 4
104
- summary: Plaid Ruby Gem
105
- test_files: []
104
+ summary: Ruby bindings for Plaid
105
+ test_files:
106
+ - spec/plaid_spec.rb
107
+ - spec/spec_helper.rb
data/lib/plaid/call.rb DELETED
@@ -1,83 +0,0 @@
1
- module Plaid
2
- class Call
3
-
4
- BASE_URL = 'https://tartan.plaid.com/'
5
-
6
- # This initializes our instance variables, and sets up a new Customer class.
7
- def initialize
8
- Plaid::Configure::KEYS.each do |key|
9
- instance_variable_set(:"@#{key}", Plaid.instance_variable_get(:"@#{key}"))
10
- end
11
- end
12
-
13
- # This is a specific route for auth,
14
- # it returns specific acct info
15
- def add_account_auth(type, username, password, email)
16
- parse_auth_response(post('/auth', type, username, password, email))
17
- end
18
-
19
- # This is a specific route for connect,
20
- # it returns transaction information
21
- def add_account_connect(type,username,password,email,options={})
22
- parse_connect_response(post('/connect',type,username,password,email,options))
23
- end
24
-
25
- def get_place(id)
26
- parse_place(get('entities/',id))
27
- end
28
-
29
- def get_institutions
30
- JSON.parse(get('/institutions'))
31
- end
32
-
33
- protected
34
-
35
- # Specific parser for auth response
36
- def parse_auth_response(response)
37
- parsed = JSON.parse(response)
38
- case response.code
39
- when 200
40
- {code: response.code, access_token: parsed['access_token'], accounts: parsed['accounts']}
41
- when 201
42
- {code: response.code, type: parsed['type'], access_token: parsed['access_token'], mfa: parsed['mfa']}
43
- else
44
- {code: response.code, message: parsed}
45
- end
46
- end
47
-
48
- def parse_connect_response(response)
49
- parsed = JSON.parse(response)
50
- case response.code
51
- when 200
52
- {code: response.code, access_token: parsed['access_token'], accounts: parsed['accounts'], transactions: parsed['transactions']}
53
- when 201
54
- {code: response.code, type: parsed['type'], access_token: parsed['access_token'], mfa: parsed['mfa']}
55
- else
56
- {code: response.code, message: parsed}
57
- end
58
- end
59
-
60
- def parse_place(response)
61
- parsed = JSON.parse(response)
62
- {code: response.code, category: parsed['category'], name: parsed['name'], id: parsed['_id'], phone: parsed['meta']['contact']['telephone'], location: parsed['meta']['location']}
63
- end
64
-
65
- def parse_institutions(response)
66
- parsed = JSON.parse(response)
67
- {code: response.code, institutions: parsed}
68
- end
69
-
70
- private
71
-
72
- def post(path,type,username,password,email,options={})
73
- url = BASE_URL + path
74
- RestClient.post url, client_id: self.instance_variable_get(:'@customer_id') ,secret: self.instance_variable_get(:'@secret'), type: type ,credentials: {username: username, password: password} ,email: email, options: options
75
- end
76
-
77
- def get(path,id = nil)
78
- url = BASE_URL + path + id.to_s
79
- RestClient.get(url)
80
- end
81
-
82
- end
83
- end
@@ -1,68 +0,0 @@
1
- module Plaid
2
- # This is used when a customer needs to be defined by the plaid access token.
3
- # Abstracting as a class makes it easier since we wont have to redefine the access_token over and over.
4
- class Customer
5
-
6
- BASE_URL = 'https://tartan.plaid.com'
7
-
8
- # This initializes our instance variables, and sets up a new Customer class.
9
- def initialize
10
- Plaid::Configure::KEYS.each do |key|
11
- instance_variable_set(:"@#{key}", Plaid.instance_variable_get(:"@#{key}"))
12
- end
13
- end
14
-
15
- def mfa_auth_step(access_token, code, type)
16
- parse_response(post('/auth/step', access_token, mfa: code, type: type), 0)
17
- end
18
-
19
- def mfa_connect_step(access_token,code)
20
- parse_response(post('/connect/step', access_token, mfa: code),1)
21
- end
22
-
23
- def get_transactions(access_token)
24
- parse_response(get('/connect', access_token),2)
25
- end
26
-
27
- def delete_account(access_token)
28
- parse_response(delete('/connect', access_token),3)
29
- end
30
-
31
- protected
32
-
33
- def parse_response(response,method)
34
- parsed = JSON.parse(response)
35
- if response.code == '200'
36
- case method
37
- when 0
38
- {code: response.code, access_token: parsed['access_token'], accounts: parsed['accounts']}
39
- when 1
40
- {code: response.code, access_token: parsed['access_token'], accounts: parsed['accounts'], transactions: parsed['transactions']}
41
- when 2
42
- {code: response.code, transactions: parsed['transactions']}
43
- else
44
- {code: response.code, message: parsed}
45
- end
46
- else
47
- {code: response.code, message: parsed}
48
- end
49
- end
50
-
51
- private
52
-
53
- def get(path,access_token)
54
- url = BASE_URL + path
55
- RestClient.get(url, params: {client_id: self.instance_variable_get(:'@customer_id'), secret: self.instance_variable_get(:'@secret'), access_token: access_token})
56
- end
57
-
58
- def post(path,access_token,options={})
59
- url = BASE_URL + path
60
- RestClient.post url, client_id: self.instance_variable_get(:'@customer_id'), secret: self.instance_variable_get(:'@secret'), access_token: access_token, mfa: options[:mfa], type: options[:type]
61
- end
62
-
63
- def delete(path,access_token)
64
- url = BASE_URL + path
65
- RestClient.delete(url, params: {client_id: self.instance_variable_get(:'@customer_id'), secret: self.instance_variable_get(:'@secret'), access_token: access_token})
66
- end
67
- end
68
- end