synapse_client 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +15 -0
- data/.travis.yml +15 -0
- data/Gemfile +4 -0
- data/Guardfile +11 -0
- data/LICENSE +22 -0
- data/README.md +116 -0
- data/Rakefile +11 -0
- data/lib/synapse_client.rb +137 -0
- data/lib/synapse_client/api_operations/create.rb +16 -0
- data/lib/synapse_client/api_operations/list.rb +17 -0
- data/lib/synapse_client/api_operations/response.rb +20 -0
- data/lib/synapse_client/api_resource.rb +50 -0
- data/lib/synapse_client/bank_account.rb +83 -0
- data/lib/synapse_client/customer.rb +140 -0
- data/lib/synapse_client/error.rb +42 -0
- data/lib/synapse_client/merchant.rb +24 -0
- data/lib/synapse_client/mfa.rb +26 -0
- data/lib/synapse_client/order.rb +65 -0
- data/lib/synapse_client/refreshed_tokens.rb +39 -0
- data/lib/synapse_client/security_question.rb +17 -0
- data/lib/synapse_client/util.rb +55 -0
- data/lib/synapse_client/version.rb +3 -0
- data/spec/spec_helper.rb +78 -0
- data/spec/synapse_client_bank_account_spec.rb +67 -0
- data/spec/synapse_client_customer_spec.rb +42 -0
- data/spec/synapse_client_order_spec.rb +53 -0
- data/spec/synapse_client_spec.rb +70 -0
- data/synapse_client.gemspec +34 -0
- metadata +253 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1c31d65fc404f16de0c7758b1006ad8eda2a3037
|
4
|
+
data.tar.gz: 025e61fa99b415922116894a44bb2b5a37c7defa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dd5ea5ccec30485c2db93c12f7a4bd4482cd45b344991d77c2e1e41f11cb75975f1199505102b355ddd16fdcb1a408d8b4806a9c6e4b649f9389e0c1d64d1708
|
7
|
+
data.tar.gz: f1820556c5b92b014be2152f6a29ebe719676be918ece522d0d4facdc2e2983133b12e6c56734420c45bf3650cfd2f987e2618168fa54ccf782a2a9fd641e643
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Miles Matthias
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/milesmatthias/synapse_client.png?branch=master)](https://travis-ci.org/milesmatthias/synapse_client) [![Gem Version](https://badge.fury.io/rb/synapse_client.png)](http://badge.fury.io/rb/synapse_client) [![Coverage Status](https://coveralls.io/repos/milesmatthias/synapse_client/badge.png)](https://coveralls.io/r/milesmatthias/synapse_client)
|
2
|
+
|
3
|
+
# synapse_client
|
4
|
+
|
5
|
+
A ruby client for the SynapsePay.com API.
|
6
|
+
|
7
|
+
I ripped originally wrote this in a rails app of mine and stripped this out. There's some work left to do to really make it a true ruby gem. See that in the todo section.
|
8
|
+
|
9
|
+
## Notes
|
10
|
+
|
11
|
+
* This is written with the perspective of being the merchant. This gem doesn't support marketplace payments yet, although SynapsePay does support that.
|
12
|
+
* This is also written with the assumption that a customer has no knowledge of their Synapse account. This means:
|
13
|
+
* that this gem says "Customers" when Synapse says "Users"
|
14
|
+
* all orders are bank pay orders
|
15
|
+
* customers do not have passwords
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
_See the specs for the most up to date usage demo._
|
20
|
+
|
21
|
+
#### configuration
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
SynapseClient.client_id = "e06fa0f143a267c2ed8e"
|
25
|
+
SynapseClient.client_secret = "f578105bf9ae03d9310e0af6f4637c1bf363998b"
|
26
|
+
SynapseClient.merchant_synapse_id = 1
|
27
|
+
SynapseClient.dev = true
|
28
|
+
```
|
29
|
+
|
30
|
+
#### create a customer
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
SynapseClient::Customer.create({
|
34
|
+
:email => "foo@example.com",
|
35
|
+
:fullname => "Foo Bar,
|
36
|
+
:phonenumber => "5555555555",
|
37
|
+
:ip_address => "8.8.8.8"
|
38
|
+
})
|
39
|
+
```
|
40
|
+
|
41
|
+
#### retrieve a customer
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
SynapseClient::Customer.retrieve("_customer_access_token_")
|
45
|
+
```
|
46
|
+
|
47
|
+
#### list bank accounts for a customer
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
@customer.bank_accounts
|
51
|
+
```
|
52
|
+
|
53
|
+
#### add a bank account to a customer with just account & routing number
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
@customer.add_bank_account({
|
57
|
+
:account_num => "1111111111",
|
58
|
+
:routing_num => "084000026",
|
59
|
+
:nickname => "Example bank account",
|
60
|
+
:account_type => "1",
|
61
|
+
:account_class => "1"
|
62
|
+
})
|
63
|
+
```
|
64
|
+
|
65
|
+
#### link a bank account to a customer with bank username/password
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
@customer.link_bank_account({
|
69
|
+
:username => "synapse_good",
|
70
|
+
:password => "test1234",
|
71
|
+
:pin => "1234",
|
72
|
+
:bank => "Bank of America"
|
73
|
+
})
|
74
|
+
```
|
75
|
+
|
76
|
+
#### get recent orders for a customer
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
@customer.orders
|
80
|
+
```
|
81
|
+
|
82
|
+
#### add an order for a customer
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
@customer.add_order({
|
86
|
+
:amount => 500, # $500 USD
|
87
|
+
:bank_id => 1
|
88
|
+
})
|
89
|
+
```
|
90
|
+
|
91
|
+
#### retrieve an order
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
SynapseClient::Order.retrieve(4)
|
95
|
+
```
|
96
|
+
|
97
|
+
## TODO (in order of priority)
|
98
|
+
|
99
|
+
* MFAs
|
100
|
+
* MassPay
|
101
|
+
* View bank account
|
102
|
+
* Refresh access tokens
|
103
|
+
* Security Questions
|
104
|
+
* Deposits
|
105
|
+
* Withdrawals
|
106
|
+
* Better synapse error handling
|
107
|
+
* HTTP Error handling
|
108
|
+
* Logging
|
109
|
+
* Callbacks?
|
110
|
+
|
111
|
+
|
112
|
+
# Links
|
113
|
+
|
114
|
+
* [dev.synapsepay.com](http://dev.synapsepay.com)
|
115
|
+
* [rubygems.org/gems/synapse_client](https://rubygems.org/gems/synapse_client)
|
116
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
|
+
# Default directory to look in is `/specs`
|
5
|
+
# Run with `rake spec`
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
7
|
+
task.rspec_opts = ['--color', '--format', 'documentation']
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# http://dev.synapsepay.com/
|
2
|
+
|
3
|
+
require "map"
|
4
|
+
require "restclient"
|
5
|
+
require "synapse_client/api_resource"
|
6
|
+
require "synapse_client/api_operations/response"
|
7
|
+
require "synapse_client/api_operations/list"
|
8
|
+
require "synapse_client/bank_account"
|
9
|
+
require "synapse_client/error"
|
10
|
+
require "synapse_client/merchant"
|
11
|
+
require "synapse_client/mfa"
|
12
|
+
require "synapse_client/order"
|
13
|
+
require "synapse_client/refreshed_tokens"
|
14
|
+
require "synapse_client/security_question"
|
15
|
+
require "synapse_client/customer"
|
16
|
+
require "synapse_client/util"
|
17
|
+
require "synapse_client/version"
|
18
|
+
|
19
|
+
module SynapseClient
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_accessor :client_id, :client_secret
|
23
|
+
attr_accessor :merchant_oauth_key, :merchant_email, :merchant_synapse_id
|
24
|
+
attr_accessor :dev
|
25
|
+
alias_method :dev?, :dev
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.ensure_trailing_slash(url='')
|
29
|
+
return url if url.empty?
|
30
|
+
return url if url[-1] == "/"
|
31
|
+
return url + "/"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.api_url(url='')
|
35
|
+
base_api_url = "https://synapsepay.com"
|
36
|
+
base_api_url = "https://sandbox.synapsepay.com" if dev?
|
37
|
+
|
38
|
+
ret = base_api_url + ensure_trailing_slash(url)
|
39
|
+
|
40
|
+
if dev?
|
41
|
+
ret + "?is_dev=true"
|
42
|
+
else
|
43
|
+
ret
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.request(method, path, params={}, headers={}, client_id=nil, client_secret=nil, api_base_url=nil)
|
48
|
+
|
49
|
+
#
|
50
|
+
unless (client_id ||= @client_id) && (client_secret ||= @client_secret)
|
51
|
+
# TODO - use a custom Error class here
|
52
|
+
raise StandardError.new("You need to enter API credentials first.")
|
53
|
+
end
|
54
|
+
|
55
|
+
if client_id =~ /\s/ || client_secret =~ /\s/
|
56
|
+
# TODO - use a custom Error class here
|
57
|
+
raise StandardError.new("Your API credentials are invalid, as they contain whitespace.")
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
url = api_url(path)
|
62
|
+
cookies = params.delete("cookies")
|
63
|
+
|
64
|
+
case method.to_s.downcase.to_sym
|
65
|
+
when :get, :head, :delete
|
66
|
+
# Make params into GET parameters
|
67
|
+
url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
|
68
|
+
payload = nil
|
69
|
+
else
|
70
|
+
if path.include?("oauth2")
|
71
|
+
payload = params.to_query
|
72
|
+
headers[:content_type] = "application/x-www-form-urlencoded"
|
73
|
+
else
|
74
|
+
payload = creds(client_id, client_secret).update(params)
|
75
|
+
|
76
|
+
# dealing with some naming inconsistencies in the api
|
77
|
+
payload[:oauth_consumer_key] = payload.delete(:access_token) if payload[:access_token]
|
78
|
+
payload[:oauth_consumer_key] = payload.delete("access_token") if payload["access_token"]
|
79
|
+
payload[:access_token] = payload.delete("bank_account_token") if payload["bank_account_token"]
|
80
|
+
payload[:access_token] = payload.delete(:bank_account_token) if payload[:bank_account_token]
|
81
|
+
|
82
|
+
payload = payload.to_json
|
83
|
+
headers[:content_type] = :json
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
request_opts = {
|
89
|
+
:headers => headers,
|
90
|
+
:method => method, :open_timeout => 30,
|
91
|
+
:payload => payload,
|
92
|
+
:url => url, :timeout => 80, :cookies => cookies
|
93
|
+
}
|
94
|
+
|
95
|
+
#
|
96
|
+
#begin
|
97
|
+
response = execute_request(request_opts)
|
98
|
+
# TODO: https://github.com/stripe/stripe-ruby/blob/master/lib/stripe.rb#L127
|
99
|
+
#rescue
|
100
|
+
#end
|
101
|
+
|
102
|
+
parse(response)
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.creds(client_id, client_secret)
|
106
|
+
{
|
107
|
+
:client_id => client_id,
|
108
|
+
:client_secret => client_secret
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.execute_request(opts)
|
113
|
+
puts "\n"
|
114
|
+
puts "SynapseClient: About to send a request with the following opts:"
|
115
|
+
puts opts
|
116
|
+
puts "\n"
|
117
|
+
RestClient::Request.execute(opts)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.uri_encode(params)
|
121
|
+
Util.flatten_params(params).
|
122
|
+
map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.parse(response)
|
126
|
+
#begin
|
127
|
+
body = JSON.parse(response.body)
|
128
|
+
#rescue JSON::ParserError
|
129
|
+
# TODO
|
130
|
+
# raise general_api_error(response.code, response.body)
|
131
|
+
#end
|
132
|
+
|
133
|
+
APIOperations::Response.new(body, response.cookies)
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Stripe
|
2
|
+
module APIOperations
|
3
|
+
module Create
|
4
|
+
module ClassMethods
|
5
|
+
def create(params={}, opts={})
|
6
|
+
response, opts = SynapseClient.request(:post, url, params, opts)
|
7
|
+
response
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SynapseClient
|
2
|
+
module APIOperations
|
3
|
+
module List
|
4
|
+
module ClassMethods
|
5
|
+
def list(params={}, list_action="show")
|
6
|
+
response = SynapseClient.request(:post, url + list_action, params)
|
7
|
+
return response unless response.successful?
|
8
|
+
response.data
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SynapseClient
|
2
|
+
module APIOperations
|
3
|
+
class Response
|
4
|
+
attr_reader :data
|
5
|
+
attr_reader :error_msg
|
6
|
+
attr_reader :success
|
7
|
+
attr_reader :cookies
|
8
|
+
alias_method :successful?, :success
|
9
|
+
|
10
|
+
def initialize(response, cookies=nil)
|
11
|
+
response = Map.new(response)
|
12
|
+
|
13
|
+
@success = response.delete(:success)
|
14
|
+
@error_msg = response.delete(:reason)
|
15
|
+
@data = response
|
16
|
+
@cookies = cookies
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
module SynapseClient
|
3
|
+
class APIResource
|
4
|
+
|
5
|
+
attr_accessor :id
|
6
|
+
|
7
|
+
def self.class_name
|
8
|
+
self.name.split('::')[-1]
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.api_resource_name
|
12
|
+
class_name.downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
hash = {}
|
17
|
+
instance_variables.each do |var|
|
18
|
+
value = instance_variable_get(var)
|
19
|
+
hash[var[1..-1].to_sym] = value if value
|
20
|
+
end
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.url
|
25
|
+
if self == APIResource
|
26
|
+
raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Customer, Bank Account, Order, etc.)')
|
27
|
+
end
|
28
|
+
"/api/v2/#{CGI.escape( api_resource_name )}/"
|
29
|
+
end
|
30
|
+
|
31
|
+
def url
|
32
|
+
self.class.url
|
33
|
+
end
|
34
|
+
|
35
|
+
def refresh(endpoint="")
|
36
|
+
response = SynapseClient.request(:post, url + endpoint, retrieve_params)
|
37
|
+
|
38
|
+
return response unless response.successful?
|
39
|
+
update_attributes(response.data[self.class.class_name.downcase])
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.retrieve(id, opts={})
|
43
|
+
opts.merge!(:id => id)
|
44
|
+
instance = self.new(opts)
|
45
|
+
instance.refresh(retrieve_endpoint)
|
46
|
+
instance
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|