Skip to content
Browse files

Switching back to Wesabe for underlying support - refactored old code…

… to work more like the adapter I built for Buxfer, as a step towards generalizing it all
  • Loading branch information...
1 parent ab54b3d commit 9cdd5738929d7da8b6383280ff67073c947c03db @konklone konklone committed Mar 29, 2010
View
4 .gitignore
@@ -1,5 +1,7 @@
/config/database.yml
/*.sqlite3
-/updater/buxfer.yml
+/updater/buxfer/buxfer.yml
+/updater/wesabe/wesabe.yml
+/updater/wesabe/cacert.pem
/tmp
/dreamhost.rb
View
2 Rakefile
@@ -3,7 +3,7 @@ require 'logger'
desc "Update all accounts"
task :update => :environment do
- require 'updater/updater'
+ require 'updater/wesabe/updater'
User.all.each do |user|
Updater.new(user).update_accounts!
View
3 config/deploy.rb
@@ -34,7 +34,8 @@
desc "Get shared files into position"
task :shared_links, :roles => [:web, :app] do
run "ln -nfs #{shared_path}/database.yml #{release_path}/config/database.yml"
- run "ln -nfs #{shared_path}/buxfer.yml #{release_path}/updater/buxfer.yml"
+ run "ln -nfs #{shared_path}/buxfer.yml #{release_path}/updater/buxfer/buxfer.yml"
+ run "ln -nfs #{shared_path}/wesabe.yml #{release_path}/updater/wesabe/wesabe.yml"
run "ln -nfs #{shared_path}/dreamhost.rb #{release_path}/dreamhost.rb"
run "rm #{File.join release_path, 'tmp', 'pids'}"
run "rm #{File.join release_path, 'public', 'system'}"
View
0 updater/buxfer.rb → updater/buxfer/buxfer.rb
File renamed without changes.
View
0 updater/buxfer.yml.example → updater/buxfer/buxfer.yml.example
File renamed without changes.
View
0 updater/updater.rb → updater/buxfer/updater.rb
File renamed without changes.
View
6 updater/wesabe/trigger.rb
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require File.join(File.dirname(__FILE__), 'wesabe')
+
+Wesabe.new.trigger_updates
View
58 updater/wesabe/updater.rb
@@ -0,0 +1,58 @@
+#!/usr/bin/ruby
+
+require 'rubygems'
+require File.join(File.dirname(__FILE__), 'wesabe')
+
+class Updater
+ attr_accessor :user
+ attr_accessor :wesabe
+ attr_accessor :maps
+ attr_accessor :manual
+
+ def initialize(user)
+ wesabe = YAML.load_file File.join(File.dirname(__FILE__), 'wesabe.yml')
+ self.user = user
+ self.wesabe = Wesabe.new
+ self.maps = wesabe[:accounts]
+ self.manual = wesabe[:manual]
+ end
+
+ def update_accounts!
+ worth = 0
+
+ # the accounts in Buxfer
+ wesabe.accounts.map do |remote|
+ map = maps.find {|m| m[:remote_id] == remote[:id]}
+ if map
+ account = user.accounts.find map[:local_id]
+ amount = (remote[:balance] * 100).to_i # convert to pennies
+ amount *= -1 if account.debts?
+
+ worth += amount
+ update_account! account, amount
+ end
+ end
+
+ # the manual accounts that Buxfer doesn't support
+ manual.each do |map|
+ account = user.accounts.find map[:local_id]
+ amount = map[:amount]
+
+ worth += amount
+ update_account! account, amount
+ end
+
+ # the net worth of it all
+ account = user.accounts.worth.first
+ update_account! account, worth
+ end
+
+ # idempotent - will overwrite balance if one exists for today
+ def update_account!(account, amount)
+ balance = account.balances.find_or_initialize_by_date_of Time.now.to_date
+ balance.user_id = user.id
+ balance.amount = amount
+ balance.save!
+ puts "Updated #{account.name} with balance of #{amount}, for #{balance.date_of}."
+ end
+end
View
87 updater/wesabe/wesabe.rb
@@ -0,0 +1,87 @@
+require 'net/https'
+require 'hpricot'
+require 'yaml'
+
+CERT_FILENAME = File.join File.dirname(__FILE__), 'cacert.pem'
+CONFIG_FILENAME = File.join File.dirname(__FILE__), 'wesabe.yml'
+
+
+class Wesabe
+ attr_accessor :email, :password, :http
+
+ def initialize
+ creds_from_file CONFIG_FILENAME
+ initialize_http
+ end
+
+ def accounts
+ doc = Hpricot.XML get_accounts_xml
+ doc.search('//account').map do |account|
+ {
+ :id => account.at(:id).inner_text.to_i,
+ :name => account.at(:name).inner_text,
+ :balance => account.at('current-balance').inner_text.to_f
+ }
+ end
+ end
+
+ def creds_from_file(file)
+ config = YAML.load_file file
+ self.email = config[:credentials][:email]
+ self.password = config[:credentials][:password]
+ end
+
+ def initialize_http
+ unless File.exist?(CERT_FILENAME)
+ puts "Downloading certificate..."
+ cert = Net::HTTP.get('curl.haxx.se', '/ca/cacert.pem')
+ File.open(CERT_FILENAME, "w") { |f| f << cert }
+ puts "Certificate downloaded."
+ end
+ self.http = Net::HTTP.new("www.wesabe.com", 443)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ http.ca_file = CERT_FILENAME
+ end
+
+ def trigger_updates
+ http.start do |wesabe|
+ request = Net::HTTP::Post.new('/user/login')
+ request.set_form_data({'email' => email, 'password' => password})
+ response = http.request(request)
+
+ case response
+ when Net::HTTPOK
+ STDERR.puts "Bad email and password"
+ when Net::HTTPRedirection
+ puts "Logged in successfully"
+ response.body
+ else
+ STDERR.puts "Unexpected response: #{response.inspect}"
+ exit(-1)
+ end
+ end
+ end
+
+ def get_accounts_xml
+ http.start do |wesabe|
+ request = Net::HTTP::Get.new('/accounts.xml')
+ request.basic_auth(email, password)
+ response = http.request(request)
+
+ case response
+ when Net::HTTPFound
+ STDERR.puts "Incorrect email or password."
+ response.each_header do |key, value|
+ STDERR.puts "#{key}: #{value}"
+ end
+ exit(-1)
+ when Net::HTTPOK
+ response.body
+ else
+ STDERR.puts "Unexpected response: #{response.inspect}"
+ exit(-1)
+ end
+ end
+ end
+end
View
22 updater/wesabe/wesabe.yml.example
@@ -0,0 +1,22 @@
+# Buxfer email and password
+:credentials:
+ :email:
+ :password:
+
+
+# local_id is the local database ID of an account
+# remote_id is Wesabe's ID for that account
+:accounts:
+ - :local_id:
+ :remote_id:
+ - :local_id:
+ :remote_id:
+
+# Any manual accounts
+# For example, Wesabe can't do student loans, so you could update this by hand each month
+# Remember to put the negative sign on a debt
+:manual:
+ - :local_id:
+ :amount:
+ - :local_id:
+ :amount:

0 comments on commit 9cdd573

Please sign in to comment.
Something went wrong with that request. Please try again.