bridge_api 0.1.54 → 0.1.63

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -13
  3. data/README.md +17 -0
  4. data/bridge_api.gemspec +0 -1
  5. data/lib/bridge_api.rb +7 -5
  6. data/lib/bridge_api/api_array.rb +4 -2
  7. data/lib/bridge_api/client.rb +124 -56
  8. data/lib/bridge_api/client/account.rb +2 -1
  9. data/lib/bridge_api/client/affiliation.rb +13 -11
  10. data/lib/bridge_api/client/clone_object.rb +3 -3
  11. data/lib/bridge_api/client/course_template.rb +2 -0
  12. data/lib/bridge_api/client/custom_field.rb +2 -0
  13. data/lib/bridge_api/client/data_dump.rb +2 -0
  14. data/lib/bridge_api/client/enrollment.rb +2 -0
  15. data/lib/bridge_api/client/group.rb +2 -0
  16. data/lib/bridge_api/client/learner_item.rb +2 -0
  17. data/lib/bridge_api/client/live_course.rb +2 -0
  18. data/lib/bridge_api/client/live_course_enrollment.rb +2 -0
  19. data/lib/bridge_api/client/live_course_session.rb +3 -2
  20. data/lib/bridge_api/client/manager.rb +2 -0
  21. data/lib/bridge_api/client/program.rb +3 -1
  22. data/lib/bridge_api/client/program_enrollment.rb +6 -0
  23. data/lib/bridge_api/client/role.rb +2 -0
  24. data/lib/bridge_api/client/sub_account.rb +7 -1
  25. data/lib/bridge_api/client/user.rb +6 -5
  26. data/lib/bridge_api/version.rb +3 -1
  27. data/spec/bridge_api/client/account_spec.rb +6 -6
  28. data/spec/bridge_api/client/affiliations_spec.rb +3 -2
  29. data/spec/bridge_api/client/clone_object_spec.rb +8 -9
  30. data/spec/bridge_api/client/course_template_spec.rb +2 -0
  31. data/spec/bridge_api/client/custom_field_spec.rb +2 -0
  32. data/spec/bridge_api/client/data_dump_spec.rb +2 -0
  33. data/spec/bridge_api/client/enrollment_spec.rb +2 -0
  34. data/spec/bridge_api/client/group_spec.rb +2 -0
  35. data/spec/bridge_api/client/learner_items_spec.rb +2 -0
  36. data/spec/bridge_api/client/live_course_enrollments_spec.rb +2 -0
  37. data/spec/bridge_api/client/live_course_session_spec.rb +5 -3
  38. data/spec/bridge_api/client/live_course_spec.rb +2 -0
  39. data/spec/bridge_api/client/manager_spec.rb +2 -0
  40. data/spec/bridge_api/client/program_enrollment_spec.rb +7 -0
  41. data/spec/bridge_api/client/role_spec.rb +2 -0
  42. data/spec/bridge_api/client/sub_account_spec.rb +6 -4
  43. data/spec/bridge_api/client/user_spec.rb +2 -1
  44. data/spec/bridge_api/client_spec.rb +99 -5
  45. data/spec/support/fake_bridge.rb +8 -2
  46. data/spec/test_helper.rb +3 -1
  47. metadata +53 -68
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d39d608d1b30d380fb6fdb79ad8284d5c2e2e1fd132623b89717cf94a9f9071
4
- data.tar.gz: a8a72c682e3868563aa290f61b1dabb3295e34aff8ef6d9c61cff9f927a32bba
3
+ metadata.gz: f7d6ea6a260943cb99e83ffdd26cf7c0e68d0d383ca31e7cd96a16065261903a
4
+ data.tar.gz: a8e36b9a696de1d2245dcb8bea4844a21fac2b6da185032b07101d424e66143c
5
5
  SHA512:
6
- metadata.gz: 8b93008180e1bdb8af16f4fbc88f4fa642cbe20e655fcac04dc34ea0c5ba20b1f38ef3b5c32e098224f48da463a7e7288fc7726c57232fc6e5c666d741c505b4
7
- data.tar.gz: 10af8a2e42a4ca6db28abdeba4258bf6559a4b6f4ffc3907a0fe3d0f8820015a82b92a2001e08ae25cc3af2bd0653f4de58526f0301db6f0320db96d65a11d0a
6
+ metadata.gz: c9fb10e6dc27d66c2ba3273ebfd7b0770245590256d1782be1cf9398b3a61c4ef36e2af7677da48322cabc35d0ca932a2ab3828f650b523e0ba85f71e6b3db14
7
+ data.tar.gz: a828d6bef4d11150bd2b4968fdeb81908c06e44de3ab8fb044fff5bc09c61b586d15c466b12ca41496bb5e3d1d5990ab12464691d6b6876327b7094451fd58e8
@@ -1,17 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bridge_api (0.1.48)
4
+ bridge_api (0.1.60)
5
5
  faraday (~> 0.9.0)
