finapps 0.0.14.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7258bf7333018dffd9148db974ba790c694d9608
4
+ data.tar.gz: 6ea476c463319fd83bcac0dcbca13d8ba6fe8695
5
+ SHA512:
6
+ metadata.gz: 5833149eb9fcc599b371415869a4807c300ddebef40a669d9195db7232e8cceb8dc420c6ad806f402d67dd3e66ee9ae23f49dc087401c7e04ec321a2b7a92255
7
+ data.tar.gz: ef79908cc3aee6c4a561414a782544cb5538ada3b2577ab955a49e60ae8e8680ab8435244a0b9fa1978f26a8adccdbf8e42e613abd12889ed09072eec097e96c
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ finapps
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p481
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 qbantek
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ FinApps Ruby-Client
2
+ ===================
3
+
4
+ Ruby client for [FinApps][financialapps].
5
+
6
+ A simple library for communicating with the [FinApps][financialapps] REST API.
7
+
8
+
9
+
10
+ ## Installation
11
+
12
+
13
+ To install using [Bundler][bundler], add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ # Gemfile
17
+ gem 'finapps'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ ```bash
23
+ $ bundle
24
+ ```
25
+
26
+ Or install it yourself as:
27
+
28
+ ```bash
29
+ $ gem install finapps
30
+ ```
31
+
32
+
33
+
34
+ ## Getting started with FinApps REST client
35
+
36
+ ### Setup
37
+
38
+ You will need to authenticate every API call using your FinApps company credentials.
39
+
40
+ Please visit [FinApps][financialapps] if you still haven't setup your account with Financial Apps or have any issues locating your company credentials.
41
+
42
+
43
+ ``` ruby
44
+ require 'finapps'
45
+
46
+ # replace with your own credentials here
47
+ company_identifier = 'my-company-identifier'
48
+ company_token = 'my-company-token'
49
+
50
+ # set up a client to talk to the FinApps REST API
51
+ @client = FinApps::REST::Client.new company_identifier, company_token
52
+ ```
53
+
54
+ ## More Information
55
+
56
+ Please check the [FinApps wiki][wiki] for extended documentation.
57
+
58
+
59
+ [FinancialApps.com][financialapps]
60
+
61
+
62
+ [bundler]: http://bundler.io
63
+ [financialapps]: https://financialapps.com
64
+ [wiki]: https://github.com/finapps/ruby-client/wiki
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+
data/bin/finapps ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'finapps/cli/common'
3
+ require 'finapps/cli/users'
4
+ require 'finapps/cli/institutions'
5
+
6
+ FinApps::CLI.start
data/finapps.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'finapps/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'finapps'
8
+ spec.version = FinApps::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.authors = ['Erich Quintero']
11
+ spec.email = ['erich@financialapps.com']
12
+
13
+ spec.summary = %q{FinApps REST API ruby client.}
14
+ spec.description = %q{A simple library for communicating with the FinApps REST API.}
15
+ spec.homepage = 'http://github.com/finapps/finapps-ruby'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = Dir['spec/**/*.rb']
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_runtime_dependency 'thor', '~> 0.19', '>= 0.19.1'
24
+ spec.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.0'
25
+ spec.add_runtime_dependency 'faraday_middleware', '~> 0.9', '>= 0.9.1'
26
+ spec.add_runtime_dependency 'typhoeus', '~> 0.6', '>= 0.6.8'
27
+ spec.add_runtime_dependency 'rash', '~> 0.4', '>= 0.4.0'
28
+
29
+ spec.add_development_dependency 'bundler', '~> 1.6', '>= 1.6.2'
30
+ spec.add_development_dependency 'rake', '~> 0.9', '>= 0.9.6'
31
+ spec.add_development_dependency 'rspec', '~> 3.0', '>= 3.0.0'
32
+
33
+ spec.extra_rdoc_files = %w(README.md LICENSE.txt)
34
+ spec.rdoc_options = %w(--line-numbers --inline-source --title finapps-ruby --main README.md)
35
+ end
@@ -0,0 +1,40 @@
1
+ require 'thor'
2
+ require 'finapps'
3
+
4
+
5
+ module FinApps
6
+ class CLI < Thor
7
+
8
+ desc 'create_client', 'initialize API REST Client'
9
+
10
+ def create_client
11
+ puts client
12
+ end
13
+
14
+ private
15
+
16
+ def client
17
+ company_id = ENV['FA_ID']
18
+ raise 'Invalid company identifier. Please setup the FA_ID environment variable.' if company_id.blank?
19
+
20
+ company_token = ENV['FA_TOKEN']
21
+ raise 'Invalid company token. Please setup the FA_TOKEN environment variable.' if company_token.blank?
22
+
23
+ host = ENV['FA_URL']
24
+ raise 'Invalid API host url. Please setup the FA_URL environment variable.' if host.blank?
25
+
26
+ @client ||= FinApps::REST::Client.new company_id, company_token, {:host => host, :log_level => Logger::DEBUG,
27
+ :request_uuid => 'le-request-uuid-z',
28
+ :session_id => 'da-session-idz'}
29
+ end
30
+
31
+ def rescue_standard_error(error)
32
+ puts '=============================='
33
+ puts 'Error:'
34
+ p error
35
+ puts "Backtrace:\n\t#{error.backtrace.join("\n\t")}"
36
+ puts '=============================='
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ require 'thor'
2
+ require 'finapps'
3
+ require 'securerandom'
4
+ require 'pp'
5
+
6
+ module FinApps
7
+ class CLI < Thor
8
+
9
+ desc 'institutions_search', 'search institutions'
10
+
11
+ def institutions_search(user_identifier, user_token, term=nil)
12
+
13
+ begin
14
+ client.user_credentials!(user_identifier, user_token)
15
+ institutions, error_messages = client.institutions.search term
16
+ if institutions.present?
17
+ puts
18
+ puts 'search results:'
19
+ pp institutions
20
+ else
21
+ puts
22
+ puts 'unable to search institutions'
23
+ error_messages.each { |m| puts m } if error_messages.present?
24
+ end
25
+ puts
26
+
27
+ rescue StandardError => error
28
+ rescue_standard_error(error)
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,87 @@
1
+ require 'thor'
2
+ require 'finapps'
3
+ require 'securerandom'
4
+ require 'pp'
5
+
6
+ module FinApps
7
+ class CLI < Thor
8
+
9
+ desc 'user_create', 'creates a new API user'
10
+
11
+ def user_create(email=nil, password=nil)
12
+
13
+ begin
14
+ email ||= "test-#{SecureRandom.uuid}@powerwallet.com"
15
+ password ||= 'Power1'
16
+ user, error_messages = client.users.create ({:email => email,
17
+ :password => password,
18
+ :password_confirm => password,
19
+ :postal_code => '33021'})
20
+ if user.present?
21
+ puts
22
+ puts 'user created:'
23
+ pp user
24
+ else
25
+ puts
26
+ puts 'unable to create user'
27
+ error_messages.each { |m| puts m } if error_messages.present?
28
+ end
29
+ puts
30
+
31
+ rescue StandardError => error
32
+ rescue_standard_error(error)
33
+ end
34
+
35
+ end
36
+
37
+ desc 'user_login', 'creates a new API user and signs in'
38
+
39
+ def user_login(email=nil, password=nil)
40
+
41
+ begin
42
+ email ||= "test-#{SecureRandom.uuid}@powerwallet.com"
43
+ password ||= 'WrongPassword'
44
+ user, error_messages = client.users.login ({:email => email, :password => password})
45
+ if user.present?
46
+ puts
47
+ puts 'user logged in:'
48
+ pp user
49
+ else
50
+ puts
51
+ puts 'unable to login user'
52
+ error_messages.each { |m| puts m } if error_messages.present?
53
+ end
54
+ puts
55
+
56
+ rescue StandardError => error
57
+ rescue_standard_error(error)
58
+ end
59
+
60
+ end
61
+
62
+ desc 'user_delete', 'deletes an API user'
63
+
64
+ def user_delete(public_id=nil)
65
+
66
+ begin
67
+ public_id ||= SecureRandom.uuid.to_s
68
+
69
+ error_messages = client.users.delete (public_id)
70
+ if error_messages.blank?
71
+ puts
72
+ puts 'user deleted!'
73
+ else
74
+ puts
75
+ puts 'unable to delete user'
76
+ error_messages.each { |m| puts m }
77
+ end
78
+ puts
79
+
80
+ rescue StandardError => error
81
+ rescue_standard_error(error)
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,25 @@
1
+ module FinApps
2
+ module Middleware
3
+
4
+ class ApiToken < Faraday::Middleware
5
+ include FinApps::Logging
6
+
7
+ def initialize(app, options={})
8
+ @app = app
9
+ @options = options
10
+ end
11
+
12
+ def call(env)
13
+ raise MissingArgumentsError.new 'Missing argument: company_identifier.' if @options[:company_identifier].blank?
14
+ raise MissingArgumentsError.new 'Missing argument: company_token.' if @options[:company_token].blank?
15
+
16
+ header_value = "#{@options[:company_identifier].trim}=#{@options[:company_token].trim}"
17
+ logger.debug "##{__method__.to_s} => Request Header X-FinApps-Token: #{header_value}"
18
+ env[:request_headers]['X-FinApps-Token'] = header_value
19
+
20
+ @app.call(env)
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,91 @@
1
+ module FinApps
2
+ module Middleware
3
+
4
+ class RaiseHttpExceptions < Faraday::Response::Middleware
5
+ include FinApps::Logging
6
+
7
+ CLIENT_ERROR_STATUSES = 400...600
8
+
9
+ def on_complete(env)
10
+
11
+ case env[:status]
12
+ when 400
13
+ raise FinApps::REST::BadRequest, response_values(env, 'The request could not be understood by the server due to malformed syntax.')
14
+ when 401
15
+ raise FinApps::REST::Unauthorized, response_values(env, 'The request requires user authentication.')
16
+ when 403
17
+ raise FinApps::REST::Forbidden, response_values(env, 'Forbidden.')
18
+ when 404
19
+ raise FinApps::REST::NotFound, response_values(env, 'Page not found.')
20
+ when 405
21
+ raise FinApps::REST::MethodNotAllowed, response_values(env, 'The method specified in the Request-Line is not allowed for the resource identified by the Request-URI.')
22
+ when 406
23
+ raise FinApps::REST::NotAcceptable, response_values(env, 'The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request')
24
+ when 407
25
+ raise Faraday::Error::ConnectionFailed, response_values(env, 'Proxy Authentication Required.')
26
+ when 409
27
+ raise FinApps::REST::Conflict, response_values(env, 'The request could not be completed due to a conflict with the current state of the resource.')
28
+
29
+ when 500
30
+ raise FinApps::REST::InternalServerError, response_values(env, 'Unexpected technical condition was encountered.')
31
+ when 502
32
+ raise FinApps::REST::BadGateway, response_values(env, 'The server returned an invalid or incomplete response.')
33
+ when 503
34
+ raise FinApps::REST::ServiceUnavailable, response_values(env, 'The server is currently unavailable.')
35
+ when 504
36
+ raise FinApps::REST::GatewayTimeout, response_values(env, 'Gateway Time-out')
37
+ when 505
38
+ raise FinApps::REST::VersionNotSupported, response_values(env, 'The Web server does not support the specified HTTP protocol version.')
39
+
40
+ when CLIENT_ERROR_STATUSES
41
+ raise FinApps::REST::Error, response_values(env, 'Unexpected error.')
42
+
43
+ else
44
+ # 200..206 Success codes
45
+ # all good!
46
+ logger.debug "##{__method__.to_s} => Status code: [#{env[:status]}]."
47
+ end
48
+
49
+ end
50
+
51
+ private
52
+
53
+ def error_messages(body)
54
+ error_array = Array.new
55
+
56
+ if body.present? && body.kind_of?(String)
57
+ begin
58
+ parsed = ::JSON.parse(body)
59
+ if parsed
60
+ parsed.each do |key, value|
61
+ value.each do |message|
62
+ logger.debug "#{key} => #{message}"
63
+ error_array.push message.to_s
64
+ end
65
+ end
66
+ else
67
+ logger.info "##{__method__.to_s} => Cannot extract errors: unexpected error while parsing response."
68
+ end
69
+ rescue ::JSON::ParserError => e
70
+ logger.error "##{__method__.to_s} => Unable to parse JSON response."
71
+ logger.error e
72
+ end
73
+ end
74
+
75
+ error_array
76
+ end
77
+
78
+ def response_values(env, status_message = nil)
79
+ {
80
+ :status => env.status,
81
+ :status_message => status_message,
82
+ :headers => env.response_headers,
83
+ :body => env.body,
84
+ :error_messages => error_messages(env.body)
85
+ }
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ module FinApps
2
+ module Middleware
3
+
4
+ class ResponseLogger < Faraday::Response::Middleware
5
+ include FinApps::Logging
6
+
7
+ def call(env)
8
+ logger.info "##{env.method} #{env.url.to_s}"
9
+ logger.debug('Request Headers') { dump_headers env.request_headers }
10
+ super
11
+ end
12
+
13
+ def on_complete(env)
14
+ logger.info "Status: #{env.status.to_s}"
15
+ logger.debug('Response Headers') { dump_headers env.response_headers }
16
+ logger.debug('Response Body') {dump_body env.body } if env.body
17
+ end
18
+
19
+ private
20
+ def dump_headers(headers)
21
+ "\n" << headers.map { |k, v| " #{k}: #{filter_sensitive_header_values(k,v)}" }.join("\n")
22
+ end
23
+
24
+ def filter_sensitive_header_values(key, value)
25
+ case key
26
+ when 'X-FinApps-Token', 'Basic-Authorization'
27
+ value.inspect
28
+ else
29
+ '[REDACTED]'
30
+ end
31
+ end
32
+
33
+ def dump_body(body)
34
+ "\n" << body
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ module FinApps
2
+ module REST
3
+
4
+ class Accounts < FinApps::REST::Resources
5
+
6
+ end
7
+
8
+ class Account < FinApps::REST::Resource
9
+ attr_accessor :public_id
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,154 @@
1
+ module FinApps
2
+ module REST
3
+ class Client
4
+ include FinApps::REST::Defaults
5
+ include FinApps::Logging
6
+ include FinApps::REST::Connection
7
+
8
+ attr_reader :users, :institutions
9
+
10
+ # @param [String] company_identifier
11
+ # @param [String] company_token
12
+ # @param [Hash] options
13
+ # @return [FinApps::REST::Client]
14
+ def initialize(company_identifier, company_token, options = {})
15
+ logger.debug "##{__method__.to_s} => Started"
16
+
17
+ @config = DEFAULTS.merge! options
18
+ if @config[:logger_tag].present?
19
+ Logging.tag= @config[:logger_tag]
20
+ logger.info "##{__method__.to_s} => Added custom tag for logger."
21
+ end
22
+
23
+ set_up_logger_level @config[:log_level]
24
+ logger.info "##{__method__.to_s} => Current logger level: #{SEVERITY_LABEL[logger.level]}"
25
+
26
+ @company_credentials = {:company_identifier => company_identifier,
27
+ :company_token => company_token}
28
+ @connection = set_up_connection(@company_credentials, @config)
29
+ logger.debug "##{__method__.to_s} => Connection initialized"
30
+
31
+ set_up_resources
32
+ logger.debug "##{__method__.to_s} => All resources initialized"
33
+
34
+ logger.debug "##{__method__.to_s} => Completed"
35
+ end
36
+
37
+ # Performs an HTTP GET request. You shouldn't need to use this method directly,
38
+ # but it can be useful for debugging. Returns a hash obtained from parsing
39
+ # the JSON object in the response body.
40
+ #
41
+ # @param [String] path
42
+ # @param [Proc] proc
43
+ # @return [Hash,Array<String>]
44
+ def get(path, &proc)
45
+ logger.debug "##{__method__.to_s} => Started"
46
+ response, result, error_messages = nil, nil, nil
47
+
48
+ begin
49
+ logger.debug "##{__method__.to_s} => GET path:#{path}"
50
+ response = @connection.get { |req| req.url path }
51
+ if response.present? && block_given?
52
+ result = proc.call(response)
53
+ logger.debug "##{__method__.to_s} => parsed result: #{result.pretty_inspect}" if result.present?
54
+
55
+ end
56
+ rescue FinApps::REST::Error => error
57
+ error_messages = error.error_messages
58
+ logger.debug "##{__method__.to_s} => Failed, error_messages: #{error_messages.pretty_inspect}" if error_messages.present?
59
+ end
60
+
61
+ logger.debug "##{__method__.to_s} => Completed"
62
+ return result, error_messages
63
+ end
64
+
65
+ # Performs an HTTP POST request. You shouldn't need to use this method directly,
66
+ # but it can be useful for debugging. Returns a hash obtained from parsing
67
+ # the JSON object in the response body.
68
+ #
69
+ # @param [String] path
70
+ # @param [Hash] params
71
+ # @param [Proc] proc
72
+ # @return [Hash,Array<String>]
73
+ def post(path, params = {}, &proc)
74
+ logger.debug "##{__method__.to_s} => Started"
75
+ response, result, error_messages = nil, nil, nil
76
+
77
+ begin
78
+ logger.debug "##{__method__.to_s} => POST path:#{path} params:#{skip_sensitive_data(params)}"
79
+ response = @connection.post do |req|
80
+ req.url path
81
+ req.body = params
82
+ end
83
+ if response.present? && block_given?
84
+ result = proc.call(response)
85
+ logger.debug "##{__method__.to_s} => parsed result: #{result.pretty_inspect}" if result.present?
86
+ end
87
+
88
+ rescue FinApps::REST::Error => error
89
+ error_messages = error.error_messages
90
+ logger.debug "##{__method__.to_s} => Failed, error_messages: #{error_messages.pretty_inspect}" if error_messages.present?
91
+ end
92
+
93
+ logger.debug "##{__method__.to_s} => Completed"
94
+ return result, error_messages
95
+ end
96
+
97
+ # Performs an HTTP DELETE request. You shouldn't need to use this method directly,
98
+ # but it can be useful for debugging. Returns a hash obtained from parsing
99
+ # the JSON object in the response body.
100
+ #
101
+ # @param [String] path
102
+ # @param [Hash] params
103
+ # @param [Proc] proc
104
+ # @return [Hash,Array<String>]
105
+ def delete(path, params = {}, &proc)
106
+ logger.debug "##{__method__.to_s} => Started"
107
+ response, result, error_messages = nil, nil, nil
108
+
109
+ begin
110
+ logger.debug "##{__method__.to_s} => DELETE path:#{path} params:#{skip_sensitive_data(params)}"
111
+ response = @connection.delete do |req|
112
+ req.url path
113
+ req.body = params
114
+ end
115
+ if response.present? && block_given?
116
+ result = proc.call(response)
117
+ logger.debug "##{__method__.to_s} => parsed result: #{result.pretty_inspect}" if result.present?
118
+ end
119
+
120
+ rescue FinApps::REST::Error => error
121
+ error_messages = error.error_messages
122
+ logger.debug "##{__method__.to_s} => Failed, error_messages: #{error_messages.pretty_inspect}" if error_messages.present?
123
+ end
124
+
125
+ logger.debug "##{__method__.to_s} => Completed"
126
+ return result, error_messages
127
+ end
128
+
129
+ # @param [String] user_identifier
130
+ # @param [String] user_token
131
+ def user_credentials!(user_identifier, user_token)
132
+ logger.debug "##{__method__.to_s} => Started"
133
+
134
+ {:user_identifier => user_identifier, :user_token => user_token}.validate_required_strings!
135
+ logger.debug "##{__method__.to_s} => Credentials passed validation. Attempting to set user credentials on current connection."
136
+
137
+
138
+ @config[:user_identifier] = user_identifier
139
+ @config[:user_token] = user_token
140
+ @connection = set_up_connection(@company_credentials, @config)
141
+
142
+ logger.debug "##{__method__.to_s} => Completed"
143
+ end
144
+
145
+ private
146
+
147
+ def set_up_resources
148
+ @users ||= FinApps::REST::Users.new self
149
+ @institutions ||= FinApps::REST::Institutions.new self
150
+ end
151
+
152
+ end
153
+ end
154
+ end