plaid_rails 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/app/assets/javascripts/plaid_rails/link.js +22 -12
- data/app/controllers/plaid_rails/accounts_controller.rb +9 -5
- data/app/controllers/plaid_rails/link_controller.rb +24 -19
- data/app/controllers/plaid_rails/webhooks_controller.rb +4 -3
- data/app/models/plaid_rails/account.rb +6 -4
- data/app/models/plaid_rails/webhook.rb +7 -3
- data/app/services/plaid_rails/create_account_service.rb +17 -12
- data/app/views/plaid_rails/accounts/new.html.erb +2 -2
- data/app/views/plaid_rails/link/_auth.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/db/migrate/20180617232228_api_update.rb +12 -0
- data/lib/generators/plaid_rails/templates/initializer.rb +4 -6
- data/lib/plaid_rails.rb +1 -1
- data/lib/plaid_rails/event.rb +6 -6
- data/lib/plaid_rails/version.rb +1 -1
- data/spec/controllers/plaid_rails/accounts_controller_spec.rb +12 -14
- data/spec/controllers/plaid_rails/link_controller_spec.rb +18 -11
- data/spec/controllers/plaid_rails/webhooks_controller_spec.rb +79 -5
- data/spec/dummy/db/schema.rb +9 -3
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +10529 -0
- data/spec/models/plaid_rails/account_spec.rb +28 -10
- data/spec/models/plaid_rails/webhook_spec.rb +3 -3
- data/spec/services/plaid_rails/create_account_service_spec.rb +7 -3
- data/spec/spec_helper.rb +31 -4
- data/spec/support/token_helper.rb +25 -0
- metadata +54 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1be2e2ff076fc81d6744b9b9ad21713f25ee03f6
|
4
|
+
data.tar.gz: 1f97d8a175a1de3e132de0ef53483d439cd2b347
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3606d4d8a413950fd005a3eb334e89649ac85ace2f686caf59d05bd9faf30e9ca6ad1e785a4b45a96492cb47dc89fd2acfb864b9b5d7170c9e49c1c238196c8a
|
7
|
+
data.tar.gz: bbbfa8aaa1ec946e9f8cab2acd7fd3c3aaad7656fa340f3fdc45c357a6b1b4366ac45f4587e11c64fe4ef077dc7667e493f61a3e19eb2777dba9c4da59951ee2
|
data/README.md
CHANGED
@@ -73,3 +73,11 @@ The plaid webhooks runs subscribers for to process transactions and report error
|
|
73
73
|
|
74
74
|
Update the PlaidRails.configuration.webhook with the address of the webhook url. The route is `plaid/webhook`
|
75
75
|
i.e. http(s)://my.app.com/plaid/webhooks
|
76
|
+
|
77
|
+
### Testing
|
78
|
+
To run the tests you need to set the PLAID credentials in environment variables.
|
79
|
+
```bash
|
80
|
+
export PLAID_CLIENT_ID='your client_id'
|
81
|
+
export PLAID_SECRET='your secret'
|
82
|
+
export PLAID_PUBLIC_KEY='your public_key'
|
83
|
+
```
|
@@ -1,24 +1,33 @@
|
|
1
|
+
function getPublicToken(access_token) {
|
2
|
+
$.post('/plaid/create_token',
|
3
|
+
{access_token: access_token},
|
4
|
+
function (data, status, xhr) {
|
5
|
+
return data.public_token;
|
6
|
+
},
|
7
|
+
'json'
|
8
|
+
);
|
9
|
+
}
|
1
10
|
function getPlaid(plaidData) {
|
2
11
|
var url = null;
|
3
|
-
var
|
12
|
+
var access_token = plaidData.data('access-token');
|
4
13
|
var env = plaidData.data('env');
|
5
|
-
|
14
|
+
var token;
|
15
|
+
if (typeof access_token === 'undefined') {
|
6
16
|
url = '/plaid/authenticate';
|
7
17
|
token = null;
|
8
18
|
} else {
|
9
19
|
url = '/plaid/update';
|
10
|
-
|
11
|
-
// set token for test environment
|
12
|
-
if (env === 'tartan' && typeof plaidData.data('type') !== 'undefined') {
|
13
|
-
token = 'test,' + plaidData.data('type') + ',connected'
|
20
|
+
token = getPublicToken(access_token);
|
14
21
|
}
|
15
22
|
|
16
23
|
var linkHandler = Plaid.create({
|
17
24
|
env: env,
|
25
|
+
apiVersion: 'v2',
|
18
26
|
clientName: plaidData.data('client-name'),
|
19
27
|
key: plaidData.data('key'),
|
20
|
-
product: '
|
28
|
+
product: 'transactions',
|
21
29
|
webhook: plaidData.data('webhook'),
|
30
|
+
token: token,
|
22
31
|
onLoad: function () {
|
23
32
|
// The Link module finished loading.
|
24
33
|
},
|
@@ -32,11 +41,12 @@ function getPlaid(plaidData) {
|
|
32
41
|
url: url,
|
33
42
|
data: {
|
34
43
|
public_token: public_token,
|
35
|
-
|
36
|
-
|
44
|
+
access_token: plaidData.data('access-token'),
|
45
|
+
name: metadata.account.name,
|
46
|
+
type: metadata.account.type,
|
37
47
|
owner_type: plaidData.data('owner-type'),
|
38
48
|
owner_id: plaidData.data('owner-id'),
|
39
|
-
number:
|
49
|
+
number: metadata.account.mask
|
40
50
|
}
|
41
51
|
});
|
42
52
|
},
|
@@ -50,10 +60,10 @@ function getPlaid(plaidData) {
|
|
50
60
|
$(document).on("click", '#plaidLinkButton', function () {
|
51
61
|
var plaidData = $(this);
|
52
62
|
linkHandler = getPlaid(plaidData);
|
53
|
-
var plaidType = plaidData.data('type')
|
63
|
+
var plaidType = plaidData.data('type');
|
54
64
|
//open handler for the institution
|
55
65
|
if (typeof plaidType === 'undefined') {
|
56
|
-
|
66
|
+
linkHandler.open();
|
57
67
|
} else {
|
58
68
|
linkHandler.open(plaidType);
|
59
69
|
}
|
@@ -9,10 +9,14 @@ module PlaidRails
|
|
9
9
|
|
10
10
|
# display list of accounts for authenticated user
|
11
11
|
def new
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
client = Plaid::Client.new(env: PlaidRails.env,
|
13
|
+
client_id: PlaidRails.client_id,
|
14
|
+
secret: PlaidRails.secret,
|
15
|
+
public_key: PlaidRails.public_key)
|
16
|
+
|
17
|
+
response = client.accounts.get(account_params["access_token"])
|
18
|
+
@plaid_accounts = response.accounts
|
19
|
+
|
16
20
|
end
|
17
21
|
|
18
22
|
#create new bank account and return all the accounts for the owner
|
@@ -33,7 +37,7 @@ module PlaidRails
|
|
33
37
|
|
34
38
|
# Never trust parameters from the scary internet, only allow the white list through.
|
35
39
|
def account_params
|
36
|
-
params.require(:account).permit(:
|
40
|
+
params.require(:account).permit(:access_token, :type,:name,
|
37
41
|
:owner_id,:owner_type, :transactions_start_date, account_ids:[])
|
38
42
|
end
|
39
43
|
end
|
@@ -3,44 +3,49 @@ require_dependency "plaid_rails/application_controller"
|
|
3
3
|
module PlaidRails
|
4
4
|
class LinkController < ApplicationController
|
5
5
|
|
6
|
+
# /plaid/authenticate
|
6
7
|
def authenticate
|
7
8
|
begin
|
8
|
-
|
9
|
-
|
9
|
+
client = Plaid::Client.new(env: PlaidRails.env,
|
10
|
+
client_id: PlaidRails.client_id,
|
11
|
+
secret: PlaidRails.secret,
|
12
|
+
public_key: PlaidRails.public_key)
|
13
|
+
@exchange_token = client.item.public_token.exchange(link_params[:public_token])
|
10
14
|
@params = link_params.merge!(token: link_params[:public_token])
|
11
15
|
|
12
16
|
rescue => e
|
13
17
|
Rails.logger.error "Error: #{e}"
|
14
|
-
Rails.logger.error e.backtrace.join("\n")
|
15
18
|
render text: e.message, status: 500
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
22
|
# updates the access token after changing password with institution
|
23
|
+
# /plaid/update
|
20
24
|
def update
|
21
25
|
begin
|
22
|
-
exchange_token = Plaid::User.exchange_token(link_params[:public_token])
|
23
|
-
|
24
|
-
# find old access_token
|
25
|
-
old_access_token = PlaidRails::Account.find_by(owner_type: link_params[:owner_type],
|
26
|
-
owner_id: link_params[:owner_id],number: link_params[:number]).access_token
|
27
|
-
|
28
|
-
# find all plaid_accounts with old access_token
|
29
|
-
accounts = PlaidRails::Account.where(owner_type: link_params[:owner_type],
|
30
|
-
owner_id: link_params[:owner_id], access_token: old_access_token)
|
31
|
-
|
32
|
-
# update found accounts with new token.
|
33
|
-
accounts.update_all(access_token: exchange_token.access_token,
|
34
|
-
transactions_start_date: Date.today)
|
35
|
-
|
36
26
|
# get all accounts to display back to user.
|
37
27
|
@plaid_accounts = PlaidRails::Account.where(owner_type: link_params[:owner_type],
|
38
|
-
|
28
|
+
owner_id: link_params[:owner_id])
|
39
29
|
|
40
30
|
flash[:success]="You have successfully updated your account(s)"
|
41
31
|
rescue => e
|
42
32
|
Rails.logger.error "Error: #{e}"
|
43
|
-
render
|
33
|
+
render json: e.message, status: 500
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# creates a new public token
|
38
|
+
# /plaid/create_token
|
39
|
+
def create_token
|
40
|
+
client = Plaid::Client.new(env: PlaidRails.env,
|
41
|
+
client_id: PlaidRails.client_id,
|
42
|
+
secret: PlaidRails.secret,
|
43
|
+
public_key: PlaidRails.public_key)
|
44
|
+
if link_params['access_token']
|
45
|
+
response = client.item.public_token.create(link_params['access_token'])
|
46
|
+
render json: {public_token: response['public_token']}.to_json
|
47
|
+
else
|
48
|
+
render json: {error: 'missing access_token'}.to_json, status: 500
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
@@ -3,13 +3,14 @@ module PlaidRails
|
|
3
3
|
skip_before_filter :verify_authenticity_token
|
4
4
|
|
5
5
|
def create
|
6
|
-
|
7
|
-
render json:
|
6
|
+
webhook = PlaidRails::Webhook.create!(webhook_params)
|
7
|
+
render json: webhook
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
11
11
|
def webhook_params
|
12
|
-
params.require(:webhook).permit(:
|
12
|
+
params.require(:webhook).permit(:webhook_type, :webhook_code,:error,
|
13
|
+
:item_id, :new_transactions, :removed_transactions, :code, :message,:access_token )
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -8,7 +8,6 @@ module PlaidRails
|
|
8
8
|
validates :plaid_id, presence: true
|
9
9
|
validates :name, presence: true
|
10
10
|
validates :access_token, presence: true
|
11
|
-
validates :plaid_type, presence: true
|
12
11
|
|
13
12
|
private
|
14
13
|
|
@@ -25,10 +24,13 @@ module PlaidRails
|
|
25
24
|
def delete_connect
|
26
25
|
begin
|
27
26
|
Rails.logger.info "Deleting Plaid User with token #{token_last_8}"
|
28
|
-
|
27
|
+
client = Plaid::Client.new(env: PlaidRails.env,
|
28
|
+
client_id: PlaidRails.client_id,
|
29
|
+
secret: PlaidRails.secret,
|
30
|
+
public_key: PlaidRails.public_key)
|
29
31
|
# skip delete if there are no transactions
|
30
|
-
if
|
31
|
-
|
32
|
+
if client.transactions.any?
|
33
|
+
client.item.remove(access_token)
|
32
34
|
Rails.logger.info "Deleted Plaid User with token #{token_last_8}"
|
33
35
|
end
|
34
36
|
rescue => e
|
@@ -1,9 +1,13 @@
|
|
1
1
|
module PlaidRails
|
2
2
|
class Webhook < ActiveRecord::Base
|
3
3
|
|
4
|
-
validates :code, presence: true
|
5
|
-
validates :message, presence: true
|
6
|
-
validates :access_token, presence: true
|
4
|
+
# validates :code, presence: true
|
5
|
+
# validates :message, presence: true
|
6
|
+
# validates :access_token, presence: true
|
7
|
+
# validates :webhook_type, presence: true
|
8
|
+
# validates :webhook_code, presence: true
|
9
|
+
# validates :item_id, presence: true
|
10
|
+
serialize :removed_transactons, Array
|
7
11
|
after_save :event
|
8
12
|
|
9
13
|
private
|
@@ -4,25 +4,30 @@ module PlaidRails
|
|
4
4
|
# creates a new plaid_rails_account for each account the user has selected
|
5
5
|
def self.call(account_params)
|
6
6
|
account_params["account_ids"].each do |id|
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# Create the Plaid Client
|
8
|
+
client = Plaid::Client.new(env: PlaidRails.env,
|
9
|
+
client_id: PlaidRails.client_id,
|
10
|
+
secret: PlaidRails.secret,
|
11
|
+
public_key: PlaidRails.public_key)
|
11
12
|
#find the account by account_id
|
12
|
-
account =
|
13
|
+
account = client.accounts.get(account_params["access_token"]).accounts.find{|a| a.account_id==id}
|
14
|
+
response = client.item.get(account_params["access_token"])
|
15
|
+
item = response.item
|
16
|
+
response = client.institutions.get_by_id(item['institution_id'])
|
17
|
+
institution = response.institution
|
13
18
|
PlaidRails::Account.create!(
|
14
19
|
access_token: account_params["access_token"],
|
15
|
-
|
16
|
-
plaid_type: account_params["type"],
|
20
|
+
plaid_type: item.institution_id,
|
17
21
|
name: account.name,
|
18
|
-
bank_name:
|
19
|
-
number: account.
|
22
|
+
bank_name: institution.name,
|
23
|
+
number: account.mask,
|
20
24
|
owner_id: account_params["owner_id"],
|
21
25
|
owner_type: account_params["owner_type"],
|
22
|
-
available_balance: account.
|
23
|
-
current_balance: account.
|
26
|
+
available_balance: account.balances.available,
|
27
|
+
current_balance: account.balances.current,
|
24
28
|
transactions_start_date: account_params["transactions_start_date"],
|
25
|
-
plaid_id: id
|
29
|
+
plaid_id: id,
|
30
|
+
item_id: item.item_id
|
26
31
|
) unless PlaidRails::Account.exists?(plaid_id: id)
|
27
32
|
end
|
28
33
|
|
@@ -9,8 +9,8 @@
|
|
9
9
|
<%= hidden_field_tag "account[owner_type]", params["owner_type"] %>
|
10
10
|
<%= label_tag "start_date" %> <%= date_field_tag "account[transactions_start_date]" %>
|
11
11
|
<% @accounts.each_with_index do |account,index| %>
|
12
|
-
<%= check_box_tag "account[account_ids][]", account.
|
13
|
-
<label for="account_account_ids_<%=index%>"> <%= "#{account.
|
12
|
+
<%= check_box_tag "account[account_ids][]", account.account_idid,nil,{id: "account_account_ids_#{index}"}%>
|
13
|
+
<label for="account_account_ids_<%=index%>"> <%= "#{account.name} - #{account.mask}"%></label><br/>
|
14
14
|
<%end%>
|
15
15
|
|
16
16
|
<%= submit_tag "Save", :class=>"button small" %>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
<div id="plaid-data"
|
5
5
|
data-client-name="<%= client_name %>"
|
6
|
-
data-env="<%= Rails.env.production? ? "production" : "
|
6
|
+
data-env="<%= Rails.env.production? ? "production" : "sandbox"%>"
|
7
7
|
data-key="<%= PlaidRails.public_key %>"
|
8
8
|
data-webhook="<%= PlaidRails.webhook %>"
|
9
9
|
data-owner-type="<%= owner.class.name %>"
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
class ApiUpdate < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
add_column :plaid_rails_webhooks, :item_id, :string
|
4
|
+
add_column :plaid_rails_webhooks, :webhook_type, :string
|
5
|
+
add_column :plaid_rails_webhooks, :webhook_code, :string
|
6
|
+
add_column :plaid_rails_webhooks, :error, :string
|
7
|
+
add_column :plaid_rails_webhooks, :new_transactions, :integer
|
8
|
+
add_column :plaid_rails_webhooks, :removed_transactions, :text
|
9
|
+
add_column :plaid_rails_accounts, :item_id, :string
|
10
|
+
remove_column :plaid_rails_accounts, :token
|
11
|
+
end
|
12
|
+
end
|
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
p.customer_id = Rails.application.secrets[:plaid][:customer_id]
|
3
|
-
p.secret = Rails.application.secrets[:plaid][:secret]
|
4
|
-
p.environment_location = Rails.env.production? ? 'https://api.plaid.com/' : 'https://tartan.plaid.com/'
|
5
|
-
end
|
1
|
+
|
6
2
|
PlaidRails.configure do |config|
|
3
|
+
config.client_id = Rails.application.secrets[:plaid][:client_id]
|
4
|
+
config.secret = Rails.application.secrets[:plaid][:secret]
|
7
5
|
config.public_key = Rails.application.secrets[:plaid][:public_key]
|
8
6
|
config.longtail = true
|
9
|
-
config.env = Rails.env.production? ? "production" : "
|
7
|
+
config.env = Rails.env.production? ? "production" : "sandbox"
|
10
8
|
config.webhook = 'https://my.app.com/plaid/webhooks'
|
11
9
|
|
12
10
|
# https://plaid.com/docs/#webhook
|
data/lib/plaid_rails.rb
CHANGED
data/lib/plaid_rails/event.rb
CHANGED
@@ -12,16 +12,16 @@ module PlaidRails
|
|
12
12
|
alias :setup :configure
|
13
13
|
|
14
14
|
def instrument(event)
|
15
|
-
name = case event.
|
16
|
-
when
|
15
|
+
name = case event.webhook_code
|
16
|
+
when 'INITIAL_UPDATE'
|
17
17
|
"transactions.initial"
|
18
|
-
when
|
18
|
+
when 'HISTORICAL_UPDATE'
|
19
19
|
"transactions.new"
|
20
|
-
when
|
20
|
+
when 'DEFAULT_UPDATE'
|
21
21
|
"transactions.interval"
|
22
|
-
when
|
22
|
+
when 'TRANSACTIONS_REMOVED'
|
23
23
|
"transactions.removed"
|
24
|
-
when
|
24
|
+
when 'WEBHOOK_UPDATE_ACKNOWLEDGED'
|
25
25
|
"webhook.updated"
|
26
26
|
else
|
27
27
|
"plaid.error"
|
data/lib/plaid_rails/version.rb
CHANGED
@@ -4,8 +4,12 @@ module PlaidRails
|
|
4
4
|
describe AccountsController do
|
5
5
|
routes { PlaidRails::Engine.routes }
|
6
6
|
let(:account){create(:account)}
|
7
|
-
let(:public_token){
|
8
|
-
let(:
|
7
|
+
let(:public_token){create_public_token}
|
8
|
+
let(:client){Plaid::Client.new(env: PlaidRails.env,
|
9
|
+
client_id: PlaidRails.client_id,
|
10
|
+
secret: PlaidRails.secret,
|
11
|
+
public_key: PlaidRails.public_key)}
|
12
|
+
let(:access_token){create_access_token}
|
9
13
|
|
10
14
|
it "get index" do
|
11
15
|
get :index, account:{owner_id: 1}
|
@@ -15,20 +19,21 @@ module PlaidRails
|
|
15
19
|
end
|
16
20
|
|
17
21
|
it "get new" do
|
18
|
-
get :new, account:{access_token:
|
22
|
+
get :new, account:{access_token: access_token, name:'Wells Fargo', type: 'wells',
|
19
23
|
owner_id: "1", owner_type: "User"}
|
20
24
|
expect(response).to be_success
|
21
25
|
expect(assigns(:plaid_accounts)).to_not be_nil
|
26
|
+
expect(assigns(:plaid_accounts).first.name).to eq('Plaid Checking')
|
22
27
|
end
|
23
28
|
|
24
29
|
it "can create" do
|
25
|
-
accounts =
|
26
|
-
post :create, account: {access_token:
|
30
|
+
accounts = client.accounts.get(access_token).accounts.map{|a| a.account_id}
|
31
|
+
post :create, account: {access_token: access_token, account_ids: accounts,
|
27
32
|
name:'Wells Fargo', type: 'wells', owner_id: "1", owner_type: "User",
|
28
33
|
token: public_token}
|
29
34
|
expect(response).to be_success
|
30
35
|
expect(assigns(:plaid_accounts).size).to eq 4
|
31
|
-
expect(assigns(:plaid_accounts).first.
|
36
|
+
expect(assigns(:plaid_accounts).first.name).to eq('Plaid Checking')
|
32
37
|
end
|
33
38
|
|
34
39
|
it "can destroy" do
|
@@ -36,13 +41,6 @@ module PlaidRails
|
|
36
41
|
expect(response).to be_success
|
37
42
|
expect(assigns(:plaid_account)).to eq account
|
38
43
|
end
|
39
|
-
|
40
|
-
# it {
|
41
|
-
# should permit(:access_token, :type,:name,:owner_id,:owner_type,:account_id).
|
42
|
-
# for(:create, params: {access_token: 'test_wells', account_id: '1',
|
43
|
-
# name: 'name'})}
|
44
|
-
# it {
|
45
|
-
# should permit(:token, :type,:name,:owner_id,:owner_type).
|
46
|
-
# for(:new, verb: :get, params: {access_token: 'test_wells'})}
|
44
|
+
|
47
45
|
end
|
48
46
|
end
|