ruby_mint 0.1.1 → 0.2.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: f35663ac4c4455968a43c43629104347ac097356
4
- data.tar.gz: c00b9cd9cf3e4eb9c54450a730cf039f3996b706
3
+ metadata.gz: 0669bb9e0106c090f125a7b2347ec0a9328cad25
4
+ data.tar.gz: 3e9ad2ca1e6eee3c10a724f67eae1faca8b3a7b5
5
5
  SHA512:
6
- metadata.gz: 13692c620ee097e5368b4bcf0ab96cc6dd7229d3ef4f38f768e42f1c634fd871d881c6e1ef5a8f043d5ecc8b77930564700a8b46c388ed1f661abd9001294637
7
- data.tar.gz: de2f372cdf31d425fb64eeac56db6e9caca6d366dcb526952a07b3468ecf834cc786fe71cc44171f15ed800bf91ca962ee60a99bfcbb675253fc1bf796c78a14
6
+ metadata.gz: a1df96b9d242217ed2ef82d9db254cf134c10c2462f7305acaabb91013978a0493f7cd7c51a62f2ab8c479dd71ef13b6050bee69e03fa9cbcb285602d689807d
7
+ data.tar.gz: fb6dba46232e82db20b155ccffdb5ae99487fa84f785719b9b9bdc70ce1476708208a8c4f83ff39bb26ba70eceedfc87e38e63cd050b272f0585aa11a62e52fb
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/ruby_mint.svg)](http://badge.fury.io/rb/ruby_mint)
2
+
1
3
  # RubyMint
2
4
 
3
5
  RubyMint is a gem to assist you with getting information from Mint.com's API.
@@ -63,10 +65,32 @@ accounts = ruby_mint.accounts
63
65
 
64
66
  # Transaction Data
65
67
 
66
- Mint.com returns transactions as CSV.
68
+ Transactions can be obtained as either CSV or JSON data.
69
+
70
+ CSV is a list of all transactions as a CSV dump.
71
+
72
+ NOTE: Breaking change from v0.1 Old transactions method is now transactions_csv
73
+
74
+ ```ruby
75
+ transactions_csv = ruby_mint.transactions_csv
76
+ ```
77
+
78
+ JSON data must specify a date range and has the option to include pending transactions
79
+ or to include a search term. Mint only returns a transaction date without a time. Date
80
+ range is inclusive.
67
81
 
68
82
  ```ruby
69
- transactions = ruby_mint.transactions
83
+ # Get all transactions from May 1, 2015 until now
84
+ transactions = ruby_mint.transactions Time.parse("2015-05-01")
85
+
86
+ # Get all transactions for the month of May
87
+ transactions = ruby_mint.transactions Time.parse("2015-05-01"), Time.parse("2015-05-31")
88
+
89
+ # Include pending transactions
90
+ transactions = ruby_mint.transactions Time.parse("2015-05-01"), Time.parse("2015-05-31"), 'include_pending' => true
91
+
92
+ # Include a search term
93
+ transactions = ruby_mint.transactions Time.parse("2015-05-01"), Time.parse("2015-05-31"), 'search_term' => 'coffee'
70
94
  ```
71
95
 
72
96
  ## Contributing
data/bin/mint_download.rb CHANGED
@@ -61,7 +61,7 @@ ruby_mint.initiate_account_refresh do
61
61
 
62
62
  if transactions_file
63
63
  puts "Downloading transactions..."
64
- transactions = ruby_mint.transactions
64
+ transactions = ruby_mint.transactions_csv
65
65
  end
66
66
  end
67
67
 
data/lib/ruby_mint.rb CHANGED
@@ -32,7 +32,11 @@ class RubyMint
32
32
  end
33
33
 
34
34
  # Login retrieves a user token from Mint.com
35
- def login
35
+ #
36
+ # @param use_token [String] Use an existing token
37
+ def login(use_token = nil)
38
+ @token = use_token and return if use_token
39
+
36
40
  response = agent.get("https://wwws.mint.com/login.event?task=L")
37
41
  raise RubyMintError.new("Unable to GET Mint login page.") if response.code != "200"
38
42
 
@@ -72,9 +76,9 @@ class RubyMint
72
76
  #
73
77
  # @param sleep_time [Integer] Num of seconds to wait between calls to refreshing? when block is passed
74
78
  # @param block [Block] Code to execute upon completion of of refreshing
75
- def initiate_account_refresh(sleep_time = 3, &block)
79
+ def initiate_account_refresh(sleep_time = 3)
76
80
  agent.post("https://wwws.mint.com/refreshFILogins.xevent", { "token" => @token }, JSON_HEADERS)
77
- if block
81
+ if block_given?
78
82
  loop{ sleep sleep_time; break if !refreshing? }
79
83
  yield
80
84
  end
@@ -112,6 +116,8 @@ class RubyMint
112
116
  results = agent.post("https://wwws.mint.com/bundledServiceController.xevent?legacy=false&token=#{@token}", account_query, JSON_HEADERS)
113
117
  raise RubyMintError.new("Unable to obtain account information. Response code: #{results.code}") if results.code != "200"
114
118
 
119
+ raise RubyMintError.new("Not logged in.") if results.body.include?('Session has expired.')
120
+
115
121
  account_body = JSON.load(results.body)
116
122
  if !account_body || !account_body["response"] || !account_body["response"][@request_id.to_s] || !account_body["response"][@request_id.to_s]["response"]
117
123
  raise RubyMintError.new("Unable to obtain account information (no account information in response).")
@@ -124,14 +130,55 @@ class RubyMint
124
130
  # the transactions available
125
131
  #
126
132
  # @return [String] CSV of all transactions
127
- def transactions
133
+ def transactions_csv
128
134
  results = agent.get("https://wwws.mint.com/transactionDownload.event", JSON_HEADERS)
129
- raise RubyMintError.new("Unable to obtain transations.") if results.code != "200"
135
+ raise RubyMintError.new("Unable to obtain transactions.") if results.code != "200"
130
136
  raise RubyMintError.new("Non-CSV content returned.") if !results.header["content-type"].include?("text/csv")
131
137
 
132
138
  results.body
133
139
  end
134
140
 
141
+ # Get transactions from mint. Returned as JSON. Paginate
142
+ #
143
+ # Options:
144
+ # include_pending [Boolean] default false
145
+ # search_term [String] default ""
146
+ #
147
+ # @param start_date [Time] get all transactions on or after this date
148
+ # @param end_date [Time] get all transactions up to and including this date
149
+ # @param options [Hash] options hash
150
+ # @returns [Array<Hash>] array of transactions
151
+ def transactions(start_date, end_date = Time.now, options = {})
152
+ include_pending = options.fetch('include_pending', false)
153
+ search_term = options.fetch('search_term', '')
154
+ offset = 0
155
+ results = []
156
+
157
+ # Convert start and end dates
158
+ start_date = Time.local(start_date.year, start_date.month, start_date.day)
159
+ end_date = Time.local(end_date.year, end_date.month, end_date.day)
160
+
161
+ loop do
162
+ next_page = transaction_page(offset, search_term)
163
+ break if next_page.empty?
164
+
165
+ # Filter out pending transactions
166
+ if !include_pending
167
+ next_page.reject!{ |t| t['isPending'] }
168
+ end
169
+
170
+ results.concat next_page
171
+ break if earliest_mint_date(next_page) < start_date
172
+
173
+ offset += next_page.count
174
+ end
175
+
176
+ # Filter by date
177
+ results.select do |t|
178
+ t['date'] >= start_date && t['date'] <= end_date
179
+ end
180
+ end
181
+
135
182
 
136
183
  private
137
184
 
@@ -140,4 +187,49 @@ class RubyMint
140
187
  agent.user_agent_alias = 'Linux Firefox'
141
188
  }
