quovo 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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +12 -0
  4. data/.rubocop.yml +12 -0
  5. data/.travis.yml +6 -0
  6. data/Gemfile +10 -0
  7. data/LICENSE +21 -0
  8. data/README.md +176 -0
  9. data/Rakefile +12 -0
  10. data/bin/console +53 -0
  11. data/lib/quovo.rb +81 -0
  12. data/lib/quovo/api.rb +31 -0
  13. data/lib/quovo/api/accounts.rb +65 -0
  14. data/lib/quovo/api/base.rb +27 -0
  15. data/lib/quovo/api/brokerages.rb +21 -0
  16. data/lib/quovo/api/challenges.rb +28 -0
  17. data/lib/quovo/api/history.rb +36 -0
  18. data/lib/quovo/api/portfolios.rb +47 -0
  19. data/lib/quovo/api/positions.rb +30 -0
  20. data/lib/quovo/api/users.rb +44 -0
  21. data/lib/quovo/config.rb +61 -0
  22. data/lib/quovo/errors.rb +7 -0
  23. data/lib/quovo/fake.rb +29 -0
  24. data/lib/quovo/hook.rb +23 -0
  25. data/lib/quovo/models/account.rb +34 -0
  26. data/lib/quovo/models/base.rb +38 -0
  27. data/lib/quovo/models/brokerage.rb +15 -0
  28. data/lib/quovo/models/challenge.rb +34 -0
  29. data/lib/quovo/models/choice.rb +10 -0
  30. data/lib/quovo/models/image.rb +10 -0
  31. data/lib/quovo/models/portfolio.rb +50 -0
  32. data/lib/quovo/models/position.rb +36 -0
  33. data/lib/quovo/models/progress.rb +11 -0
  34. data/lib/quovo/models/sync.rb +20 -0
  35. data/lib/quovo/models/transaction.rb +37 -0
  36. data/lib/quovo/models/user.rb +14 -0
  37. data/lib/quovo/refinements/cast.rb +22 -0
  38. data/lib/quovo/refinements/compact.rb +11 -0
  39. data/lib/quovo/refinements/permit.rb +11 -0
  40. data/lib/quovo/refinements/require.rb +20 -0
  41. data/lib/quovo/refinements/sensitive.rb +38 -0
  42. data/lib/quovo/refinements/to_time.rb +18 -0
  43. data/lib/quovo/request.rb +114 -0
  44. data/lib/quovo/scope.rb +19 -0
  45. data/lib/quovo/token.rb +70 -0
  46. data/lib/quovo/version.rb +3 -0
  47. data/quovo.gemspec +19 -0
  48. metadata +93 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a3f2ab2081c5d4a1ba365f371b1c8784ef51a214
