dwolla-ruby 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.
@@ -0,0 +1,4 @@
1
+ module Dwolla
2
+ class RequestException < Exception
3
+ end
4
+ end
@@ -0,0 +1,18 @@
1
+ module Dwolla
2
+ class FundingSource
3
+ attr_accessor :id, :name, :type, :verified
4
+ def verified?
5
+ !!verified
6
+ end
7
+
8
+ def self.from_json(options)
9
+ source = FundingSource.new
10
+ source.id = options["Id"]
11
+ source.name = options["Name"]
12
+ source.type = options["Type"]
13
+ source.verified = options["Verified"]
14
+ source
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,44 @@
1
+ module Dwolla
2
+ module Response
3
+ class RedirectLimitReached < Faraday::Error::ClientError
4
+ attr_reader :response
5
+
6
+ def initialize(response)
7
+ super "too many redirects; last one to: #{response['location']}"
8
+ @response = response
9
+ end
10
+ end
11
+
12
+ class FollowRedirects < Faraday::Middleware
13
+ REDIRECTS = [301, 302, 303, 307]
14
+ # default value for max redirects followed
15
+ FOLLOW_LIMIT = 3
16
+
17
+ def initialize(app, options = {})
18
+ super(app)
19
+ @options = options
20
+ @follow_limit = options[:limit] || FOLLOW_LIMIT
21
+ end
22
+
23
+ def call(env)
24
+ process_response(@app.call(env), @follow_limit)
25
+ end
26
+
27
+ def process_response(response, follows)
28
+ response.on_complete do |env|
29
+ if redirect? response
30
+ raise RedirectLimitReached, response if follows.zero?
31
+ env[:url] += response['location']
32
+ env[:method] = :get
33
+ response = process_response(@app.call(env), follows - 1)
34
+ end
35
+ end
36
+ response
37
+ end
38
+
39
+ def redirect?(response)
40
+ REDIRECTS.include? response.status
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ module Dwolla
2
+ module Response
3
+ class InternalServerError < Faraday::Error::ClientError
4
+ attr_reader :response
5
+
6
+ def initialize(response)
7
+ super "Internal Server Error"
8
+ @response = response
9
+ end
10
+ end
11
+ class AccessDeniedError < Faraday::Error::ClientError
12
+ attr_reader :response
13
+
14
+ def initialize(response)
15
+ super "Access was denied."
16
+ @response = response
17
+ end
18
+ end
19
+
20
+ class GuardServerError < Faraday::Response::Middleware
21
+ def on_complete(env)
22
+ if env[:status] == 500
23
+ if env[:body].match /Access is denied/
24
+ raise AccessDeniedError, env[:body]
25
+ else
26
+ raise InternalServerError, env[:body]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ module Dwolla
2
+ module Response
3
+ class ParseJson < Faraday::Response::Middleware
4
+ def on_complete(env)
5
+ if respond_to? :parse
6
+ env[:body] = parse(env[:body]) unless [204,302,304,307].index env[:status]
7
+ end
8
+ end
9
+
10
+ def parse(body)
11
+ case body
12
+ when ''
13
+ nil
14
+ else
15
+ response_hash = ::MultiJson.load(body)
16
+
17
+ raise Dwolla::RequestException, response_hash["Message"] if response_hash["Success"] == false
18
+
19
+ response_hash["Response"] ||
20
+ response_hash["SendResult"] ||
21
+ response_hash["RequestResult"] ||
22
+ response_hash
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ module Dwolla
2
+ class Transaction
3
+ include Dwolla::Connection
4
+ @test_mode = false
5
+ def self.test_mode
6
+ @test_mode
7
+ end
8
+ def self.test_mode=(m)
9
+ @test_mode = m
10
+ end
11
+
12
+ ENDPOINTS = { :send => 'transactions/send',
13
+ :request => 'transactions/request' }
14
+ TEST_ENDPOINTS = { :send => 'testapi/send',
15
+ :request => 'testapi/request' }
16
+
17
+ attr_accessor :origin, :destination, :destination_type, :type, :amount, :pin, :id, :source, :source_type, :description, :funds_source
18
+
19
+ def initialize(attrs = {})
20
+ attrs.each do |key, value|
21
+ send("#{key}=".to_sym, value)
22
+ end
23
+ end
24
+
25
+ def execute
26
+ if self.class.test_mode
27
+ end_point = TEST_ENDPOINTS[type]
28
+ else
29
+ end_point = ENDPOINTS[type]
30
+ end
31
+ self.id = post(end_point, to_payload)
32
+ end
33
+
34
+ private
35
+
36
+ def auth_params
37
+ { :oauth_token => origin.oauth_token }
38
+ end
39
+
40
+ def to_payload
41
+ payload = {
42
+ :amount => amount,
43
+ :pin => pin
44
+ }
45
+ payload[:destinationId] = destination if destination
46
+ payload[:destinationType] = destination_type if destination_type
47
+ payload[:sourceId] = source if source
48
+ payload[:sourceType] = source_type if source_type
49
+ payload[:notes] = description if description
50
+ payload[:fundsSource] = funds_source if funds_source
51
+
52
+ payload
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,98 @@
1
+ module Dwolla
2
+ class User
3
+ include Dwolla::Connection
4
+
5
+ attr_accessor :id,
6
+ :name,
7
+ :latitude,
8
+ :longitude,
9
+ :city,
10
+ :state,
11
+ :type,
12
+ :contact_type,
13
+ :image,
14
+ :oauth_token
15
+
16
+ def initialize(attrs={})
17
+ update_attributes(attrs)
18
+ end
19
+
20
+ def self.me(access_token)
21
+ User.new(:oauth_token => access_token)
22
+ end
23
+
24
+ def fetch
25
+ user_attributes = get('users')
26
+ update_attributes(user_attributes)
27
+ self
28
+ end
29
+
30
+ def update_attributes(attrs)
31
+ attrs.each do |key, value|
32
+ key_string = key.is_a?(String) ? key : key.to_s
33
+ send("#{key_string.downcase}=".to_sym, value)
34
+ end
35
+ end
36
+
37
+ def balance
38
+ get('balance')
39
+ end
40
+
41
+ def funding_sources
42
+ sources = get('fundingsources')
43
+ sources.map{|s| FundingSource.from_json(s)}
44
+ end
45
+
46
+ def funding_source(funding_id)
47
+ sources = get('fundingsources?fundingid=' + funding_id)
48
+ sources.map{|s| FundingSource.from_json(s)}
49
+ end
50
+
51
+ def contacts(options = {})
52
+ contacts_url = 'contacts'
53
+ contacts = get(contacts_url, options)
54
+
55
+ instances_from_contacts(contacts)
56
+ end
57
+
58
+ def send_money_to(destination, amount, pin, type='dwolla', description='', funds_source=nil)
59
+ transaction = Transaction.new(:origin => self,
60
+ :destination => destination,
61
+ :destination_type => type,
62
+ :description => description,
63
+ :type => :send,
64
+ :amount => amount,
65
+ :pin => pin,
66
+ :funds_source => funds_source)
67
+
68
+ transaction.execute
69
+ end
70
+
71
+ def request_money_from(source, amount, pin, source_type='dwolla', description='')
72
+ transaction = Transaction.new(:origin => self,
73
+ :source => source,
74
+ :source_type => source_type,
75
+ :description => description,
76
+ :type => :request,
77
+ :amount => amount,
78
+ :pin => pin)
79
+ transaction.execute
80
+ end
81
+
82
+ private
83
+
84
+ def instances_from_contacts(contacts)
85
+ user_instances = []
86
+ contacts.each do |contact|
87
+ contact["Contact_Type"] = contact["Type"]
88
+ contact.delete("Type")
89
+ user_instances << User.new(contact)
90
+ end
91
+ user_instances
92
+ end
93
+
94
+ def auth_params
95
+ { :oauth_token => self.oauth_token }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module Dwolla
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dwolla::Client do
4
+ subject { Dwolla::Client.new('sample_client_id', 'sample_client_secret') }
5
+ let(:query_params) { "client_id=sample_client_id&client_secret=sample_client_secret" }
6
+
7
+ describe "getting user basic information" do
8
+ before do
9
+ stub_get('/users/812-111-1111', query_params).
10
+ to_return(:body => fixture("basic_information.json"))
11
+ end
12
+
13
+ it 'should request the correct resource' do
14
+ subject.user('812-111-1111')
15
+ a_get('/users/812-111-1111', query_params).should have_been_made
16
+ end
17
+
18
+ it 'should return extended information of a given user' do
19
+ user = subject.user('812-111-1111')
20
+ user.should be_a Dwolla::User
21
+ user.id.should == '812-111-1111'
22
+ user.name.should == 'Test User'
23
+ user.latitude.should == 41.584546
24
+ user.longitude.should == -93.634167
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'forwardable'
3
+
4
+ describe Dwolla::Response::FollowRedirects do
5
+
6
+ before do
7
+ @conn = Faraday.new do |b|
8
+ b.use Dwolla::Response::FollowRedirects
9
+ b.adapter :test do |stub|
10
+ stub.get('/') { [301, {'Location' => '/found'}, ''] }
11
+ stub.post('/create') { [302, {'Location' => '/'}, ''] }
12
+ stub.get('/found') { [200, {'Content-Type' => 'text/plain'}, 'fin'] }
13
+ stub.get('/loop') { [302, {'Location' => '/loop'}, ''] }
14
+ stub.get('/temp') { [307, {'Location' => '/found'}, ''] }
15
+ end
16
+ end
17
+ end
18
+
19
+ extend Forwardable
20
+ def_delegators :@conn, :get, :post
21
+
22
+ it 'follow one redirect' do
23
+ get('/').body.should == 'fin'
24
+ end
25
+
26
+ it 'follow twice redirect' do
27
+ post('/create').body.should == 'fin'
28
+ end
29
+
30
+ it 'follows 307 redirects' do
31
+ get('/temp').body.should == 'fin'
32
+ end
33
+
34
+ it 'has a redirect limit' do
35
+ expect { get('/loop') }.to raise_error(Dwolla::Response::RedirectLimitReached)
36
+ end
37
+ end
38
+
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dwolla::Transaction do
4
+ describe "send transaction" do
5
+ context "to a dwolla account" do
6
+ before do
7
+ @origin = double(:oauth_token => '1')
8
+ @destination = '2'
9
+ @destination_type = "dwolla"
10
+ @payload = { :amount => 200,
11
+ :pin => '1234',
12
+ :destinationId => '2',
13
+ :destinationType => 'dwolla',
14
+ :notes => "Sending a transaction",
15
+ :oauth_token => '1' }
16
+
17
+ stub_post('/transactions/send').with(:body => MultiJson.dump(@payload)).to_return(
18
+ :body => fixture('send_transaction.json'))
19
+ end
20
+ it "should request the correct resource" do
21
+ transaction = Dwolla::Transaction.new(:origin => @origin,
22
+ :destination => @destination,
23
+ :destination_type => @destination_type,
24
+ :description => "Sending a transaction",
25
+ :type => :send,
26
+ :amount => 200,
27
+ :pin => '1234')
28
+ transaction.execute
29
+
30
+ a_post('/transactions/send').
31
+ with(:body => MultiJson.dump(@payload)).should have_been_made
32
+ end
33
+
34
+ it "should fetch the id if transaction succesfull" do
35
+ transaction = Dwolla::Transaction.new(:origin => @origin,
36
+ :destination => @destination,
37
+ :destination_type => @destination_type,
38
+ :description => "Sending a transaction",
39
+ :type => :send,
40
+ :amount => 200,
41
+ :pin => '1234')
42
+
43
+ transaction.execute.should == 12345
44
+ transaction.id.should == 12345
45
+ end
46
+ end
47
+
48
+ context "to an email address" do
49
+ before do
50
+ @origin = double(:oauth_token => '1')
51
+ @destination = "user@example.com"
52
+ @destination_type = "email"
53
+ @payload = { :amount => 200,
54
+ :pin => '1234',
55
+ :destinationId => 'user@example.com',
56
+ :destinationType => 'email',
57
+ :notes => "Sending a transaction",
58
+ :oauth_token => '1' }
59
+ stub_post('/transactions/send').with(:body => MultiJson.dump(@payload)).to_return(
60
+ :body => fixture('send_transaction.json'))
61
+ end
62
+ it "should request the correct resource" do
63
+ transaction = Dwolla::Transaction.new(:origin => @origin,
64
+ :destination => @destination,
65
+ :destination_type => @destination_type,
66
+ :description => "Sending a transaction",
67
+ :type => :send,
68
+ :amount => 200,
69
+ :pin => '1234')
70
+
71
+ transaction.execute
72
+
73
+ a_post('/transactions/send').
74
+ with(:body => MultiJson.dump(@payload)).should have_been_made
75
+ end
76
+
77
+ it "should fetch the id if transaction succesfull" do
78
+ transaction = Dwolla::Transaction.new(:origin => @origin,
79
+ :destination => @destination,
80
+ :destination_type => @destination_type,
81
+ :description => "Sending a transaction",
82
+ :type => :send,
83
+ :amount => 200,
84
+ :pin => '1234')
85
+
86
+ transaction.execute.should == 12345
87
+ transaction.id.should == 12345
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ describe "request transaction" do
94
+ context "from a dwolla account" do
95
+ before do
96
+ @origin = double(:oauth_token => '1')
97
+ @source = '2'
98
+ @source_type = 'dwolla'
99
+ @payload = { :amount => 200,
100
+ :pin => '1234',
101
+ :sourceId => '2',
102
+ :sourceType => 'dwolla',
103
+ :notes => "Sending a transaction",
104
+ :oauth_token => '1' }
105
+
106
+ stub_post('/transactions/request').with(:body => MultiJson.dump(@payload)).to_return(
107
+ :body => fixture('request_transaction.json'))
108
+ end
109
+
110
+ it "should request the correct resource" do
111
+ transaction = Dwolla::Transaction.new(:origin => @origin,
112
+ :source => @source,
113
+ :source_type => @source_type,
114
+ :description => "Sending a transaction",
115
+ :type => :request,
116
+ :amount => 200,
117
+ :pin => '1234')
118
+ transaction.execute
119
+
120
+ a_post('/transactions/request').
121
+ with(:body => MultiJson.dump(@payload)).should have_been_made
122
+ end
123
+
124
+ it "should fetch the id if transaction succesfull" do
125
+ transaction = Dwolla::Transaction.new(:origin => @origin,
126
+ :source => @source,
127
+ :source_type => @source_type,
128
+ :description => "Sending a transaction",
129
+ :type => :request,
130
+ :amount => 200,
131
+ :pin => '1234')
132
+
133
+ transaction.execute.should == 12345
134
+ transaction.id.should == 12345
135
+ end
136
+ end
137
+ context "from an email address" do
138
+ before do
139
+ @origin = double(:oauth_token => '1')
140
+ @source = 'user@example.com'
141
+ @source_type = "email"
142
+ @payload = { :amount => 200,
143
+ :pin => '1234',
144
+ :sourceId => 'user@example.com',
145
+ :sourceType => 'email',
146
+ :notes => "Sending a transaction",
147
+ :oauth_token => '1' }
148
+
149
+ stub_post('/transactions/request').with(:body => MultiJson.dump(@payload)).to_return(
150
+ :body => fixture('request_transaction.json'))
151
+ end
152
+
153
+ it "should request the correct resource" do
154
+ transaction = Dwolla::Transaction.new(:origin => @origin,
155
+ :source => @source,
156
+ :source_type => @source_type,
157
+ :description => "Sending a transaction",
158
+ :type => :request,
159
+ :amount => 200,
160
+ :pin => '1234')
161
+ transaction.execute
162
+
163
+ a_post('/transactions/request').
164
+ with(:body => MultiJson.dump(@payload)).should have_been_made
165
+ end
166
+
167
+ it "should fetch the id if transaction succesfull" do
168
+ transaction = Dwolla::Transaction.new(:origin => @origin,
169
+ :source => @source,
170
+ :source_type => @source_type,
171
+ :description => "Sending a transaction",
172
+ :type => :request,
173
+ :amount => 200,
174
+ :pin => '1234')
175
+
176
+ transaction.execute.should == 12345
177
+ transaction.id.should == 12345
178
+ end
179
+ end
180
+ end
181
+ end