142
189
  end
190
+
191
+ # Get a single page of transaction data. Mint always returns 50 transactions per page.
192
+ def transaction_page(offset, search_term)
193
+ # Example query: https://wwws.mint.com/app/getJsonData.xevent?queryNew=&offset=0&filterType=cash&acctChanged=T&task=transactions&rnd=1436026512488
194
+ base_url = "https://wwws.mint.com/app/getJsonData.xevent"
195
+ search_query = "?queryNew=#{URI.encode(search_term)}"
196
+ offset_query = "&offset=#{offset}"
197
+ transaction_query = "&filterType=cash&comparableType=8&task=transactions&rnd=#{random_number}"
198
+
199
+ json_results = agent.get("#{base_url}#{search_query}#{offset_query}#{transaction_query}", JSON_HEADERS)
200
+ raise RubyMintError.new("Unable to obtain transactions.") if json_results.code != "200"
201
+ raise RubyMintError.new("Non-JSON content returned.") if !json_results.header["content-type"].include?("text/json")
202
+
203
+ transform_transaction_times JSON.parse(json_results.body)['set'][0]['data']
204
+ end
205
+
206
+ # Mint returns transactions in two formats: "Mar 8" for this year, "10/08/14" for previous years (month/day/year).
207
+ # Transform dates into ruby time objects.
208
+ #
209
+ # NOTE: Mint only returns the date of the transaction, there is no time
210
+ #
211
+ # @param transactions [Array<Hash>] array of transactions
212
+ def transform_transaction_times(transactions)
213
+ transactions.map do |t|
214
+ t['date'] = (t['date'] =~ /\d+\/\d+\/\d+/ ? Time.strptime(t['date'], "%D") : Time.parse(t['date']))
215
+ t
216
+ end
217
+ end
218
+
219
+ # Get the earliest date from this set of transactions. Assumes they are in reverse order.
220
+ #
221
+ # @params transactions [Array<Hash>]
222
+ # @returns [Time]
223
+ def earliest_mint_date(transactions)
224
+ transactions.last['date']
225
+ end
226
+
227
+ # Queries require a 12-digit random number
228
+ def random_number
229
+ # They are starting with 14, so I won't break the mold. Get 10 more.
230
+ nums = (0..9).to_a
231
+ result = "14"
232
+ 10.times{ result << nums.sample.to_s }
233
+ result
234
+ end
143
235
  end