6
6
  faraday_middleware (>= 0.12.2)
7
7
  footrest (>= 0.5.1)
8
- logging (>= 2.2.2)
9
8
  paul_walker (>= 0.1.1)
10
9
 
11
10
  GEM
12
11
  remote: https://rubygems.org/
13
12
  specs:
14
- activesupport (5.2.2)
13
+ activesupport (5.2.3)
15
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
15
  i18n (>= 0.7, < 2)
17
16
  minitest (~> 5.1)
@@ -20,29 +19,24 @@ GEM
20
19
  public_suffix (>= 2.0.2, < 4.0)
21
20
  byebug (8.2.5)
22
21
  coderay (1.1.2)
23
- concurrent-ruby (1.1.3)
22
+ concurrent-ruby (1.1.5)
24
23
  crack (0.4.3)
25
24
  safe_yaml (~> 1.0.0)
26
25
  diff-lcs (1.3)
27
26
  faraday (0.9.2)
28
27
  multipart-post (>= 1.2, < 3)
29
- faraday_middleware (0.12.2)
28
+ faraday_middleware (0.13.1)
30
29
  faraday (>= 0.7.4, < 1.0)
31
30
  footrest (0.5.3)
32
31
  activesupport (>= 3.0.0)
33
32
  faraday (>= 0.9.0, < 1)
34
33
  link_header (>= 0.0.7)
35
34
  hashdiff (0.3.7)
36
- i18n (1.1.1)
35
+ i18n (1.6.0)
37
36
  concurrent-ruby (~> 1.0)
38
37
  link_header (0.0.8)
39
- little-plugger (1.1.4)
40
- logging (2.2.2)
41
- little-plugger (~> 1.1)
42
- multi_json (~> 1.10)
43
38
  method_source (0.9.0)
44
39
  minitest (5.11.3)
45
- multi_json (1.13.1)
46
40
  multipart-post (2.0.0)
47
41
  paul_walker (0.1.1)
48
42
  redis (>= 4.0)
@@ -54,7 +48,7 @@ GEM
54
48
  rack-protection (1.5.5)
55
49
  rack
56
50
  rake (0.9.6)
57
- redis (4.0.3)
51
+ redis (4.1.0)
58
52
  rspec (2.99.0)
59
53
  rspec-core (~> 2.99.0)
60
54
  rspec-expectations (~> 2.99.0)
@@ -92,4 +86,4 @@ DEPENDENCIES
92
86
  webmock (~> 1.22.6)
93
87
 
94
88
  BUNDLED WITH
95
- 1.17.1
89
+ 1.17.2
data/README.md CHANGED
@@ -25,3 +25,20 @@ instantiating several instances of `client`, you can also supply your client
25
25
  initializer with `master_rate_limit: true`. This will use a redis
26
26
  keystore to track your rate limits across all instances of `client` and
27
27
  properly throttle your application as needed.
28
+
29
+ ## Token Pools
30
+
31
+ This supports token pooling to get around rate limiting issues in bridge (but should never be used without Core approval)
32
+ To use with Tokens:
33
+ ```
34
+ client = BridgeAPI::Client.new(tokens: ['token1', 'token2'], prefix: "https://yourdomain.bridgeapp.com")
35
+ ```
36
+ To use with API Keys:
37
+ ```
38
+ client = BridgeAPI::Client.new(api_keys: {'key1' => 'secret1', 'key2' => 'secret2'}, prefix: "https://yourdomain.bridgeapp.com")
39
+ ```
40
+
41
+ The logic will start with the first token provided, and check against the redis cache to see what its current limit
42
+ is. If its already under the limit threshold, it will rotate to the next in the pool, and perform the same check. It
43
+ will do this till it finds one that is not under the threshold, and use it. If none are found, it will sleep for the
44
+ configured time, and then try to make a call.
@@ -30,6 +30,5 @@ Gem::Specification.new do |gem|
30
30
  gem.add_dependency 'faraday', '~> 0.9.0'
