quovo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,27 @@
1
+ module Quovo
2
+ module Api
3
+ class Base
4
+ include Quovo::Models
5
+ include Quovo::Request
6
+
7
+ def initialize(token = Quovo::Token.new)
8
+ @token = token
9
+ end
10
+
11
+ def api(method, path, params = {})
12
+ format = case method
13
+ when :delete
14
+ :plain
15
+ else
16
+ :json
17
+ end
18
+
19
+ request(method, path, params, format) do |req|
20
+ req['Authorization'] = "Bearer #{token.get}"
21
+ end || {}
22
+ end
23
+
24
+ attr_reader :token
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Quovo
2
+ module Api
3
+ class Brokerages < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Require
6
+
7
+ def all
8
+ api(:get, '/brokerages')
9
+ .fetch('brokerages')
10
+ .cast(Brokerage)
11
+ end
12
+
13
+ def find(id)
14
+ id.require!(as: :id)
15
+ api(:get, "/brokerages/#{id}")
16
+ .fetch('brokerage')
17
+ .cast(Brokerage)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ module Quovo
2
+ module Api
3
+ class Challenges < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Require
6
+
7
+ def for_account(id)
8
+ id.require!(as: :id)
9
+ api(:get, "/accounts/#{id}/challenges")
10
+ .fetch('challenges')
11
+ .cast(Challenge)
12
+ end
13
+
14
+ def answers!(account_id, answers)
15
+ account_id.require!(as: 'account_id')
16
+ answers.require!(as: 'answers')
17
+ answers.each do |answer|
18
+ answer.require!(:answer, :question)
19
+ end
20
+
21
+ params = { questions: answers.to_json }
22
+ api(:put, "/accounts/#{account_id}/challenges", params)
23
+ .fetch('challenges')
24
+ .cast(Challenge)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ module Quovo
2
+ module Api
3
+ class History < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Require
6
+ using Quovo::Refinements::Permit
7
+
8
+ def for_user(id, params = {})
9
+ id.require!(as: :id)
10
+ params.permit!(:start_date, :end_date, :start_id, :end_id)
11
+ api(:get, "/users/#{id}/history", params)
12
+ .fetch('history')
13
+ .cast(Transaction)
14
+ .sort_by(&:sort_key)
15
+ end
16
+
17
+ def for_account(id, params = {})
18
+ id.require!(as: :id)
19
+ params.permit!(:start_date, :end_date, :start_id, :end_id)
20
+ api(:get, "/accounts/#{id}/history", params)
21
+ .fetch('history')
22
+ .cast(Transaction)
23
+ .sort_by(&:sort_key)
24
+ end
25
+
26
+ def for_portfolio(id, params = {})
27
+ id.require!(as: :id)
28
+ params.permit!(:start_date, :end_date, :start_id, :end_id)
29
+ api(:get, "/portfolios/#{id}/history", params)
30
+ .fetch('history')
31
+ .cast(Transaction)
32
+ .sort_by(&:sort_key)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ module Quovo
2
+ module Api
3
+ class Portfolios < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Compact
6
+ using Quovo::Refinements::Permit
7
+ using Quovo::Refinements::Require
8
+
9
+ def all
10
+ api(:get, '/portfolios')
11
+ .fetch('portfolios')
12
+ .cast(Portfolio)
13
+ end
14
+
15
+ def find(id)
16
+ id.require!(as: :id)
17
+ api(:get, "/portfolios/#{id}")
18
+ .fetch('portfolio')
19
+ .cast(Portfolio)
20
+ end
21
+
22
+ def update(id, params)
23
+ id.require!(as: :id)
24
+ params
25
+ .permit!(:nickname, :portfolio_type, :is_inactive)
26
+ .compact!
27
+ api(:put, "/portfolios/#{id}", params)
28
+ .fetch('portfolio')
29
+ .cast(Portfolio)
30
+ end
31
+
32
+ def for_user(id)
33
+ id.require!(as: :id)
34
+ api(:get, "/users/#{id}/portfolios")
35
+ .fetch('portfolios')
36
+ .cast(Portfolio)
37
+ end
38
+
39
+ def for_account(id)
40
+ id.require!(as: :id)
41
+ api(:get, "/accounts/#{id}/portfolios")
42
+ .fetch('portfolios')
43
+ .cast(Portfolio)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ module Quovo
2
+ module Api
3
+ class Positions < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Permit
6
+ using Quovo::Refinements::Require
7
+
8
+ def for_user(id)
9
+ id.require!(as: :id)
10
+ api(:get, "/users/#{id}/positions")
11
+ .fetch('positions')
12
+ .cast(Position)
13
+ end
14
+
15
+ def for_account(id)
16
+ id.require!(as: :id)
17
+ api(:get, "/accounts/#{id}/positions")
18
+ .fetch('positions')
19
+ .cast(Position)
20
+ end
21
+
22
+ def for_portfolio(id)
23
+ id.require!(as: :id)
24
+ api(:get, "/portfolios/#{id}/positions")
25
+ .fetch('positions')
26
+ .cast(Position)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,44 @@
1
+ module Quovo
2
+ module Api
3
+ class Users < Base
4
+ using Quovo::Refinements::Cast
5
+ using Quovo::Refinements::Require
6
+ using Quovo::Refinements::Permit
7
+
8
+ def all
9
+ api(:get, '/users')
10
+ .fetch('users')
11
+ .cast(User)
12
+ end
13
+
14
+ def find(id)
15
+ id.require!(as: :id)
16
+ api(:get, "/users/#{id}")
17
+ .fetch('user')
18
+ .cast(User)
19
+ end
20
+
21
+ def create(params)
22
+ params
23
+ .permit!(:username, :name, :email, :phone)
24
+ .require!(:username)
25
+ api(:post, '/users', params)
26
+ .fetch('user')
27
+ .cast(User)
28
+ end
29
+
30
+ def update(id, params)
31
+ id.require!(as: :id)
32
+ params.permit!(:name, :email, :phone)
33
+ api(:put, "/users/#{id}", params)
34
+ .fetch('user')
35
+ .cast(User)
36
+ end
37
+
38
+ def delete(id)
39
+ id.require!(as: :id)
40
+ api(:delete, "/users/#{id}")
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ module Quovo
2
+ class Config
3
+ attr_accessor :username
4
+ attr_accessor :password
5
+ attr_accessor :token_ttl # seconds
6
+ attr_accessor :request_timeout # seconds
7
+ attr_accessor :token_prefix
8
+ attr_accessor :token_storage
9
+ attr_accessor :debug
10
+ attr_accessor :strip_sensitive_params
11
+
12
+ DEFAULT_ENDPOINT = 'https://api.quovo.com/v2'.freeze
13
+
14
+ def initialize
15
+ @username = nil
16
+ @password = nil
17
+ @token_ttl = 60 * 60
18
+ @request_timeout = 60
19
+ @token_prefix = 'QUOVO-ACCESS-TOKEN'
20
+ @token_storage = default_memory_storage
21
+ @debug = false
22
+ @strip_sensitive_params = true
23
+ end
24
+
25
+ def endpoint
26
+ DEFAULT_ENDPOINT
27
+ end
28
+
29
+ def [](option)
30
+ send(option)
31
+ end
32
+
33
+ def self.configurator
34
+ @conf_mod ||= Module.new do
35
+ def configure
36
+ yield(config)
37
+ end
38
+
39
+ def config
40
+ @config ||= Config.new
41
+ end
42
+ end
43
+ end
44
+
45
+ def default_memory_storage
46
+ Object.new.tap do |o|
47
+ def o.storage
48
+ @storage ||= {}
49
+ end
50
+
51
+ def o.read(key)
52
+ storage[key]
53
+ end
54
+
55
+ def o.write(key, value)
56
+ storage[key] = value
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,7 @@
1
+ module Quovo
2
+ QuovoError = Class.new(StandardError)
3
+ ParamsError = Class.new(QuovoError)
4
+ HttpError = Class.new(QuovoError)
5
+ ForbiddenError = Class.new(HttpError)
6
+ NotFoundError = Class.new(HttpError)
7
+ end
@@ -0,0 +1,29 @@
1
+ module Quovo
2
+ module Fake
3
+ def fake?
4
+ @fake
5
+ end
6
+
7
+ # format of fake calls
8
+ # [
9
+ # [:get, "/accounts/id", {}, { id: 123, nickname: '123' ... }]
10
+ # ]
11
+ def fake!(fake_calls = [])
12
+ @fake_calls = fake_calls
13
+ @fake = true
14
+ Quovo.config.token_storage = Object.new.tap do |o|
15
+ def o.read(_)
16
+ ['FAKE-TOKEN', (Time.now.utc + 1_000).iso8601].join('|')
17
+ end
18
+ end
19
+ end
20
+
21
+ def real!
22
+ @fake = false
23
+ end
24
+
25
+ def fake_calls
26
+ @fake_calls
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module Quovo
2
+ module Hook
3
+ def hook(&callback)
4
+ hooks << callback
5
+ end
6
+
7
+ def hooks
8
+ @hooks ||= []
9
+ end
10
+
11
+ def clear_hooks!
12
+ @hooks = []
13
+ end
14
+
15
+ def run_hooks!(*args)
16
+ log_params = (args << Quovo.current_scope)
17
+ hooks.each do |hook|
18
+ hook.call(*log_params)
19
+ end
20
+ :ok
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ module Quovo
2
+ module Models
3
+ class Account < Base
4
+ using Quovo::Refinements::ToTime
5
+
6
+ fields %i(
7
+ id
8
+ nickname
9
+ is_inactive
10
+ brokerage
11
+ brokerage_name
12
+ user
13
+ username
14
+ status
15
+ value
16
+ config_instructions
17
+ failures
18
+ update_count
19
+ opened
20
+ updated
21
+ )
22
+
23
+ undef :opened
24
+ def opened
25
+ @opened.to_time
26
+ end
27
+
28
+ undef :updated
29
+ def updated
30
+ @updated.to_time
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ module Quovo
2
+ module Models
3
+ class Base
4
+ extend ::Forwardable
5
+ def_delegators :to_h, :fetch, :to_json
6
+ def self.fields(fields = nil)
7
+ if fields
8
+ @fields = fields.map(&:to_sym)
9
+ @fields.each do |field|
10
+ attr_reader field
11
+ end
12
+ else
13
+ @fields || []
14
+ end
15
+ end
16
+
17
+ def initialize(props)
18
+ props.each do |field, value|
19
+ instance_variable_set("@#{field}", value)
20
+ end
21
+ end
22
+
23
+ def [](field)
24
+ send(field)
25
+ end
26
+
27
+ def to_hash
28
+ self.class.fields.map do |field|
29
+ [field, self[field]]
30
+ end.to_h
31
+ end
32
+
33
+ def to_h
34
+ to_hash
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ module Quovo
2
+ module Models
3
+ class Brokerage < Base
4
+ fields %i(
5
+ id
6
+ is_test
7
+ name
8
+ notes
9
+ password
10
+ username
11
+ website
12
+ )
13
+ end
14
+ end
15
+ end