openstax_accounts 4.1.1 → 5.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.
- checksums.yaml +4 -4
- data/README.md +4 -1
- data/app/controllers/openstax/accounts/application_controller.rb +1 -1
- data/app/models/openstax/accounts/account.rb +11 -6
- data/app/models/openstax/accounts/anonymous_account.rb +1 -1
- data/app/models/openstax/accounts/application_account.rb +2 -1
- data/app/models/openstax/accounts/group.rb +14 -12
- data/app/models/openstax/accounts/group_member.rb +10 -10
- data/app/models/openstax/accounts/group_nesting.rb +7 -13
- data/app/models/openstax/accounts/group_owner.rb +10 -10
- data/app/representers/openstax/accounts/api/v1/account_representer.rb +4 -3
- data/app/representers/openstax/accounts/api/v1/application_account_representer.rb +7 -2
- data/app/representers/openstax/accounts/api/v1/application_accounts_representer.rb +0 -2
- data/app/representers/openstax/accounts/api/v1/application_group_representer.rb +7 -2
- data/app/representers/openstax/accounts/api/v1/application_groups_representer.rb +0 -2
- data/app/representers/openstax/accounts/api/v1/group_nesting_representer.rb +1 -1
- data/app/representers/openstax/accounts/api/v1/group_representer.rb +1 -1
- data/app/representers/openstax/accounts/api/v1/group_user_representer.rb +1 -1
- data/app/routines/openstax/accounts/search_accounts.rb +1 -1
- data/app/routines/openstax/accounts/sync_accounts.rb +24 -27
- data/app/routines/openstax/accounts/sync_groups.rb +22 -26
- data/lib/openstax/accounts/action_controller/base.rb +61 -0
- data/lib/openstax/accounts/api.rb +270 -0
- data/lib/openstax/accounts/configuration.rb +77 -0
- data/lib/openstax/accounts/engine.rb +13 -11
- data/lib/openstax/accounts/has_many_through_groups/active_record/base.rb +51 -0
- data/lib/openstax/accounts/version.rb +1 -1
- data/lib/openstax_accounts.rb +8 -331
- data/spec/dummy/app/controllers/api/users_controller.rb +4 -0
- data/spec/dummy/config/routes.rb +3 -1
- data/spec/dummy/log/test.log +152307 -0
- data/spec/lib/openstax/accounts/api_spec.rb +232 -0
- data/spec/lib/openstax/accounts/has_many_through_groups/active_record/base_spec.rb +57 -0
- data/spec/routines/openstax/accounts/sync_accounts_spec.rb +5 -9
- data/spec/routines/openstax/accounts/sync_groups_spec.rb +38 -39
- metadata +27 -16
- data/lib/openstax/accounts/extend_builtins.rb +0 -50
- data/lib/openstax/accounts/has_many_through_groups.rb +0 -47
- data/spec/lib/openstax/accounts/has_many_through_groups_spec.rb +0 -53
- data/spec/lib/openstax_accounts_spec.rb +0 -210
@@ -1,18 +1,20 @@
|
|
1
|
-
require 'omniauth'
|
2
|
-
require 'omniauth/strategies/openstax'
|
3
|
-
require 'lev'
|
4
|
-
require 'roar/decorator'
|
5
|
-
require 'roar/representer/json'
|
6
|
-
require 'keyword_search'
|
7
|
-
require 'squeel'
|
8
|
-
require 'action_interceptor'
|
9
|
-
require 'openstax/accounts/extend_builtins'
|
10
|
-
require 'doorkeeper'
|
11
|
-
|
12
1
|
ActiveSupport::Inflector.inflections do |inflect|
|
13
2
|
inflect.acronym 'OpenStax'
|
14
3
|
end
|
15
4
|
|
5
|
+
require 'action_interceptor'
|
6
|
+
require 'doorkeeper'
|
7
|
+
require 'keyword_search'
|
8
|
+
require 'lev'
|
9
|
+
require 'representable'
|
10
|
+
require 'representable/json/collection'
|
11
|
+
require 'roar'
|
12
|
+
require 'roar/decorator'
|
13
|
+
require 'roar/json'
|
14
|
+
require 'squeel'
|
15
|
+
require 'openstax/accounts/action_controller/base'
|
16
|
+
require 'openstax/accounts/has_many_through_groups/active_record/base'
|
17
|
+
|
16
18
|
module OpenStax
|
17
19
|
module Accounts
|
18
20
|
class Engine < ::Rails::Engine
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module HasManyThroughGroups
|
4
|
+
module ActiveRecord
|
5
|
+
module Base
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def has_many_through_groups(groups_name, name, options = {})
|
12
|
+
options = {class_name: name.to_s.classify}.merge(options)
|
13
|
+
association_name = "direct_#{name.to_s}".to_sym
|
14
|
+
|
15
|
+
OpenStax::Accounts::Group.class_exec do
|
16
|
+
has_many association_name, options
|
17
|
+
|
18
|
+
define_method(name) do
|
19
|
+
OpenStax::Accounts::Group.includes(association_name)
|
20
|
+
.where(openstax_uid: supertree_group_ids)
|
21
|
+
.collect{|g| g.send(association_name).to_a}.flatten.uniq
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class_exec do
|
26
|
+
has_many association_name, options if options[:as]
|
27
|
+
|
28
|
+
define_method(name) do
|
29
|
+
direct_records = respond_to?(association_name) ? \
|
30
|
+
send(association_name).to_a : []
|
31
|
+
indirect_records = OpenStax::Accounts::Group
|
32
|
+
.includes(association_name).where(
|
33
|
+
openstax_uid: send(groups_name).collect{|g|
|
34
|
+
g.supertree_group_ids
|
35
|
+
}.flatten.uniq
|
36
|
+
)
|
37
|
+
.collect{|g| g.send(association_name).to_a}
|
38
|
+
(direct_records + indirect_records).flatten.uniq
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
::ActiveRecord::Base.send(
|
50
|
+
:include, OpenStax::Accounts::HasManyThroughGroups::ActiveRecord::Base
|
51
|
+
)
|
data/lib/openstax_accounts.rb
CHANGED
@@ -1,22 +1,19 @@
|
|
1
|
-
require 'openstax/accounts/version'
|
2
|
-
require 'openstax/accounts/engine'
|
3
|
-
require 'openstax/accounts/default_account_user_mapper'
|
4
|
-
require 'openstax/accounts/current_user_manager'
|
5
|
-
require 'openstax/accounts/has_many_through_groups'
|
6
|
-
require 'openstax_utilities'
|
7
|
-
|
8
1
|
require 'oauth2'
|
2
|
+
require 'omniauth'
|
3
|
+
require 'openstax_utilities'
|
9
4
|
require 'uri'
|
5
|
+
require 'omniauth/strategies/openstax'
|
6
|
+
require 'openstax/accounts/api'
|
7
|
+
require 'openstax/accounts/configuration'
|
8
|
+
require 'openstax/accounts/current_user_manager'
|
9
|
+
require 'openstax/accounts/default_account_user_mapper'
|
10
|
+
require 'openstax/accounts/engine'
|
10
11
|
|
11
12
|
module OpenStax
|
12
13
|
module Accounts
|
13
14
|
|
14
|
-
DEFAULT_API_VERSION = :v1
|
15
|
-
|
16
15
|
class << self
|
17
16
|
|
18
|
-
mattr_accessor :syncing
|
19
|
-
|
20
17
|
###########################################################################
|
21
18
|
#
|
22
19
|
# Configuration machinery.
|
@@ -39,326 +36,6 @@ module OpenStax
|
|
39
36
|
@configuration ||= Configuration.new
|
40
37
|
end
|
41
38
|
|
42
|
-
class Configuration
|
43
|
-
# openstax_accounts_url
|
44
|
-
# Base URL for OpenStax Accounts
|
45
|
-
attr_reader :openstax_accounts_url
|
46
|
-
|
47
|
-
# openstax_application_id
|
48
|
-
# OAuth client_id received from OpenStax Accounts
|
49
|
-
attr_accessor :openstax_application_id
|
50
|
-
|
51
|
-
# openstax_application_secret
|
52
|
-
# OAuth client_secret received from OpenStax Accounts
|
53
|
-
attr_accessor :openstax_application_secret
|
54
|
-
|
55
|
-
# enable_stubbing
|
56
|
-
# Set to true if you want this engine to fake all
|
57
|
-
# interaction with the accounts site.
|
58
|
-
attr_accessor :enable_stubbing
|
59
|
-
|
60
|
-
# logout_via
|
61
|
-
# HTTP method to accept for logout requests
|
62
|
-
attr_accessor :logout_via
|
63
|
-
|
64
|
-
attr_accessor :default_errors_partial
|
65
|
-
attr_accessor :default_errors_html_id
|
66
|
-
attr_accessor :default_errors_added_trigger
|
67
|
-
|
68
|
-
# security_transgression_exception
|
69
|
-
# Class to be used for security transgression exceptions
|
70
|
-
attr_accessor :security_transgression_exception
|
71
|
-
|
72
|
-
# account_user_mapper
|
73
|
-
# This class teaches the gem how to convert between accounts and users
|
74
|
-
# See the "account_user_mapper" discussion in the README
|
75
|
-
attr_accessor :account_user_mapper
|
76
|
-
|
77
|
-
# min_search_characters
|
78
|
-
# The minimum number of characters that can be used
|
79
|
-
# as a query in a call to the AccountsSearch handler
|
80
|
-
# If less are used, the handler will return an error instead
|
81
|
-
attr_accessor :min_search_characters
|
82
|
-
|
83
|
-
# max_search_items
|
84
|
-
# The maximum number of accounts that can be returned
|
85
|
-
# in a call to the AccountsSearch handler
|
86
|
-
# If more would be returned, the result will be empty instead
|
87
|
-
attr_accessor :max_search_items
|
88
|
-
|
89
|
-
def openstax_accounts_url=(url)
|
90
|
-
url.gsub!(/https|http/,'https') if !(url =~ /localhost/)
|
91
|
-
url = url + "/" if url[url.size-1] != '/'
|
92
|
-
@openstax_accounts_url = url
|
93
|
-
end
|
94
|
-
|
95
|
-
def initialize
|
96
|
-
@openstax_application_id = 'SET ME!'
|
97
|
-
@openstax_application_secret = 'SET ME!'
|
98
|
-
@openstax_accounts_url = 'https://accounts.openstax.org/'
|
99
|
-
@enable_stubbing = true
|
100
|
-
@logout_via = :get
|
101
|
-
@default_errors_partial = 'openstax/accounts/shared/attention'
|
102
|
-
@default_errors_html_id = 'openstax-accounts-attention'
|
103
|
-
@default_errors_added_trigger = 'openstax-accounts-errors-added'
|
104
|
-
@security_transgression_exception = SecurityTransgression
|
105
|
-
@account_user_mapper = OpenStax::Accounts::DefaultAccountUserMapper
|
106
|
-
@min_search_characters = 3
|
107
|
-
@max_search_items = 10
|
108
|
-
super
|
109
|
-
end
|
110
|
-
|
111
|
-
def enable_stubbing?
|
112
|
-
!Rails.env.production? && enable_stubbing
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Executes an OpenStax Accounts API call, using the given HTTP method,
|
117
|
-
# API url and request options.
|
118
|
-
# Any options accepted by OAuth2 requests can be used, such as
|
119
|
-
# :params, :body, :headers, etc, plus the :access_token option, which can
|
120
|
-
# be used to manually specify an OAuth access token.
|
121
|
-
# On failure, it can throw Faraday::ConnectionFailed for connection errors
|
122
|
-
# or OAuth2::Error if Accounts returns an HTTP 400 error,
|
123
|
-
# such as 422 Unprocessable Entity.
|
124
|
-
# On success, returns an OAuth2::Response object.
|
125
|
-
def api_call(http_method, url, options = {})
|
126
|
-
version = options.delete(:api_version)
|
127
|
-
unless version.blank?
|
128
|
-
options[:headers] ||= {}
|
129
|
-
options[:headers].merge!({
|
130
|
-
'Accept' => "application/vnd.accounts.openstax.#{version.to_s}"
|
131
|
-
})
|
132
|
-
end
|
133
|
-
|
134
|
-
token_string = options.delete(:access_token)
|
135
|
-
token = token_string.blank? ? client.client_credentials.get_token :
|
136
|
-
OAuth2::AccessToken.new(client, token_string)
|
137
|
-
|
138
|
-
api_url = URI.join(configuration.openstax_accounts_url, 'api/', url)
|
139
|
-
|
140
|
-
token.request(http_method, api_url, options)
|
141
|
-
end
|
142
|
-
|
143
|
-
# Performs an account search in the Accounts server.
|
144
|
-
# Results are limited to 10 accounts maximum.
|
145
|
-
# Takes a query parameter and an optional API version parameter.
|
146
|
-
# API version currently defaults to :v1 (may change in the future).
|
147
|
-
# On failure, throws an Exception, just like api_call.
|
148
|
-
# On success, returns an OAuth2::Response object.
|
149
|
-
def search_accounts(query, version = DEFAULT_API_VERSION)
|
150
|
-
options = {:params => {:q => query},
|
151
|
-
:api_version => version}
|
152
|
-
api_call(:get, 'users', options)
|
153
|
-
end
|
154
|
-
|
155
|
-
# Updates a user account in the Accounts server.
|
156
|
-
# The account is determined by the OAuth access token.
|
157
|
-
# Also takes an optional API version parameter.
|
158
|
-
# API version currently defaults to :v1 (may change in the future).
|
159
|
-
# On failure, throws an Exception, just like api_call.
|
160
|
-
# On success, returns an OAuth2::Response object.
|
161
|
-
def update_account(account, version = DEFAULT_API_VERSION)
|
162
|
-
options = {:access_token => account.access_token,
|
163
|
-
:api_version => version,
|
164
|
-
:body => account.attributes.slice('username', 'first_name',
|
165
|
-
'last_name', 'full_name', 'title').to_json}
|
166
|
-
api_call(:put, 'user', options)
|
167
|
-
end
|
168
|
-
|
169
|
-
# Performs an account search in the Accounts server.
|
170
|
-
# Results are limited to accounts that have used the current app.
|
171
|
-
# Takes a query parameter and an optional API version parameter.
|
172
|
-
# API version currently defaults to :v1 (may change in the future).
|
173
|
-
# On failure, throws an Exception, just like api_call.
|
174
|
-
# On success, returns an OAuth2::Response object.
|
175
|
-
def search_application_accounts(query, version = DEFAULT_API_VERSION)
|
176
|
-
options = {:params => {:q => query},
|
177
|
-
:api_version => version}
|
178
|
-
api_call(:get, 'application_users', options)
|
179
|
-
end
|
180
|
-
|
181
|
-
# Retrieves information about accounts that have been
|
182
|
-
# recently updated.
|
183
|
-
# Results are limited to accounts that have used the current app.
|
184
|
-
# On failure, throws an Exception, just like api_call.
|
185
|
-
# On success, returns an OAuth2::Response object.
|
186
|
-
def get_application_account_updates(version = DEFAULT_API_VERSION)
|
187
|
-
options = {:api_version => version}
|
188
|
-
api_call(:get, 'application_users/updates', options)
|
189
|
-
end
|
190
|
-
|
191
|
-
# Marks account updates as "read".
|
192
|
-
# The application_users parameter is an array of hashes.
|
193
|
-
# Each hash has 2 required fields: 'id', which should contain the
|
194
|
-
# application_user's id, and 'read_updates', which should contain
|
195
|
-
# the last received value of unread_updates for that application_user.
|
196
|
-
# Can only be called for application_users that belong to the current app.
|
197
|
-
# On failure, throws an Exception, just like api_call.
|
198
|
-
# On success, returns an OAuth2::Response object.
|
199
|
-
def mark_account_updates_as_read(application_users, version = DEFAULT_API_VERSION)
|
200
|
-
options = {:api_version => version,
|
201
|
-
:body => application_users.to_json}
|
202
|
-
api_call(:put, 'application_users/updated', options)
|
203
|
-
end
|
204
|
-
|
205
|
-
# Retrieves information about groups that have been
|
206
|
-
# recently updated.
|
207
|
-
# Results are limited to groups that users of the current app have access to.
|
208
|
-
# On failure, throws an Exception, just like api_call.
|
209
|
-
# On success, returns an OAuth2::Response object.
|
210
|
-
def get_application_group_updates(version = DEFAULT_API_VERSION)
|
211
|
-
options = {:api_version => version}
|
212
|
-
api_call(:get, 'application_groups/updates', options)
|
213
|
-
end
|
214
|
-
|
215
|
-
# Marks group updates as "read".
|
216
|
-
# The application_groups parameter is an array of hashes.
|
217
|
-
# Each hash has 2 required fields: 'id', which should contain the
|
218
|
-
# application_group's id, and 'read_updates', which should contain
|
219
|
-
# the last received value of unread_updates for that application_group.
|
220
|
-
# Can only be called for application_groups that belong to the current app.
|
221
|
-
# On failure, throws an Exception, just like api_call.
|
222
|
-
# On success, returns an OAuth2::Response object.
|
223
|
-
def mark_group_updates_as_read(application_groups, version = DEFAULT_API_VERSION)
|
224
|
-
options = {:api_version => version,
|
225
|
-
:body => application_groups.to_json}
|
226
|
-
api_call(:put, 'application_groups/updated', options)
|
227
|
-
end
|
228
|
-
|
229
|
-
# Creates a group in the Accounts server.
|
230
|
-
# The given account will be the owner of the group.
|
231
|
-
# Also takes an optional API version parameter.
|
232
|
-
# API version currently defaults to :v1 (may change in the future).
|
233
|
-
# On failure, throws an Exception, just like api_call.
|
234
|
-
# On success, returns an OAuth2::Response object.
|
235
|
-
def create_group(account, group, version = DEFAULT_API_VERSION)
|
236
|
-
options = {:access_token => account.access_token,
|
237
|
-
:api_version => version,
|
238
|
-
:body => group.attributes.slice('name', 'is_public').to_json}
|
239
|
-
response = ActiveSupport::JSON.decode(api_call(
|
240
|
-
:post, 'groups', options).body)
|
241
|
-
group.openstax_uid = response['id']
|
242
|
-
response
|
243
|
-
end
|
244
|
-
|
245
|
-
# Updates a group in the Accounts server.
|
246
|
-
# The given account must own the group.
|
247
|
-
# Also takes an optional API version parameter.
|
248
|
-
# API version currently defaults to :v1 (may change in the future).
|
249
|
-
# On failure, throws an Exception, just like api_call.
|
250
|
-
# On success, returns an OAuth2::Response object.
|
251
|
-
def update_group(account, group, version = DEFAULT_API_VERSION)
|
252
|
-
options = {:access_token => account.access_token,
|
253
|
-
:api_version => version,
|
254
|
-
:body => group.attributes.slice('name', 'is_public').to_json}
|
255
|
-
api_call(:put, "groups/#{group.openstax_uid}", options)
|
256
|
-
end
|
257
|
-
|
258
|
-
# Deletes a group from the Accounts server.
|
259
|
-
# The given account must own the group.
|
260
|
-
# Also takes an optional API version parameter.
|
261
|
-
# API version currently defaults to :v1 (may change in the future).
|
262
|
-
# On failure, throws an Exception, just like api_call.
|
263
|
-
# On success, returns an OAuth2::Response object.
|
264
|
-
def destroy_group(account, group, version = DEFAULT_API_VERSION)
|
265
|
-
options = {:access_token => account.access_token,
|
266
|
-
:api_version => version}
|
267
|
-
api_call(:delete, "groups/#{group.openstax_uid}", options)
|
268
|
-
end
|
269
|
-
|
270
|
-
# Creates a group_member in the Accounts server.
|
271
|
-
# The given account must own the group.
|
272
|
-
# Also takes an optional API version parameter.
|
273
|
-
# API version currently defaults to :v1 (may change in the future).
|
274
|
-
# On failure, throws an Exception, just like api_call.
|
275
|
-
# On success, returns an OAuth2::Response object.
|
276
|
-
def create_group_member(account, group_member, version = DEFAULT_API_VERSION)
|
277
|
-
options = {:access_token => account.access_token,
|
278
|
-
:api_version => version}
|
279
|
-
api_call(:post,
|
280
|
-
"groups/#{group_member.group_id}/members/#{group_member.user_id}",
|
281
|
-
options)
|
282
|
-
end
|
283
|
-
|
284
|
-
# Deletes a group_member from the Accounts server.
|
285
|
-
# The given account must own the group.
|
286
|
-
# Also takes an optional API version parameter.
|
287
|
-
# API version currently defaults to :v1 (may change in the future).
|
288
|
-
# On failure, throws an Exception, just like api_call.
|
289
|
-
# On success, returns an OAuth2::Response object.
|
290
|
-
def destroy_group_member(account, group_member, version = DEFAULT_API_VERSION)
|
291
|
-
options = {:access_token => account.access_token,
|
292
|
-
:api_version => version}
|
293
|
-
api_call(:delete,
|
294
|
-
"groups/#{group_member.group_id}/members/#{group_member.user_id}",
|
295
|
-
options)
|
296
|
-
end
|
297
|
-
|
298
|
-
# Creates a group_owner in the Accounts server.
|
299
|
-
# The given account must own the group.
|
300
|
-
# Also takes an optional API version parameter.
|
301
|
-
# API version currently defaults to :v1 (may change in the future).
|
302
|
-
# On failure, throws an Exception, just like api_call.
|
303
|
-
# On success, returns an OAuth2::Response object.
|
304
|
-
def create_group_owner(account, group_owner, version = DEFAULT_API_VERSION)
|
305
|
-
options = {:access_token => account.access_token,
|
306
|
-
:api_version => version}
|
307
|
-
api_call(:post,
|
308
|
-
"groups/#{group_owner.group_id}/owners/#{group_owner.user_id}",
|
309
|
-
options)
|
310
|
-
end
|
311
|
-
|
312
|
-
# Deletes a group_owner from the Accounts server.
|
313
|
-
# The given account must own the group.
|
314
|
-
# Also takes an optional API version parameter.
|
315
|
-
# API version currently defaults to :v1 (may change in the future).
|
316
|
-
# On failure, throws an Exception, just like api_call.
|
317
|
-
# On success, returns an OAuth2::Response object.
|
318
|
-
def destroy_group_owner(account, group_owner, version = DEFAULT_API_VERSION)
|
319
|
-
options = {:access_token => account.access_token,
|
320
|
-
:api_version => version}
|
321
|
-
api_call(:delete,
|
322
|
-
"groups/#{group_owner.group_id}/owners/#{group_owner.user_id}",
|
323
|
-
options)
|
324
|
-
end
|
325
|
-
|
326
|
-
# Creates a group_nesting in the Accounts server.
|
327
|
-
# The given account must own both groups.
|
328
|
-
# Also takes an optional API version parameter.
|
329
|
-
# API version currently defaults to :v1 (may change in the future).
|
330
|
-
# On failure, throws an Exception, just like api_call.
|
331
|
-
# On success, returns an OAuth2::Response object.
|
332
|
-
def create_group_nesting(account, group_nesting, version = DEFAULT_API_VERSION)
|
333
|
-
options = {:access_token => account.access_token,
|
334
|
-
:api_version => version}
|
335
|
-
api_call(:post,
|
336
|
-
"groups/#{group_nesting.container_group_id}/nestings/#{group_nesting.member_group_id}",
|
337
|
-
options)
|
338
|
-
end
|
339
|
-
|
340
|
-
# Deletes a group_nesting from the Accounts server.
|
341
|
-
# The given account must own either group.
|
342
|
-
# Also takes an optional API version parameter.
|
343
|
-
# API version currently defaults to :v1 (may change in the future).
|
344
|
-
# On failure, throws an Exception, just like api_call.
|
345
|
-
# On success, returns an OAuth2::Response object.
|
346
|
-
def destroy_group_nesting(account, group_nesting, version = DEFAULT_API_VERSION)
|
347
|
-
options = {:access_token => account.access_token,
|
348
|
-
:api_version => version}
|
349
|
-
api_call(:delete,
|
350
|
-
"groups/#{group_nesting.container_group_id}/nestings/#{group_nesting.member_group_id}",
|
351
|
-
options)
|
352
|
-
end
|
353
|
-
|
354
|
-
protected
|
355
|
-
|
356
|
-
def client
|
357
|
-
@client ||= OAuth2::Client.new(configuration.openstax_application_id,
|
358
|
-
configuration.openstax_application_secret,
|
359
|
-
:site => configuration.openstax_accounts_url)
|
360
|
-
end
|
361
|
-
|
362
39
|
end
|
363
40
|
|
364
41
|
end
|