31
31
  gem.add_dependency 'faraday_middleware', '>= 0.12.2'
32
32
  gem.add_dependency 'footrest', '>= 0.5.1'
33
- gem.add_dependency 'logging', '>= 2.2.2'
34
33
  gem.add_dependency 'paul_walker', '>= 0.1.1'
35
34
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bridge_api/version'
2
4
  require 'bridge_api/client'
3
5
 
4
6
  module BridgeAPI
5
7
  class << self
6
- require 'logging'
7
- attr_writer :enforce_rate_limits, :rate_limit_min, :rate_limits, :max_sleep_seconds, :min_sleep_seconds,
8
+ require 'logger'
9
+ attr_writer :enforce_rate_limits, :beginning_rate_limit, :rate_limits, :max_sleep_seconds, :min_sleep_seconds,
8
10
  :logger, :master_rate_limit, :master_mutex, :rate_limit_threshold
9
11
 
10
12
  def configure
@@ -15,8 +17,8 @@ module BridgeAPI
15
17
  @enforce_rate_limits ||= false
16
18
  end
17
19
 
18
- def rate_limit_min
19
- @rate_limit_min ||= 30
20
+ def beginning_rate_limit
21
+ @beginning_rate_limit ||= 30
20
22
  end
21
23
 
22
24
  def rate_limits
@@ -41,7 +43,7 @@ module BridgeAPI
41
43
 
42
44
  def logger
43
45
  return @logger if defined? @logger
44
- @logger = Logging.logger(STDOUT)
46
+ @logger = Logger.new(STDOUT)
45
47
  @logger.level = :debug
46
48
  @logger
47
49
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module BridgeAPI
3
4
  class ApiArray
@@ -18,7 +19,7 @@ module BridgeAPI
18
19
  @linked = {}
19
20
  @meta = {}
20
21
  @extra_meta_fields = []
21
- pattern = /.*(\/api\/.*)/
22
+ pattern = %r{.*(/api/.*)}
22
23
  path = response.env.url
23
24
  matches = pattern.match(path.to_s)
24
25
  mapping = nil
@@ -67,7 +68,6 @@ module BridgeAPI
67
68
  !@next_page.nil?
68
69
  end
69
70
 
70
-
71
71
  def next_page
72
72
  load_page(@next_page)
73
73
  end
@@ -119,8 +119,10 @@ module BridgeAPI
119
119
 
120
120
  def get_response_content(response)
121
121
  return [] unless response.body.is_a?(Hash)
122
+
122
123
  content = response.body.reject { |k, _v| @meta_fields.include?(k) || @extra_meta_fields.include?(k) }
123
124
  return content.values[0] unless content.empty?
125
+
124
126
  []
125
127
  end
126
128
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'footrest/client'
2
4
  require 'faraday'
3
5
  require 'footrest'
@@ -12,60 +14,126 @@ module BridgeAPI
12
14
  class Client < Footrest::Client
13
15
  require 'bridge_api/api_array'
14
16
 
15
- DATA_DUMP_DOWNLOAD_PATH = '/data_dumps/download'.freeze
16
- DATA_DUMP_PATH = '/data_dumps'.freeze
17
- COURSE_TEMPLATE_PATH = '/course_templates'.freeze
18
- ENROLLMENT_PATH = '/enrollments'.freeze
19
- LTI_TOOLS_PATH = '/lti_tools'.freeze
20
- PROGRAM_PATH = '/programs'.freeze
21
- PROGRAM_ENROLLMENT_PATH = '/learners'.freeze
22
- USER_PATH = '/users'.freeze
23
- GROUPS_PATH = '/groups'.freeze
24
- MANAGER_PATH = '/managers'.freeze
25
- ADMIN_PATH = '/admin'.freeze
26
- AUTHOR_PATH = '/author'.freeze
27
- LEARNER_PATH = '/learner'.freeze
28
- LEARNERS_PATH = '/learners'.freeze
29
- LEARNER_ITEMS_PATH = '/learner_items'.freeze
30
- CUSTOM_FIELD_PATH = '/custom_fields'.freeze
31
- SUB_ACCOUNT_PATH = '/sub_accounts'.freeze
32
- SUPPORT_PATH = '/support'.freeze
33
- ACCOUNT_PATH = '/accounts'.freeze
34
- CLONE_OBJECTS_PATH = '/clone_objects'.freeze
35
- API_VERSION = 1
36
- API_PATH = '/api'.freeze
37
- ROLE_PATH = '/roles'.freeze
38
- AFFILIATED_SUBACCOUNTS = '/affiliated_sub_accounts'.freeze
39
- BATCH_PATH = '/batch'.freeze
40
- LIVE_COURSES_PATH = '/live_courses'.freeze
41
- SESSIONS_PATH = '/sessions'.freeze
42
- PUBLISH_PATH = '/publish'.freeze
43
- WEB_CONFERENCE_PATH = '/web_conference'.freeze
44
- RESTORE_PATH = '/restore'.freeze
45
- DUE_DATE_PATH = '/due_date'.freeze
46
- RESET_PATH = '/reset'.freeze
47
- RESULT_MAPPING = {}
17
+ DATA_DUMP_DOWNLOAD_PATH = '/data_dumps/download'
18
+ DATA_DUMP_PATH = '/data_dumps'
19
+ COURSE_TEMPLATE_PATH = '/course_templates'
20
+ ENROLLMENT_PATH = '/enrollments'
21
+ LTI_TOOLS_PATH = '/lti_tools'
22
+ PROGRAM_PATH = '/programs'
23
+ PROGRAM_ENROLLMENT_PATH = '/learners'
24
+ USER_PATH = '/users'
25
+ GROUPS_PATH = '/groups'
26
+ MANAGER_PATH = '/managers'
27
+ ADMIN_PATH = '/admin'
28
+ AUTHOR_PATH = '/author'
29
+ LEARNER_PATH = '/learner'
30
+ LEARNERS_PATH = '/learners'
31
+ LEARNER_ITEMS_PATH = '/learner_items'
32
+ CUSTOM_FIELD_PATH = '/custom_fields'
33
+ SUB_ACCOUNT_PATH = '/sub_accounts'
34
+ SUPPORT_PATH = '/support'
35
+ ACCOUNT_PATH = '/accounts'
36
+ CLONE_OBJECTS_PATH = '/clone_objects'
37
+ API_VERSION = 1
38
+ API_PATH = '/api'
39
+ ROLE_PATH = '/roles'
40
+ AFFILIATED_SUBACCOUNTS = '/affiliated_sub_accounts'
41
+ BATCH_PATH = '/batch'
42
+ LIVE_COURSES_PATH = '/live_courses'
43
+ SESSIONS_PATH = '/sessions'
44
+ PUBLISH_PATH = '/publish'
45
+ WEB_CONFERENCE_PATH = '/web_conference'
46
+ RESTORE_PATH = '/restore'
47
+ DUE_DATE_PATH = '/due_date'
48
+ RESET_PATH = '/reset'
49
+ RESULT_MAPPING = {}
48
50
 
49
51
  Dir[File.dirname(__FILE__) + '/client/*.rb'].each do |file|
50
52
  require file
51
53
  include const_get(File.basename(file).gsub('.rb', '').split('_').map(&:capitalize).join('').to_s)
52
54
  end
53
55
 
56
+ def initialize(options = {}, &block)
57
+ if BridgeAPI.enforce_rate_limits && has_token_pool?(options)
58
+ options = initialize_from_token_pool(options)
59
+ end
60
+ super
61
+ end
62
+
54
63
  # Override Footrest request for ApiArray support
55
64
  def request(method, &block)
56
- enforce_rate_limits
65
+ if has_token_pool?(config)
66
+ (config[:api_tokens] || config[:api_keys].keys).size.times do
67
+ break unless rate_limit_reached?
68
+
69
+ rotate_token!
70
+ end
71
+ end
72
+ enforce_rate_limits if rate_limit_reached?
57
73
  response = connection.send(method, &block)
58
74
  apply_rate_limits(response)
59
75
  ApiArray.process_response(response, self, RESULT_MAPPING)
60
76
  end
61
77
 