@@ -1,3 +1,3 @@
1
1
  class RubyMint
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/ruby_mint.gemspec CHANGED
@@ -25,4 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "bundler", "~> 1.8"
26
26
  spec.add_development_dependency "rake", "~> 10.0"
27
27
  spec.add_development_dependency "pry", "~> 0.10"
28
+ spec.add_development_dependency "rspec", "~> 3.3"
29
+ spec.add_development_dependency "vcr", "~> 2.9"
30
+ spec.add_development_dependency "webmock", "~> 1.21"
28
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_mint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Marrone
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-03-09 00:00:00.000000000 Z
11
+ date: 2015-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mechanize
@@ -80,6 +80,48 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: vcr
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.9'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.9'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webmock
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.21'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.21'
83
125
  description: Gem to allow you to incorporate Mint.com into your ruby applications.
84
126
  email:
85
127
  - nickmarrone@gmail.com
@@ -88,6 +130,7 @@ extensions: []
88
130
  extra_rdoc_files: []
89
131
  files:
90
132
  - ".gitignore"
133
+ - ".rspec"
91
134
  - ".travis.yml"
92
135
  - CODE_OF_CONDUCT.md
93
136
  - Gemfile
@@ -118,9 +161,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
161
  version: '0'
119
162
  requirements: []
120
163
  rubyforge_project:
121
- rubygems_version: 2.2.2
164
+ rubygems_version: 2.2.3
122
165
  signing_key:
123
166
  specification_version: 4
124
167
  summary: Retrieve your Mint.com transaction and account information.
125
168
  test_files: []
126
- has_rdoc: