plaid-legacy 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +34 -0
- data/CONTRIBUTING.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +328 -0
- data/Rakefile +54 -0
- data/UPGRADING.md +60 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/lib/plaid.rb +64 -0
- data/lib/plaid/account.rb +144 -0
- data/lib/plaid/category.rb +62 -0
- data/lib/plaid/client.rb +69 -0
- data/lib/plaid/connector.rb +172 -0
- data/lib/plaid/errors.rb +37 -0
- data/lib/plaid/income.rb +106 -0
- data/lib/plaid/info.rb +65 -0
- data/lib/plaid/institution.rb +253 -0
- data/lib/plaid/risk.rb +34 -0
- data/lib/plaid/transaction.rb +128 -0
- data/lib/plaid/user.rb +507 -0
- data/lib/plaid/version.rb +3 -0
- data/lib/plaid/webhook.rb +153 -0
- data/plaid-legacy.gemspec +36 -0
- metadata +167 -0
data/UPGRADING.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
## Upgrading from 2.x.x to 3.0.0
|
2
|
+
|
3
|
+
Version 3.0.0 makes `Plaid::Institution` use new `institutions/all` endpoint
|
4
|
+
of Plaid API which unites "native" and "long tail" institutions.
|
5
|
+
`Plaid::LongTailInstitution` class is removed, its functionality is
|
6
|
+
concentrated in `Plaid::Institution`.
|
7
|
+
|
8
|
+
Use `Plaid::Institution.all` instead of `Plaid::LongTailInstitution.all` (the
|
9
|
+
semantics is the same, with added products param).
|
10
|
+
|
11
|
+
Use `Plaid::Institution.search` instead of `Plaid::LongTailInstitution.search`.
|
12
|
+
|
13
|
+
Use `Plaid::Institution.search_by_id` instead of `Plaid::LongTailInstitution.get`.
|
14
|
+
|
15
|
+
|
16
|
+
## Upgrading from 1.x to 2.0.0
|
17
|
+
|
18
|
+
Make sure you use Ruby 2.0 or higher.
|
19
|
+
|
20
|
+
Update the `Plaid.config` block:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
Plaid.config do |p|
|
24
|
+
p.client_id = '<<< Plaid provided client ID >>>' # WAS: customer_id
|
25
|
+
p.secret = '<<< Plaid provided secret key >>>' # No change
|
26
|
+
p.env = :tartan # or :api for production # WAS: environment_location
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
Use `Plaid::User.create` instead of `Plaid.add_user` (**NOTE**: parameter order has changed!)
|
31
|
+
|
32
|
+
Use `Plaid::User.load` instead of `Plaid.set_user` (**NOTE**: parameter order has changed!)
|
33
|
+
|
34
|
+
Use `Plaid::User.exchange_token` instead of `Plaid.exchange_token` (**NOTE**: parameter list has changed!)
|
35
|
+
|
36
|
+
Use `Plaid::User.create` or (`.load`) and `Plaid::User#transactions` instead of `Plaid.transactions`.
|
37
|
+
|
38
|
+
Use `Plaid::Institution.all` and `Plaid::Institution.get` instead of `Plaid.institution`.
|
39
|
+
|
40
|
+
Use `Plaid::Category.all` and `Plaid::Category.get` instead of `Plaid.category`.
|
41
|
+
|
42
|
+
`Plaid::Account#institution_type` was renamed to `Plaid::Account#institution`.
|
43
|
+
|
44
|
+
`Plaid::Transaction#account` was renamed to `Plaid::Transaction#account_id`.
|
45
|
+
|
46
|
+
`Plaid::Transaction#date` is a Date, not a String object now.
|
47
|
+
|
48
|
+
`Plaid::Transaction#cat` was removed. Use `Plaid::Transaction#category_hierarchy` and `Plaid::Transaction#category_id` directly.
|
49
|
+
|
50
|
+
`Plaid::Transaction#category` was renamed to `Plaid::Transaction#category_hierarchy`.
|
51
|
+
|
52
|
+
`Plaid::Transaction#pending_transaction` was renamed to `Plaid::Transaction#pending_transaction_id`.
|
53
|
+
|
54
|
+
Use `Plaid::User#mfa_step` instead of `Plaid::User#select_mfa_method` and `Plaid::User#mfa_authentication`.
|
55
|
+
|
56
|
+
`Plaid::User#permit?` was removed. You don't need this.
|
57
|
+
|
58
|
+
`Plaid::User.delete_user` was renamed to `Plaid::User.delete`.
|
59
|
+
|
60
|
+
**NOTE** that Symbols are now consistently used instead of Strings as product names, keys in hashes, etc. Look at the docs, they have all the examples.
|
data/bin/console
ADDED
data/bin/setup
ADDED
data/lib/plaid.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'plaid/version'
|
2
|
+
require 'plaid/errors'
|
3
|
+
require 'plaid/connector'
|
4
|
+
require 'plaid/category'
|
5
|
+
require 'plaid/institution'
|
6
|
+
require 'plaid/user'
|
7
|
+
require 'plaid/transaction'
|
8
|
+
require 'plaid/info'
|
9
|
+
require 'plaid/income'
|
10
|
+
require 'plaid/client'
|
11
|
+
require 'plaid/webhook'
|
12
|
+
|
13
|
+
require 'uri'
|
14
|
+
|
15
|
+
# Public: The Plaid namespace.
|
16
|
+
module Plaid
|
17
|
+
# Public: Available Plaid products.
|
18
|
+
PRODUCTS = %i(connect auth info income risk).freeze
|
19
|
+
|
20
|
+
class <<self
|
21
|
+
# Public: The default Client.
|
22
|
+
attr_accessor :client
|
23
|
+
|
24
|
+
# Public: The Integer read timeout for requests to Plaid HTTP API.
|
25
|
+
# Should be specified in seconds. Default value is 120 (2 minutes).
|
26
|
+
attr_accessor :read_timeout
|
27
|
+
|
28
|
+
# Public: A helper function to ease configuration.
|
29
|
+
#
|
30
|
+
# Yields self.
|
31
|
+
#
|
32
|
+
# Examples
|
33
|
+
#
|
34
|
+
# Plaid.configure do |p|
|
35
|
+
# p.client_id = 'Plaid provided client ID here'
|
36
|
+
# p.secret = 'Plaid provided secret key here'
|
37
|
+
# p.env = :tartan
|
38
|
+
# p.read_timeout = 300 # it's 5 minutes, yay!
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# Returns nothing.
|
42
|
+
def config
|
43
|
+
client = Client.new
|
44
|
+
yield client
|
45
|
+
self.client = client
|
46
|
+
end
|
47
|
+
|
48
|
+
# Internal: Symbolize keys (and values) for a hash.
|
49
|
+
#
|
50
|
+
# hash - The Hash with string keys (or nil).
|
51
|
+
# values - The Boolean flag telling the function to symbolize values
|
52
|
+
# as well.
|
53
|
+
#
|
54
|
+
# Returns a Hash with keys.to_sym (or nil if hash is nil).
|
55
|
+
def symbolize_hash(hash, values: false)
|
56
|
+
return unless hash
|
57
|
+
return hash.map { |h| symbolize_hash(h) } if hash.is_a?(Array)
|
58
|
+
|
59
|
+
hash.each_with_object({}) do |(k, v), memo|
|
60
|
+
memo[k.to_sym] = values ? v.to_sym : v
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'plaid/risk'
|
2
|
+
|
3
|
+
module Plaid
|
4
|
+
# Public: Representation of user account data.
|
5
|
+
class Account
|
6
|
+
# Public: The String unique ID of the account. E.g.
|
7
|
+
# "QPO8Jo8vdDHMepg41PBwckXm4KdK1yUdmXOwK".
|
8
|
+
attr_reader :id
|
9
|
+
|
10
|
+
# Public: The String account ID unique to the accounts of a particular
|
11
|
+
# access token. E.g. "KdDjmojBERUKx3JkDd9RuxA5EvejA4SENO4AA".
|
12
|
+
attr_reader :item_id
|
13
|
+
|
14
|
+
# Public: The Float value of the current balance for the account.
|
15
|
+
attr_reader :current_balance
|
16
|
+
|
17
|
+
# Public: The Float value of the available balance for the account.
|
18
|
+
#
|
19
|
+
# The Available Balance is the Current Balance less any outstanding holds
|
20
|
+
# or debits that have not yet posted to the account. Note that not all
|
21
|
+
# institutions calculate the Available Balance. In the case that Available
|
22
|
+
# Balance is unavailable from the institution, Plaid will either return an
|
23
|
+
# Available Balance value of null or only return a Current Balance.
|
24
|
+
attr_reader :available_balance
|
25
|
+
|
26
|
+
# Public: The Symbol institution type, e.g. :wells.
|
27
|
+
attr_reader :institution
|
28
|
+
|
29
|
+
# Public: The Hash with additional information pertaining to the account
|
30
|
+
# such as the limit, name, or last few digits of the account number. E.g.
|
31
|
+
# {"name": "Plaid Savings", "number": "9606" }.
|
32
|
+
attr_reader :meta
|
33
|
+
|
34
|
+
# Public: The Symbol account type. One of :depository, :credit, :loan,
|
35
|
+
# :mortgage, :brokerage, and :other.
|
36
|
+
attr_reader :type
|
37
|
+
|
38
|
+
# Public: The String account subtype. E.g. "savings".
|
39
|
+
#
|
40
|
+
# Read more about subtypes in the Plaid API docs.
|
41
|
+
attr_reader :subtype
|
42
|
+
|
43
|
+
# Public: The Hash with account and routing numbers for the account.
|
44
|
+
#
|
45
|
+
# This attribute would be nil unless you used Auth product for the user.
|
46
|
+
#
|
47
|
+
# The Hash contains Symbol keys and String values. E.g.
|
48
|
+
# {routing: "021000021", account: "9900009606", wireRouting: "021000021"}.
|
49
|
+
attr_reader :numbers
|
50
|
+
|
51
|
+
# Public: The Risk information associated with the account.
|
52
|
+
#
|
53
|
+
# This attribute would be nil unless you used Risk product for the user.
|
54
|
+
attr_reader :risk
|
55
|
+
|
56
|
+
def initialize(hash)
|
57
|
+
@id = hash['_id']
|
58
|
+
@item_id = hash['_item']
|
59
|
+
@meta = hash['meta']
|
60
|
+
@type = hash['type'].to_sym
|
61
|
+
@subtype = hash['subtype']
|
62
|
+
@institution = hash['institution_type'].to_sym
|
63
|
+
|
64
|
+
unless (bal = hash['balance']).nil?
|
65
|
+
@available_balance = bal['available']
|
66
|
+
@current_balance = bal['current']
|
67
|
+
end
|
68
|
+
|
69
|
+
if (risk = hash['risk'])
|
70
|
+
@risk = Plaid::Risk.new(risk)
|
71
|
+
end
|
72
|
+
|
73
|
+
@numbers = Plaid.symbolize_hash(hash['numbers'])
|
74
|
+
end
|
75
|
+
|
76
|
+
# Public: Get a String representation of the account.
|
77
|
+
#
|
78
|
+
# Returns a String.
|
79
|
+
def inspect
|
80
|
+
"#<Plaid::Account id=#{id.inspect}, type=#{type.inspect}, " \
|
81
|
+
"name=#{name.inspect}, institution=#{institution.inspect}>"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Public: Get a String representation of the account.
|
85
|
+
#
|
86
|
+
# Returns a String.
|
87
|
+
alias to_s inspect
|
88
|
+
|
89
|
+
# Public: Get the account name.
|
90
|
+
#
|
91
|
+
# The name is obtained from #meta Hash.
|
92
|
+
#
|
93
|
+
# Returns the String name.
|
94
|
+
def name
|
95
|
+
meta && meta['name']
|
96
|
+
end
|
97
|
+
|
98
|
+
# Internal: Merge account information.
|
99
|
+
#
|
100
|
+
# accounts - The Array of Account instances.
|
101
|
+
# new_accounts - The Array of Account instances.
|
102
|
+
#
|
103
|
+
# Returns accounts.
|
104
|
+
def self.merge(accounts, new_accounts)
|
105
|
+
# Index accounts by their ID.
|
106
|
+
#
|
107
|
+
# Same as index = accounts.index_by(&:id) in ActiveSupport.
|
108
|
+
index = Hash[accounts.map { |a| [a.id, a] }]
|
109
|
+
|
110
|
+
new_accounts.each do |acc|
|
111
|
+
if (old_acc = index[acc.id])
|
112
|
+
old_acc.update_from(acc)
|
113
|
+
else
|
114
|
+
accounts << acc
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
accounts
|
119
|
+
end
|
120
|
+
|
121
|
+
# Internal: Update account information.
|
122
|
+
#
|
123
|
+
# All fields which are not nil in another are copied to self.
|
124
|
+
#
|
125
|
+
# another - The Account instance with new information.
|
126
|
+
#
|
127
|
+
# Returns self.
|
128
|
+
def update_from(another)
|
129
|
+
# A sanity check. Nobody would want to update information from totally
|
130
|
+
# different account!
|
131
|
+
if id != another.id
|
132
|
+
raise ArgumentError, 'Plaid::Account#update_from: id != another.id!'
|
133
|
+
end
|
134
|
+
|
135
|
+
%i(item_id meta name type subtype institution available_balance
|
136
|
+
current_balance numbers risk).each do |field|
|
137
|
+
value = another.send(field)
|
138
|
+
instance_variable_set("@#{field}", value) unless value.nil?
|
139
|
+
end
|
140
|
+
|
141
|
+
self
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Plaid
|
2
|
+
# Public: A class which encapsulates information about a Plaid category.
|
3
|
+
class Category
|
4
|
+
# Public: The String category ID, e.g. "21010006".
|
5
|
+
attr_reader :id
|
6
|
+
|
7
|
+
# Public: The Symbol category type. One of :special, :place, :digital.
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
# Public: The Array of String hierarchy. E.g.
|
11
|
+
# ["Food and Drink", "Nightlife"].
|
12
|
+
attr_reader :hierarchy
|
13
|
+
|
14
|
+
# Internal: Initialize a Category with given fields.
|
15
|
+
def initialize(fields)
|
16
|
+
@type = fields['type'].to_sym
|
17
|
+
@hierarchy = fields['hierarchy']
|
18
|
+
@id = fields['id']
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Get a String representation of Category.
|
22
|
+
#
|
23
|
+
# Returns a String.
|
24
|
+
def inspect
|
25
|
+
"#<Plaid::Category id=#{id.inspect}, type=#{type.inspect}, " \
|
26
|
+
"hierarchy=#{hierarchy.inspect}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Public: Get a String representation of Category.
|
30
|
+
#
|
31
|
+
# Returns a String.
|
32
|
+
alias to_s inspect
|
33
|
+
|
34
|
+
# Public: Get information about all available categories.
|
35
|
+
#
|
36
|
+
# Does a GET /categories call.
|
37
|
+
#
|
38
|
+
# client - The Plaid::Client instance used to connect
|
39
|
+
# (default: Plaid.client).
|
40
|
+
#
|
41
|
+
# Returns an Array of Category instances.
|
42
|
+
def self.all(client: nil)
|
43
|
+
Connector.new(:categories, client: client).get.map do |category_data|
|
44
|
+
new(category_data)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Get information about a given category.
|
49
|
+
#
|
50
|
+
# Does a GET /categories/:id call.
|
51
|
+
#
|
52
|
+
# id - the String category ID (e.g. "17001013").
|
53
|
+
# client - The Plaid::Client instance used to connect
|
54
|
+
# (default: Plaid.client).
|
55
|
+
#
|
56
|
+
# Returns a Category instance or raises Plaid::NotFoundError if category
|
57
|
+
# with given id is not found.
|
58
|
+
def self.get(id, client: nil)
|
59
|
+
new Connector.new(:categories, id, client: client).get
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/plaid/client.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Plaid
|
2
|
+
# Public: A class encapsulating client_id, secret, and Plaid API URL.
|
3
|
+
class Client
|
4
|
+
# Public: The String Plaid account client ID to authenticate requests.
|
5
|
+
attr_accessor :client_id
|
6
|
+
|
7
|
+
# Public: The String Plaid account secret to authenticate requests.
|
8
|
+
attr_accessor :secret
|
9
|
+
|
10
|
+
# Public: Plaid environment, i.e. String base URL of the API site.
|
11
|
+
#
|
12
|
+
# E.g. 'https://tartan.plaid.com'.
|
13
|
+
attr_reader :env
|
14
|
+
|
15
|
+
# Public: Set Plaid environment to use.
|
16
|
+
#
|
17
|
+
# env - The Symbol (:tartan, :production), or a full String URL like
|
18
|
+
# 'https://tartan.plaid.com'.
|
19
|
+
def env=(env)
|
20
|
+
case env
|
21
|
+
when :tartan
|
22
|
+
@env = 'https://tartan.plaid.com/'
|
23
|
+
when :production
|
24
|
+
@env = 'https://api.plaid.com/'
|
25
|
+
when String
|
26
|
+
begin
|
27
|
+
URI.parse(env)
|
28
|
+
@env = env
|
29
|
+
rescue
|
30
|
+
raise ArgumentError, 'Invalid URL in Plaid::Client.env' \
|
31
|
+
" (#{env.inspect}). " \
|
32
|
+
'Specify either Symbol (:tartan, :production),' \
|
33
|
+
" or a full URL, like 'https://tartan.plaid.com'"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
raise ArgumentError, 'Invalid value for Plaid::Client.env' \
|
37
|
+
" (#{env.inspect}): " \
|
38
|
+
'must be :tartan, :production, or a full URL, ' \
|
39
|
+
"e.g. 'https://tartan.plaid.com'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Construct a Client instance.
|
44
|
+
#
|
45
|
+
# env - The Symbol (:tartan, :production), or a full String URL like
|
46
|
+
# 'https://tartan.plaid.com'.
|
47
|
+
# client_id - The String Plaid account client ID to authenticate requests.
|
48
|
+
# secret - The String Plaid account secret to authenticate requests.
|
49
|
+
def initialize(env: nil, client_id: nil, secret: nil)
|
50
|
+
env && self.env = env
|
51
|
+
self.client_id = client_id
|
52
|
+
self.secret = secret
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Check if client_id is configured.
|
56
|
+
#
|
57
|
+
# Returns true if it is.
|
58
|
+
def client_id_configured?
|
59
|
+
@client_id.is_a?(String) && !@client_id.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
# Public: Check if client_id is configured.
|
63
|
+
#
|
64
|
+
# Returns true if it is.
|
65
|
+
def secret_configured?
|
66
|
+
@secret.is_a?(String) && !@secret.empty?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module Plaid
|
6
|
+
# Internal: A class encapsulating HTTP requests to the Plaid API servers
|
7
|
+
class Connector
|
8
|
+
attr_reader :uri, :http, :request, :response, :body
|
9
|
+
|
10
|
+
# Internal: Default read timeout for HTTP calls.
|
11
|
+
DEFAULT_TIMEOUT = 120
|
12
|
+
|
13
|
+
# Internal: Prepare to run request.
|
14
|
+
#
|
15
|
+
# path - The String path without leading slash. E.g. 'connect'
|
16
|
+
# subpath - The String subpath. E.g. 'get'
|
17
|
+
# auth - The Boolean flag indicating that client_id and secret should be
|
18
|
+
# included into the request payload.
|
19
|
+
# client - The Plaid::Client instance used to connect
|
20
|
+
# (default: Plaid.client).
|
21
|
+
def initialize(path, subpath = nil, auth: false, client: nil)
|
22
|
+
@auth = auth
|
23
|
+
@client = client || Plaid.client
|
24
|
+
verify_configuration
|
25
|
+
|
26
|
+
path = File.join(@client.env, path.to_s)
|
27
|
+
path = File.join(path, subpath.to_s) if subpath
|
28
|
+
|
29
|
+
@uri = URI.parse(path)
|
30
|
+
|
31
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
32
|
+
@http.use_ssl = true
|
33
|
+
|
34
|
+
@http.read_timeout = Plaid.read_timeout || DEFAULT_TIMEOUT
|
35
|
+
end
|
36
|
+
|
37
|
+
# Internal: Run GET request.
|
38
|
+
#
|
39
|
+
# Returns the parsed JSON response body.
|
40
|
+
def get(payload = {})
|
41
|
+
payload = with_credentials(payload)
|
42
|
+
|
43
|
+
@uri.query = URI.encode_www_form(payload) unless payload.empty?
|
44
|
+
|
45
|
+
run Net::HTTP::Get.new(@uri)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Internal: Run POST request.
|
49
|
+
#
|
50
|
+
# Adds client_id and secret to the payload if @auth is true.
|
51
|
+
#
|
52
|
+
# payload - The Hash with data.
|
53
|
+
#
|
54
|
+
# Returns the parsed JSON response body.
|
55
|
+
def post(payload)
|
56
|
+
post_like payload, Net::HTTP::Post.new(@uri.path)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Run PATCH request.
|
60
|
+
#
|
61
|
+
# Adds client_id and secret to the payload if @auth is true.
|
62
|
+
#
|
63
|
+
# payload - The Hash with data.
|
64
|
+
#
|
65
|
+
# Returns the parsed JSON response body.
|
66
|
+
def patch(payload)
|
67
|
+
post_like payload, Net::HTTP::Patch.new(@uri.path)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Internal: Run DELETE request.
|
71
|
+
#
|
72
|
+
# Adds client_id and secret to the payload if @auth is true.
|
73
|
+
#
|
74
|
+
# payload - The Hash with data.
|
75
|
+
#
|
76
|
+
# Returns the parsed JSON response body.
|
77
|
+
def delete(payload)
|
78
|
+
post_like payload, Net::HTTP::Delete.new(@uri.path)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Internal: Check if MFA response received.
|
82
|
+
#
|
83
|
+
# Returns true if response has code 201.
|
84
|
+
def mfa?
|
85
|
+
@response.is_a?(Net::HTTPCreated)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Internal: Run the request and process the response.
|
91
|
+
#
|
92
|
+
# Returns the parsed JSON body or raises an appropriate exception (a
|
93
|
+
# descendant of Plaid::PlaidError).
|
94
|
+
def run(request)
|
95
|
+
@request = request
|
96
|
+
@response = http.request(@request)
|
97
|
+
|
98
|
+
if @response.body.nil? || @response.body.empty?
|
99
|
+
raise Plaid::ServerError.new(0, 'Server error', 'Try to connect later')
|
100
|
+
end
|
101
|
+
|
102
|
+
# All responses are expected to have a JSON body, so we always parse,
|
103
|
+
# not looking at the status code.
|
104
|
+
@body = MultiJson.load(@response.body)
|
105
|
+
|
106
|
+
case @response
|
107
|
+
when Net::HTTPSuccess, Net::HTTPCreated
|
108
|
+
@body
|
109
|
+
else
|
110
|
+
raise_error
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Internal: Run POST-like request.
|
115
|
+
#
|
116
|
+
# payload - The Hash with posted data.
|
117
|
+
# request - The Net::HTTPGenericRequest descendant instance.
|
118
|
+
def post_like(payload, request)
|
119
|
+
request.set_form_data(with_credentials(payload))
|
120
|
+
|
121
|
+
run request
|
122
|
+
end
|
123
|
+
|
124
|
+
# Internal: Raise an error with the class depending on @response.
|
125
|
+
#
|
126
|
+
# Returns an Array with arguments.
|
127
|
+
def raise_error
|
128
|
+
klass = case @response
|
129
|
+
when Net::HTTPBadRequest then Plaid::BadRequestError
|
130
|
+
when Net::HTTPUnauthorized then Plaid::UnauthorizedError
|
131
|
+
when Net::HTTPPaymentRequired then Plaid::RequestFailedError
|
132
|
+
when Net::HTTPNotFound then Plaid::NotFoundError
|
133
|
+
else
|
134
|
+
Plaid::ServerError
|
135
|
+
end
|
136
|
+
|
137
|
+
raise klass.new(body['code'], body['message'], body['resolve'])
|
138
|
+
end
|
139
|
+
|
140
|
+
# Internal: Verify that Plaid environment is properly configured.
|
141
|
+
#
|
142
|
+
# Raises NotConfiguredError if anything is wrong.
|
143
|
+
def verify_configuration
|
144
|
+
raise_not_configured(:env, auth: false) unless @client.env
|
145
|
+
return unless @auth
|
146
|
+
|
147
|
+
!@client.client_id_configured? && raise_not_configured(:client_id)
|
148
|
+
!@client.secret_configured? && raise_not_configured(:secret)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Internal: Raise a NotConfiguredError exception with proper message.
|
152
|
+
def raise_not_configured(field, auth: true)
|
153
|
+
message = "You must set Plaid::Client.#{field} before using any methods"
|
154
|
+
message << ' which require authentication' if auth
|
155
|
+
message << "! It's current value is #{@client.send(field).inspect}. " \
|
156
|
+
'E.g. add a Plaid.config do .. end block somewhere in the ' \
|
157
|
+
'initialization code of your program.'
|
158
|
+
|
159
|
+
raise NotConfiguredError, message
|
160
|
+
end
|
161
|
+
|
162
|
+
# Internal: Merge credentials to the payload if needed.
|
163
|
+
def with_credentials(payload)
|
164
|
+
if @auth
|
165
|
+
payload.merge(client_id: @client.client_id,
|
166
|
+
secret: @client.secret)
|
167
|
+
else
|
168
|
+
payload
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|