78
+ def has_token_pool?(config)
79
+ config[:api_keys].is_a?(Hash) && config[:api_keys].keys.count >= 1 ||
80
+ config[:api_tokens].is_a?(Array) && config[:api_tokens].count >= 1
81
+ end
82
+
83
+ # Since a pool is passed in, initialize first token with the first token passed in
84
+ def initialize_from_token_pool(config)
85
+ if config[:api_keys].is_a?(Hash)
86
+ creds = config[:api_keys].first
87
+ config[:api_key] ||= creds[0]
88
+ config[:api_secret] ||= creds[1]
89
+ elsif config[:api_tokens].is_a?(Array)
90
+ config[:token] ||= config[:api_tokens].first
91
+ end
92
+ config
93
+ end
94
+
95
+ # rotates to the next token in the pool (by order in which they were provided)
96
+ def rotate_token!
97
+ BridgeAPI.master_mutex.synchronize do
98
+ old_api_key = config[:api_key]
99
+ if config[:api_keys].is_a?(Hash)
100
+ keys = config[:api_keys].keys
101
+ return if keys.count <= 1
102
+
103
+ key = get_next_key(keys, config[:api_key])
104
+ config[:api_key] = key
105
+ config[:api_secret] = config[:api_keys][key]
106
+ elsif config[:api_tokens].is_a?(Array)
107
+ keys = config[:api_tokens]
108
+ return if keys.count <= 1
109
+
110
+ token = get_next_key(keys, config[:token])
111
+ config[:token] = token
112
+ end
113
+ BridgeAPI.logger.debug('rotating API Keys')
114
+ set_connection(config)
115
+ end
116
+ end
117
+
118
+ def get_next_key(keys, current_key)
119
+ i = keys.index(current_key) || -1
120
+ i = (i + 2) > keys.count ? 0 : (i + 1)
121
+ keys[i]
122
+ end
123
+
124
+ def rate_limit_reached?
125
+ return false unless BridgeAPI.enforce_rate_limits && limit_remaining.present?
126
+
127
+ limit_remaining < BridgeAPI.rate_limit_threshold
128
+ end
129
+
62
130
  def enforce_rate_limits
63
- return unless BridgeAPI.enforce_rate_limits && limit_remaining.present?
64
- return unless limit_remaining < BridgeAPI.rate_limit_threshold
65
- tts = ((BridgeAPI.rate_limit_min - limit_remaining) / 5).ceil
66
- tts = BridgeAPI.min_sleep_seconds if tts < BridgeAPI.min_sleep_seconds
67
- tts = BridgeAPI.max_sleep_seconds if tts > BridgeAPI.max_sleep_seconds
68
- message = "Bridge API rate limit minimum #{BridgeAPI.rate_limit_min} reached for key: '#{config[:api_key]}'. "\
131
+ return unless rate_limit_reached?
132
+
133
+ tts = ((BridgeAPI.beginning_rate_limit - limit_remaining) / 5).ceil
134
+ tts = BridgeAPI.min_sleep_seconds if tts < BridgeAPI.min_sleep_seconds
135
+ tts = BridgeAPI.max_sleep_seconds if tts > BridgeAPI.max_sleep_seconds
136
+ message = "Bridge API rate limit minimum #{BridgeAPI.rate_limit_threshold} reached for key: '#{config[:api_key]}'. "\
69
137
  "Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\
70
138
  "Limit Remaining: #{limit_remaining}"
71
139
  BridgeAPI.logger.debug(message)
@@ -79,6 +147,7 @@ module BridgeAPI
79
147
  def apply_rate_limits(response)
80
148
  limit = response.headers['x-rate-limit-remaining']
81
149
  return if limit.nil?
150
+
82
151
  BridgeAPI.logger.debug("BRIDGE RATE LIMIT REMAINING: #{limit}")
83
152
  self.limit_remaining = limit.to_i
84
153
  end
@@ -88,8 +157,8 @@ module BridgeAPI
88
157
  BridgeAPI.master_mutex.synchronize do
89
158
  limit = PaulWalker::RateLimit.get(config[:api_key], config[:api_key])
90
159
  if limit.nil?
91
- PaulWalker::RateLimit.add(config[:api_key], config[:api_key], 0, BridgeAPI::rate_limit_min)
92
- limit = {current: 0}.with_indifferent_access
160
+ PaulWalker::RateLimit.add(config[:api_key], config[:api_key], 0, BridgeAPI.beginning_rate_limit)
161
+ limit = { current: 0 }.with_indifferent_access
93
162
  end
94
163
  limit['current']
95
164
  end
@@ -101,7 +170,7 @@ module BridgeAPI
101
170
  def limit_remaining=(value)
102
171
  if using_master_rate_limit?
103
172
  BridgeAPI.master_mutex.synchronize do
