aggcat 0.4.0 → 1.0.1

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: ab0c6e9b22ff49963c78a07302e83aaa846abd8a
4
- data.tar.gz: d9912a2c3d68bc93fe7ef90790eba73340a825ab
3
+ metadata.gz: 04cae6d196e8a35478b7c0264578977c7a8c3b24
4
+ data.tar.gz: 9488dfe842aced92961c1c7833ed982683633c81
5
5
  SHA512:
6
- metadata.gz: c74e838e70a3b0564cafe8be97e5fbe321d12d7742992bbc9fa36438f79c9cd94f553a3e9084c7df0ca4cbc15569dd03477bfd3a49ad2fbd1d5bb4b5da6b0fe6
7
- data.tar.gz: 9ca6d14fc9a46972c397046a8f66222de4f6a323d2c3b0a2d109a7d49633a17817ab9465106bac5b1024d2384815e34d4fbfd006b1390809554989bdde77fd46
6
+ metadata.gz: 520b7105368d998757a51606ae920dd19c26aecfed002889c4108b1daa52a00fb8d40dfad59f8c3e6130b73f1ed371316d5a6c74ba5e7598b353c67612d3f94e
7
+ data.tar.gz: d9dd0219d569e94069be492157f3bf01d3163b77a2ef86595df2086e7badd3ed7d464e0c4d9b3343b74b4780ecd27a60ad15b9b19b8348694e1ba6d92403ae15
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.2.0
1
+ ruby-2.2.3
data/.travis.yml CHANGED
@@ -6,7 +6,8 @@ rvm:
6
6
  - 1.9.3
7
7
  - 2.0.0
8
8
  - 2.1.2
9
- - 2.2.0
9
+ - 2.2.4
10
+ - 2.3.0
10
11
  script:
11
12
  - gem build aggcat.gemspec
12
13
  - gem install aggcat-*
data/README.md CHANGED
@@ -36,6 +36,7 @@ Aggcat.configure do |config|
36
36
  config.consumer_key = 'your consumer key'
37
37
  config.consumer_secret = 'your consumer secret'
38
38
  config.certificate_path = '/path/to/your/certificate/key'
39
+ config.verbose = false # verpose = true will output all raw XML API requests/responses to STDOUT
39
40
  # certificate could be provided as a string instead of a path to a file using certificate_value
40
41
  # certificate_value takes precedence over certificate_path
41
42
  # certificate_value should contain newline characters as appropriate
data/aggcat.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.required_rubygems_version = '>= 1.3.6'
23
23
 
24
24
  spec.add_dependency 'oauth', '>= 0.4'
25
- spec.add_dependency 'xmlhasher'
25
+ spec.add_dependency 'xmlhasher', '>= 1.0.2'
26
26
  spec.add_dependency 'builder', '>= 3.0'
27
27
  spec.add_dependency 'activesupport', '>= 3.2'
28
28
 
data/lib/aggcat/base.rb CHANGED
@@ -54,7 +54,7 @@ module Aggcat
54
54
  end
55
55
 
56
56
  def new_token(message)
57
- uri = URI.parse(SAML_URL)
57
+ uri = URI.parse(@oauth_url)
58
58
  http = Net::HTTP.new(uri.host, uri.port)
59
59
  request = Net::HTTP::Post.new(uri.request_uri)
60
60
  request['Authorization'] = %[OAuth oauth_consumer_key="#{@consumer_key}"]
@@ -77,7 +77,7 @@ module Aggcat
77
77
  signature_value = Base64.encode64(key.sign(OpenSSL::Digest::SHA1.new(nil), signed_info)).gsub(/\n/, '')