4
+ data.tar.gz: fb22a12ed8ccad14dc2f1bcda6e4f3dc2600bc1b
5
+ SHA512:
6
+ metadata.gz: 91c9ee1b9a94cc1d3da4a1e159e8812c829763ce322ce3514a883dc4decb783d79d58b36f08ccd0b29f2ae854a1348e8c4c42c83be3445b6f8fbf63a8f68124a
7
+ data.tar.gz: 6ed3bb5cbb6f4d51d35f522e1101150d160f6cf0fff06406174ffc17432acac2a1ec6cba7ef9bf38ecaa5465f661e595a06ec8a483f113c9167ada6f9f49c52e
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ .storage
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ coverage
12
+ .DS_Store
@@ -0,0 +1,12 @@
1
+ Style/Documentation:
2
+ Enabled: false
3
+ Metrics/MethodLength:
4
+ Enabled: false
5
+ Metrics/ParameterLists:
6
+ Enabled: false
7
+ Metrics/LineLength:
8
+ Enabled: false
9
+ Metrics/AbcSize:
10
+ Exclude:
11
+ - 'bin/console'
12
+ - 'tests/**'
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ cache: bundler
3
+ language: ruby
4
+ rvm:
5
+ - 2.2
6
+ before_install: gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'bundler'
6
+ gem 'rake'
7
+ gem 'minitest', require: false
8
+ gem 'coveralls', require: false
9
+ gem 'rubocop', require: false
10
+ gem 'pry', require: false
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2016 Canopy
2
+
3
+ The MIT License (MIT)
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,176 @@
1
+ # Quovo
2
+
3
+ Quovo RESTful API ruby client.
4
+
5
+ Read more about Quovo [here](https://new.quovo.com/api/docs/).
6
+
7
+ [![Build Status](https://travis-ci.org/CanopyFA/quovo-ruby.svg?branch=master)](https://travis-ci.org/CanopyFA/quovo-ruby) [![Coverage Status](https://coveralls.io/repos/github/CanopyFA/quovo-ruby/badge.svg?branch=master)](https://coveralls.io/github/CanopyFA/quovo-ruby?branch=master)
8
+
9
+ ## Installation
10
+
11
+ ```ruby
12
+ # Gemfile
13
+ gem 'quovo'
14
+
15
+ # run `bundle` in shell
16
+ ```
17
+
18
+ ## Configuration
19
+
20
+ ```ruby
21
+ Quovo.configurate do |config|
22
+ config.username = 'username'
23
+ config.password = 'password'
24
+ config.request_timeout = 30.seconds # by default 60 seconds
25
+ config.token_ttl = 2.hour # by default 1 hour
26
+ config.token_prefix = 'APP-NAME' # add custom prefix for token (helps to manage token list)
27
+ config.debug = true # if you want to see detailed logs
28
+ config.strip_sensitive_params = true # show [FILTERED] in logs for sensitive data
29
+ end
30
+ ```
31
+ If you use Rails put this configuration into `config/initializers/quovo.rb`.
32
+
33
+ **Note:** By default client uses in-memory storage for access tokens. If you want to use persistent storage (redis, file)
34
+ you need to set storage object in configuration:
35
+
36
+ ```ruby
37
+ Quovo.configurate do |config|
38
+ # ...
39
+ config.token_storage = Object.new.tap do |o|
40
+ def o.read(key)
41
+ # read value by key from storage
42
+ end
43
+
44
+ def o.write(key, value)
45
+ # write value by key to storage
46
+ end
47
+ end
48
+ end
49
+ ```
50
+
51
+ You can also use `Rails.cache` as storage:
52
+
53
+ ```ruby
54
+ Quovo.configurate do |config|
55
+ # ...
56
+ config.token_storage = Rails.cache
57
+ end
58
+ ```
59
+ ## Scopes and Hooks
60
+
61
+ You can scope quovo actions with user-defined hash that
62
+ could be used in hooks. Useful for action logging.
63
+
64
+ ```ruby
65
+ Quovo.scope(user: user) do
66
+ Quovo.accounts.all
67
+ end
68
+ ```
69
+
70
+ Hook is a registered callback that invokes when web request happens.
71
+
72
+ ```ruby
73
+ Quovo.hook do |path, method, params, status_code, response, elapsed_time, scope|
74
+ # path, method, params, status_code, response - attributes of web request
75
+ # elapsed_time - time in seconds of web request
76
+ # scope - user-defined hash, see docs about scopes
77
+
78
+ # log quovo action in database or file
79
+ end
80
+ ```
81
+
82
+ ## Quovo Api bindings
83
+
84
+ ### Brokerages
85
+ ```ruby
86
+ # Provides information on Quovo's supported brokerages
87
+ client.brokerages.all
88
+ # Information about single brokerage
89
+ client.brokerages.find(brokerage_id)
90
+ ```
91
+
92
+ ### Users
93
+ ```ruby
94
+ client.users.all
95
+ client.users.find(user_id)
96
+ # Creates new user
97
+ # additional parameters
98
+ # name: - client's name
99
+ # email: - client's email. Cannot match another user's email
100
+ # phone: - client's phone number
101
+ client.users.create(username)
102
+ # Updates user information
103
+ # additional parameters
104
+ # name: - client's name
105
+ # email: - client's email. Cannot match another user's email
106
+ # phone: - client's phone number
107
+ client.users.update(user_id)
108
+ client.users.delete(user_id)
109
+ ```
110
+
111
+ ### Accounts
112
+ ```ruby
113
+ client.accounts.all
114
+ client.accounts.find(id)
115
+ client.accounts.create(user_id, brokerage_id, username, password)
116
+ client.accounts.update(account_id, brokerage_id, username, password)
117
+ client.accounts.delete(account_id)
118
+ client.accounts.for_user(user_id)
119
+ # Init new sync
120
+ client.accounts.sync!(account_id)
121
+ # Get sync status
122
+ client.accounts.sync(account_id)
123
+ ```
124
+
125
+ ### Challenges
126
+ ```ruby
127
+ client.challenges.for_account(account_id)
128
+ # for text, image questions
129
+ client.challenges.answers!(account_id, [{question: 'question text', answer: 'answer text'}])
130
+ # for choice questions
131
+ client.challenges.answers!(account_id, [{question: 'question text', answer: 0}])
132
+ ```
133
+
134
+ ### History
135
+ ```ruby
136
+ client.history.all
137
+ # additional parameters
138
+ # start: - pointer to next set of items
139
+ # count: - max number of results to return
140
+ # start_date: - filters out history before this date
141
+ # end_date: - filters out history after this date
142
+ # start_id: - filters out history before this id
143
+ # end_id: - filters out history after this id
144
+ client.history.for_user(user_id)
145
+ client.history.for_account(account_id)
146
+ client.history.for_portfolio(portfolio_id)
147
+ ```
148
+
149
+ ### Portfolios
150
+ ```ruby
151
+ client.portfolios.all
152
+ client.portfolios.find(portfolio_id)
153
+ client.portfolios.update(portfolio_id, nickname, portfolio_type, is_inactive)
154
+ client.portfolios.for_user(user_id)
155
+ client.portfolios.for_account(account_id)
156
+ ```
157
+
158
+ ### Positions
159
+ ```ruby
160
+ # Load all positions
161
+ # additional parameters
162
+ # start: - pointer to next set of items
163
+ # count: - max number of results to return
164
+ client.positions.all
165
+ client.positions.for_user(user_id)
166
+ client.positions.for_account(account_id)
167
+ client.positions.for_portfolio(portfolio_id)
168
+ ```
169
+
170
+ ## Contributors
171
+ * Canopy Financials [https://www.canopyfa.com](https://www.canopyfa.com)
172
+ * Castle Digital Partners [https://castle.co](https://castle.co)
173
+
174
+ ## License
175
+
176
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'rubocop/rake_task'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'tests'
7
+ t.pattern = 'tests/**/*_test.rb'
8
+ end
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: [:rubocop, :test]
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'quovo'
5
+ require 'pry'
6
+ require 'json'
7
+
8
+ def reconfigure!
9
+ Quovo.configure do |config|
10
+ config.username = ARGV[0]
11
+ config.password = ARGV[1]
12
+ config.debug = true
13
+ config.token_storage = Object.new.tap do |o|
14
+ def o.path
15
+ '../.storage'
16
+ end
17
+
18
+ def o.storage
19
+ @storage ||= begin
20
+ data = File.exist?(path) ? File.read(path) : nil
21
+ data ? JSON.parse(data) : {}
22
+ end
23
+ end
24
+
25
+ def o.read(key)
26
+ storage[key]
27
+ end
28
+
29
+ def o.write(key, value)
30
+ storage[key] = value
31
+ File.write(path, storage.to_json)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def reload!
38
+ Quovo.instance_variables.each do |var|
39
+ Quovo.instance_variable_set(var, nil)
40
+ end
41
+ Quovo.clear_hooks!
42
+ original_verbose = $VERBOSE
43
+ $VERBOSE = nil
44
+ $LOADED_FEATURES
45
+ .select { |file| file =~ %r{\/quovo\/} }
46
+ .each { |file| load(file) }
47
+ $VERBOSE = original_verbose
48
+ reconfigure!
49
+ 'Reloaded!'
50
+ end
51
+
52
+ reconfigure!
53
+ Pry.start
@@ -0,0 +1,81 @@
1
+ require 'json'
2
+ require 'uri'
3
+ require 'time'
4
+ require 'base64'
5
+ require 'forwardable'
6
+ require 'net/http'
7
+ require 'openssl'
8
+
9
+ require 'quovo/refinements/require'
10
+ require 'quovo/refinements/to_time'
11
+ require 'quovo/refinements/cast'
12
+ require 'quovo/refinements/compact'
13
+ require 'quovo/refinements/permit'
14
+ require 'quovo/refinements/sensitive'
15
+
16
+ require 'quovo/errors'
17
+
18
+ require 'quovo/scope'
19
+ require 'quovo/hook'
20
+ require 'quovo/version'
21
+ require 'quovo/config'
22
+ require 'quovo/request'
23
+ require 'quovo/token'
24
+ require 'quovo/fake'
25
+
26
+ require 'quovo/models/base'
27
+ require 'quovo/models/account'
28
+ require 'quovo/models/brokerage'
29
+ require 'quovo/models/choice'
30
+ require 'quovo/models/image'
31
+ require 'quovo/models/challenge'
32
+ require 'quovo/models/progress'
33
+ require 'quovo/models/sync'
34
+ require 'quovo/models/portfolio'
35
+ require 'quovo/models/user'
36
+ require 'quovo/models/position'
37
+ require 'quovo/models/transaction'
38
+
39
+ require 'quovo/api/base'
40
+ require 'quovo/api/brokerages'
41
+ require 'quovo/api/accounts'
42
+ require 'quovo/api/challenges'
43
+ require 'quovo/api/portfolios'
44
+ require 'quovo/api/users'
45
+ require 'quovo/api/positions'
46
+ require 'quovo/api/history'
47
+ require 'quovo/api'
48
+
49
+ module Quovo
50
+ extend Quovo::Config.configurator
51
+ extend Quovo::Scope
52
+ extend Quovo::Hook
53
+ extend Quovo::Api
54
+ extend Quovo::Fake
55
+
56
+ def self.inspect
57
+ config.inspect
58
+ end
59
+
60
+ def self.enable_logging
61
+ Quovo.hook do |path, method, params, status_code, response, elapsed_time, scope|
62
+ if Quovo.config.debug
63
+ log = [
64
+ '',
65
+ 'Quovo Action:',
66
+ "path: #{path}",
67
+ "method: #{method}",
68
+ "params: #{params.inspect}",
69
+ "status_code: #{status_code}",
70
+ "response: #{response.inspect}",
71
+ "elapsed_time: #{elapsed_time}s",
72
+ "scope: #{scope.inspect}",
73
+ ''
74
+ ]
75
+ puts log.join("\n ")
76
+ end
77
+ end
78
+ end
79
+
80
+ enable_logging
81
+ end
@@ -0,0 +1,31 @@
1
+ module Quovo
2
+ module Api
3
+ def brokerages
4
+ @brokerages ||= Quovo::Api::Brokerages.new
5
+ end
6
+
7
+ def accounts
8
+ @accounts ||= Quovo::Api::Accounts.new
9
+ end
10
+
11
+ def challenges
12
+ @challenges ||= Quovo::Api::Challenges.new
13
+ end
14
+
15
+ def portfolios
16
+ @portfolios ||= Quovo::Api::Portfolios.new
17
+ end
18
+
19
+ def users
20
+ @users ||= Quovo::Api::Users.new
21
+ end
22
+
23
+ def positions
24
+ @positions ||= Quovo::Api::Positions.new
25
+ end
26
+
27
+ def history
28
+ @history ||= Quovo::Api::History.new
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,65 @@
1
+ module Quovo
2
+ module Api
3
+ class Accounts < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Require
6
+ using Quovo::Refinements::Permit
7
+
8
+ def all
9
+ api(:get, '/accounts')
10
+ .fetch('accounts')
11
+ .cast(Account)
12
+ end
13
+
14
+ def find(id)
15
+ id.require!(as: :id)
16
+ api(:get, "/accounts/#{id}")
17
+ .fetch('account')
18
+ .cast(Account)
19
+ end
20
+
21
+ def create(params)
22
+ params.require!(:user, :brokerage, :username, :password)
23
+ api(:post, '/accounts', params)
24
+ .fetch('account')
25
+ .cast(Account)
26
+ end
27
+
28
+ def update(id, params)
29
+ id.require!(as: :id)
30
+ params
31
+ .permit!(:brokerage, :username, :password)
32
+ params.require!(:username, :password) if params[:username] || params[:password]
33
+ api(:put, "/accounts/#{id}", params)
34
+ .fetch('account')
35
+ .cast(Account)
36
+ end
37
+
38
+ def delete(id)
39
+ id.require!(as: :id)
40
+ api(:delete, "/accounts/#{id}")
41
+ end
42
+
43
+ def for_user(id)
44
+ id.require!(as: :id)
45
+ api(:get, "/users/#{id}/accounts")
46
+ .fetch('accounts')
47
+ .cast(Account)
48
+ end
49
+
50
+ def sync!(id)
51
+ id.require!(as: :id)
52
+ api(:post, "/accounts/#{id}/sync")
53
+ .fetch('sync')
54
+ .cast(Sync)
55
+ end
56
+
57
+ def sync(id)
58
+ id.require!(as: :id)
59
+ api(:get, "/accounts/#{id}/sync")
60
+ .fetch('sync')
61
+ .cast(Sync)
62
+ end
63
+ end
64
+ end
65
+ end