104
- PaulWalker::RateLimit.add(config[:api_key], config[:api_key], value, BridgeAPI::rate_limit_min)
173
+ PaulWalker::RateLimit.add(config[:api_key], config[:api_key], value, BridgeAPI.beginning_rate_limit)
105
174
  end
106
175
  else
107
176
  BridgeAPI.rate_limits[config[:api_key]] = value
@@ -110,26 +179,25 @@ module BridgeAPI
110
179
 
111
180
  def set_connection(config)
112
181
  config[:logger] = config[:logging] if config[:logging]
113
- @connection = Faraday.new(url: config[:prefix]) do |faraday|
114
- faraday.request :multipart
115
- faraday.request :url_encoded
182
+ @connection = Faraday.new(url: config[:prefix]) do |faraday|
183
+ faraday.request :multipart
184
+ faraday.request :url_encoded
116
185
  if config[:logger] == true
117
186
  faraday.response :logger
118
187
  elsif config[:logger]
119
188
  faraday.use Faraday::Response::Logger, config[:logger]
120
189
  end
121
- faraday.use Footrest::FollowRedirects, limit: 5 unless config[:follow_redirects] == false
122
- faraday.adapter Faraday.default_adapter
123
- faraday.use Footrest::ParseJson, content_type: /\bjson$/
124
- faraday.use Footrest::RaiseFootrestErrors
125
- faraday.use Footrest::Pagination
126
- faraday.headers[:accept] = 'application/json'
127
- faraday.headers[:authorization] = "Bearer #{config[:token]}" if config[:token]
128
- faraday.headers[:user_agent] = 'Footrest'
190
+ faraday.use Footrest::FollowRedirects, limit: 5 unless config[:follow_redirects] == false
191
+ faraday.adapter Faraday.default_adapter
192
+ faraday.use Footrest::ParseJson, content_type: /\bjson$/
193
+ faraday.use Footrest::RaiseFootrestErrors
194
+ faraday.use Footrest::Pagination
195
+ faraday.headers[:accept] = 'application/json'
196
+ faraday.headers[:user_agent] = 'Footrest'
129
197
  if config[:api_key] && config[:api_secret]
130
- faraday.headers[:authorization] = 'Basic ' + Base64.strict_encode64("#{config[:api_key]}:#{config[:api_secret]}")
198
+ faraday.headers[:authorization] = 'Basic ' + Base64.strict_encode64("#{config[:api_key]}:#{config[:api_secret]}")
131
199
  elsif config[:token]
132
- faraday.headers[:authorization] = "Bearer #{config[:token]}"
200
+ faraday.headers[:authorization] = "Bearer #{config[:token]}"
133
201
  else
134
202
  raise 'No api authorization provided'
135
203
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BridgeAPI
2
4
  class Client
3
5
  module Account
4
-
5
6
  def create_account(params = {})
6
7
  post("#{API_PATH}#{ADMIN_PATH}/sub_accounts", params)
7
8
  end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BridgeAPI
2
- class Client
3
- module Affiliation
4
- def list_affiliations(params = {})
5
- get("#{API_PATH}#{AUTHOR_PATH}#{AFFILIATED_SUBACCOUNTS}", params)
6
- end
4
+ class Client
5
+ module Affiliation
6
+ def list_affiliations(params = {})
7
+ get("#{API_PATH}#{AUTHOR_PATH}#{AFFILIATED_SUBACCOUNTS}", params)
8
+ end
7
9
 
8
- def revoke_affiliations_batch(params = {})
9
- put("#{API_PATH}#{AUTHOR_PATH}#{AFFILIATED_SUBACCOUNTS}/revoke_batch", params)
10
- end
10
+ def revoke_affiliations_batch(params = {})
11
+ put("#{API_PATH}#{AUTHOR_PATH}#{AFFILIATED_SUBACCOUNTS}/revoke_batch", params)
12
+ end
11
13
 
12
- def share_affiliations_batch(params = {})
13
- put("#{API_PATH}#{AUTHOR_PATH}#{AFFILIATED_SUBACCOUNTS}/share_batch", params)
14
- end
14
+ def share_affiliations_batch(params = {})
15
+ put("#{API_PATH}#{AUTHOR_PATH}#{AFFILIATED_SUBACCOUNTS}/share_batch", params)
15
16
  end
16
17
  end
17
18
  end
19
+ end