78
78
  signature = %[<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#_#{reference_id}"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>#{digest}</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>#{signature_value}</ds:SignatureValue></ds:Signature>]
79
79
  assertion_with_signature = assertion.sub(/saml2:Issuer\>\<saml2:Subject/, "saml2:Issuer>#{signature}<saml2:Subject")
80
- Base64.encode64(assertion_with_signature)
80
+ Base64.strict_encode64(assertion_with_signature)
81
81
  end
82
82
 
83
83
  def certificate
@@ -90,6 +90,7 @@ module Aggcat
90
90
 
91
91
  def parse_xml(data)
92
92
  return data if data.nil? || data.to_s.empty?
93
+ $stdout.puts(data) if @verbose
93
94
  @parser ||= XmlHasher::Parser.new(snakecase: true, ignore_namespaces: true)
94
95
  @parser.parse(data)
95
96
  end
data/lib/aggcat/client.rb CHANGED
@@ -5,6 +5,8 @@ module Aggcat
5
5
 
6
6
  def initialize(options={})
7
7
  raise ArgumentError.new('customer_id is required for scoping all requests') if options[:customer_id].nil? || options[:customer_id].to_s.empty?
8
+ options[:oauth_url] ||= SAML_URL
9
+ options[:base_url] ||= BASE_URL
8
10
  options[:open_timeout] ||= OPEN_TIMEOUT
9
11
  options[:read_timeout] ||= READ_TIMEOUT
10
12
  options[:verbose] ||= false
@@ -115,7 +117,7 @@ module Aggcat
115
117
  def request(http_method, path, *options)
116
118
  tries = 0
117
119
  begin
118
- response = oauth_client.send(http_method, BASE_URL + path, *options)
120
+ response = oauth_client.send(http_method, @base_url + path, *options)
119
121
  result = {:status_code => response.code, :result => parse_xml(response.body)}
120
122
  if response['challengeSessionId']
121
123
  result[:challenge_session_id] = response['challengeSessionId']
@@ -140,7 +142,9 @@ module Aggcat
140
142
 
141
143
  def credentials(institution_id, login_credentials)
142
144
  institution = institution(institution_id)
143
- raise ArgumentError.new("institution_id #{institution_id} is invalid") if institution.nil? || institution[:result].nil? || institution[:result][:institution_detail].nil?
145
+ if institution.nil? || institution[:result].nil? || institution[:result][:institution_detail].nil?
146
+ raise ArgumentError.new(institution[:result][:status][:error_info][:error_message])
147
+ end
144
148
  login_keys = institution[:result][:institution_detail][:keys][:key].select { |key| key[:display_flag] == 'true' }.sort { |a, b| a[:display_order].to_i <=> b[:display_order].to_i }
145
149
  if login_keys.length != login_credentials.length
146
150
  raise ArgumentError.new("institution_id #{institution_id} requires #{login_keys.length} credential fields but was given #{login_credentials.length} to authenticate with.")
@@ -198,5 +202,3 @@ module Aggcat
198
202
  end
199
203
  end
200
204
  end
201
-
202
-
@@ -1,7 +1,7 @@
1
1
  module Aggcat
2
2
  module Configurable
3
3
 
4
- KEYS = [:issuer_id, :consumer_key, :consumer_secret, :certificate_value, :certificate_password, :certificate_path, :customer_id, :open_timeout, :read_timeout, :verbose]
4
+ KEYS = [:oauth_url, :base_url, :issuer_id, :consumer_key, :consumer_secret, :certificate_value, :certificate_password, :certificate_path, :customer_id, :open_timeout, :read_timeout, :verbose]
5
5
 
6
6
  attr_writer *KEYS
7
7
 
@@ -1,3 +1,3 @@
1
1
  module Aggcat
2
- VERSION = '0.4.0'
2
+ VERSION = '1.0.1'
3
3
  end
@@ -1,8 +1,13 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class AggcatTest < Test::Unit::TestCase
4
+ OAUTH_URL = Aggcat::Base::SAML_URL
5
+ BASE_URL = Aggcat::Client::BASE_URL
6
+
4
7
  def setup
5
8
  Aggcat.configure do |config|
9
+ config.oauth_url = OAUTH_URL
10
+ config.base_url = BASE_URL
6
11
  config.issuer_id = 'issuer_id'
7
12
  config.consumer_key = 'consumer_key'
8
13
  config.consumer_secret = 'consumer_secret'
@@ -12,6 +17,8 @@ class AggcatTest < Test::Unit::TestCase
12
17
 
13
18
  def test_configure
14
19
  configurable = Aggcat.configure do |config|
20
+ config.oauth_url = OAUTH_URL
21
+ config.base_url = BASE_URL
15
22
  config.issuer_id = 'issuer_id'
16
23
  config.consumer_key = 'consumer_key'
17
24
  config.consumer_secret = 'consumer_secret'
@@ -19,6 +26,8 @@ class AggcatTest < Test::Unit::TestCase
19
26
  config.open_timeout = 5
20
27
  config.read_timeout = 30
21
28
  end
29
+ assert_equal OAUTH_URL, configurable.instance_variable_get(:'@oauth_url')
30
+ assert_equal BASE_URL, configurable.instance_variable_get(:'@base_url')
22
31
  assert_equal 'issuer_id', configurable.instance_variable_get(:'@issuer_id')
23
32
  assert_equal 'consumer_key', configurable.instance_variable_get(:'@consumer_key')
24
33
  assert_equal 'consumer_secret', configurable.instance_variable_get(:'@consumer_secret')
@@ -30,6 +39,8 @@ class AggcatTest < Test::Unit::TestCase
30
39
  def test_configure_certificate_by_value
31
40
  cert_value = File.read("#{fixture_path}/cert.key")
32
41
  configurable = Aggcat.configure do |config|
42
+ config.oauth_url = OAUTH_URL
43
+ config.base_url = BASE_URL
33
44
  config.issuer_id = 'issuer_id'
34
45
  config.consumer_key = 'consumer_key'
35
46
  config.consumer_secret = 'consumer_secret'
@@ -37,6 +48,8 @@ class AggcatTest < Test::Unit::TestCase
37
48
  config.open_timeout = 5
38
49
  config.read_timeout = 30
39
50
  end
51
+ assert_equal OAUTH_URL, configurable.instance_variable_get(:'@oauth_url')
52
+ assert_equal BASE_URL, configurable.instance_variable_get(:'@base_url')
40
53
  assert_equal 'issuer_id', configurable.instance_variable_get(:'@issuer_id')
41
54
  assert_equal 'consumer_key', configurable.instance_variable_get(:'@consumer_key')
42
55
  assert_equal 'consumer_secret', configurable.instance_variable_get(:'@consumer_secret')
@@ -48,12 +61,16 @@ class AggcatTest < Test::Unit::TestCase
48
61
  def test_configure_certificate_with_password
49
62
  cert_value = File.read("#{fixture_path}/cert.key")
50
63
  configurable = Aggcat.configure do |config|
64
+ config.oauth_url = OAUTH_URL
65
+ config.base_url = BASE_URL
51
66
  config.issuer_id = 'issuer_id'
52
67
  config.consumer_key = 'consumer_key'
53
68
  config.consumer_secret = 'consumer_secret'
54
69
  config.certificate_value = cert_value
55
70
  config.certificate_password = 'cert_password'
56
71
  end
72
+ assert_equal OAUTH_URL, configurable.instance_variable_get(:'@oauth_url')
73
+ assert_equal BASE_URL, configurable.instance_variable_get(:'@base_url')
57
74
  assert_equal 'issuer_id', configurable.instance_variable_get(:'@issuer_id')
58
75
  assert_equal 'consumer_key', configurable.instance_variable_get(:'@consumer_key')
59
76
  assert_equal 'consumer_secret', configurable.instance_variable_get(:'@consumer_secret')
@@ -64,6 +81,8 @@ class AggcatTest < Test::Unit::TestCase
64
81
  def test_scope
65
82
  client1 = Aggcat.scope('1')
66
83
  assert_true client1.is_a?(Aggcat::Client)
84
+ assert_equal OAUTH_URL, client1.instance_variable_get(:'@oauth_url')
85
+ assert_equal BASE_URL, client1.instance_variable_get(:'@base_url')
67
86
  assert_equal 'issuer_id', client1.instance_variable_get(:'@issuer_id')
68
87
  assert_equal 'consumer_key', client1.instance_variable_get(:'@consumer_key')
69
88
  assert_equal 'consumer_secret', client1.instance_variable_get(:'@consumer_secret')
@@ -83,7 +102,7 @@ class AggcatTest < Test::Unit::TestCase
83
102
  end
84
103
 
85
104
  def test_client_api
86
- stub_request(:post, Aggcat::Base::SAML_URL).to_return(:status => 200, :body => fixture('oauth_token.txt'))
105
+ stub_request(:post, OAUTH_URL).to_return(:status => 200, :body => fixture('oauth_token.txt'))
87
106
  Aggcat.scope('1')
88
107
  stub_get('/institutions').to_return(:body => fixture('institutions.xml'), :headers => {:content_type => 'application/xml; charset=utf-8'})
89
108
  response = Aggcat.institutions
@@ -1,8 +1,14 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class ClientTest < Test::Unit::TestCase
4
+ INTUIT_OAUTH_URL = Aggcat::Base::SAML_URL
5
+ INTUIT_BASE_URL = Aggcat::Client::BASE_URL
6
+
7
+ FINICITY_OAUTH_URL = 'https://api.finicity.com/oauth/v1/get_access_token_by_saml'
8
+ FINICITY_BASE_URL = 'https://api.finicity.com/financialdatafeed/v1'
9
+
4
10
  def setup
5
- stub_request(:post, Aggcat::Base::SAML_URL).to_return(:status => 200, :body => fixture('oauth_token.txt'))
11
+ stub_request(:post, INTUIT_OAUTH_URL).to_return(:status => 200, :body => fixture('oauth_token.txt'))
6
12
  @client = Aggcat::Client.new(
7
13
  {
8
14
  issuer_id: 'issuer_id',
@@ -12,20 +18,53 @@ class ClientTest < Test::Unit::TestCase
12
18
  customer_id: 'default'
13
19
  }
14
20
  )
21
+
22
+ stub_request(:post, FINICITY_OAUTH_URL).to_return(:status => 200, :body => fixture('oauth_token.txt'))
23
+ @finicity_client = Aggcat::Client.new(
24
+ {
25
+ oauth_url: FINICITY_OAUTH_URL,
26
+ base_url: FINICITY_BASE_URL,
27
+ issuer_id: 'issuer_id',
28
+ consumer_key: 'consumer_key',
29
+ consumer_secret: 'consumer_secret',
30
+ certificate_path: "#{fixture_path}/cert.key",
31
+ customer_id: 'default'
32
+ }
33
+ )
15
34
  end
16
35
 
17
- def test_arguments
18
- assert_equal 'issuer_id', @client.instance_variable_get(:'@issuer_id')
19
- assert_equal 'consumer_key', @client.instance_variable_get(:'@consumer_key')
20
- assert_equal 'consumer_secret', @client.instance_variable_get(:'@consumer_secret')
21
- assert_equal "#{fixture_path}/cert.key", @client.instance_variable_get(:'@certificate_path')
22
- assert_equal 'default', @client.instance_variable_get(:'@customer_id')
23
- assert_equal false, @client.instance_variable_get(:'@verbose')
36
+ def test_intuit_arguments
37
+ assert_equal INTUIT_OAUTH_URL, @client.instance_variable_get(:'@oauth_url')
38
+ assert_equal INTUIT_BASE_URL, @client.instance_variable_get(:'@base_url')
39
+ check_arguments @client
40
+ end
41
+
42
+ def test_finicity_arguments
43
+ assert_equal FINICITY_OAUTH_URL, @finicity_client.instance_variable_get(:'@oauth_url')
44
+ assert_equal FINICITY_BASE_URL, @finicity_client.instance_variable_get(:'@base_url')
45
+ check_arguments @finicity_client
46
+ end
47
+
48
+ def check_arguments(client)
49
+ assert_equal 'issuer_id', client.instance_variable_get(:'@issuer_id')
50
+ assert_equal 'consumer_key', client.instance_variable_get(:'@consumer_key')
51
+ assert_equal 'consumer_secret', client.instance_variable_get(:'@consumer_secret')
52
+ assert_equal "#{fixture_path}/cert.key", client.instance_variable_get(:'@certificate_path')
53
+ assert_equal 'default', client.instance_variable_get(:'@customer_id')
54
+ assert_equal false, client.instance_variable_get(:'@verbose')
24
55
  end
25
56
 
26
57
  def test_institutions
27
- stub_get('/institutions').to_return(:body => fixture('institutions.xml'), :headers => {:content_type => 'application/xml; charset=utf-8'})
28
- response = @client.institutions
58
+ check_institutions INTUIT_BASE_URL, @client
59
+ end
60
+
61
+ def test_finicity_institutions
62
+ check_institutions FINICITY_BASE_URL, @finicity_client
63
+ end
64
+
65
+ def check_institutions(base_url, client)
66
+ stub_request(:get, base_url + '/institutions').to_return(:body => fixture('institutions.xml'), :headers => {:content_type => 'application/xml; charset=utf-8'})
67
+ response = client.institutions
29
68
  assert_equal response[:result][:institutions][:institution][0][:institution_id].to_i, 100000
30
69
  end
31
70
 
@@ -318,8 +357,16 @@ class ClientTest < Test::Unit::TestCase
318
357
  account_id = '000000000001'
319
358
  stub_get("/accounts/#{account_id}/positions").to_return(:body => fixture('positions.xml'), :headers => {:content_type => 'application/xml; charset=utf-8'})
320
359
  response = @client.investment_positions(account_id)
321
- assert_equal response[:result][:investment_positions][:position][0][:investment_position_id].to_i , 000000000001
322
- assert_equal response[:result][:investment_positions][:position][1][:investment_position_id].to_i , 000000000002
360
+ assert_equal response[:result][:investment_positions][:position][0][:investment_position_id].to_i, 000000000001
361
+ assert_equal response[:result][:investment_positions][:position][1][:investment_position_id].to_i, 000000000002
362
+ end
363
+
364
+ def test_max_customers_reached
365
+ institution_id = '100000'
366
+ stub_get("/institutions/#{institution_id}").to_return(:body => fixture('max_customers_reached.xml'), :headers => {:content_type => 'application/xml; charset=utf-8'})
367
+ stub_post("/institutions/#{institution_id}/logins").to_return(:body => fixture('max_customers_reached.xml'), :headers => {:content_type => 'application/xml; charset=utf-8'})
368
+ exception = assert_raise(ArgumentError) { @client.discover_and_add_accounts(institution_id, 'username', 'password') }
369
+ assert_equal('The offering has reached the maximum number of customers allowed.', exception.message)
323
370
  end
324
371
 
325
372
  end
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <Status xmlns="http://schema.intuit.com/platform/fdatafeed/common/v1">
3
+ <errorInfo>
4
+ <errorType>APP_ERROR</errorType>
5
+ <errorCode>api.max.customers</errorCode>
6
+ <errorMessage>The offering has reached the maximum number of customers allowed.</errorMessage>
7
+ <correlationId>gw-49b48b84-8962-46af-9116-fdaf4fe5ac9e</correlationId>
8
+ </errorInfo>
9
+ </Status>
data/test/test_helper.rb CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
4
  require 'simplecov'
5
5
  require 'coveralls'
6
6
 
7
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
+ SimpleCov.formatters = [
8
8
  SimpleCov::Formatter::HTMLFormatter,
9
9
  Coveralls::SimpleCov::Formatter
10
10
  ]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aggcat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gene Drabkin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-11 00:00:00.000000000 Z
11
+ date: 2016-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 1.0.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 1.0.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: builder
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -113,6 +113,7 @@ files:
113
113
  - test/fixtures/institution_three_credentials.xml
114
114
  - test/fixtures/institutions.xml
115
115
  - test/fixtures/login.xml
116
+ - test/fixtures/max_customers_reached.xml
116
117
  - test/fixtures/oauth_token.txt
117
118
  - test/fixtures/positions.xml
118
119
  - test/fixtures/transactions.xml
@@ -137,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
138
  version: 1.3.6
138
139
  requirements: []
139
140
  rubyforge_project:
140
- rubygems_version: 2.4.5
141
+ rubygems_version: 2.4.5.1
141
142
  signing_key:
142
143
  specification_version: 4
143
144
  summary: Ruby client for Intuit Customer Account Data APIs
@@ -154,6 +155,7 @@ test_files:
154
155
  - test/fixtures/institution_three_credentials.xml
155
156
  - test/fixtures/institutions.xml
156
157
  - test/fixtures/login.xml
158
+ - test/fixtures/max_customers_reached.xml
157
159
  - test/fixtures/oauth_token.txt
158
160
  - test/fixtures/positions.xml
159
161
  - test/fixtures/transactions.xml