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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -1
  3. data/app/controllers/openstax/accounts/application_controller.rb +1 -1
  4. data/app/models/openstax/accounts/account.rb +11 -6
  5. data/app/models/openstax/accounts/anonymous_account.rb +1 -1
  6. data/app/models/openstax/accounts/application_account.rb +2 -1
  7. data/app/models/openstax/accounts/group.rb +14 -12
  8. data/app/models/openstax/accounts/group_member.rb +10 -10
  9. data/app/models/openstax/accounts/group_nesting.rb +7 -13
  10. data/app/models/openstax/accounts/group_owner.rb +10 -10
  11. data/app/representers/openstax/accounts/api/v1/account_representer.rb +4 -3
  12. data/app/representers/openstax/accounts/api/v1/application_account_representer.rb +7 -2
  13. data/app/representers/openstax/accounts/api/v1/application_accounts_representer.rb +0 -2
  14. data/app/representers/openstax/accounts/api/v1/application_group_representer.rb +7 -2
  15. data/app/representers/openstax/accounts/api/v1/application_groups_representer.rb +0 -2
  16. data/app/representers/openstax/accounts/api/v1/group_nesting_representer.rb +1 -1
  17. data/app/representers/openstax/accounts/api/v1/group_representer.rb +1 -1
  18. data/app/representers/openstax/accounts/api/v1/group_user_representer.rb +1 -1
  19. data/app/routines/openstax/accounts/search_accounts.rb +1 -1
  20. data/app/routines/openstax/accounts/sync_accounts.rb +24 -27
  21. data/app/routines/openstax/accounts/sync_groups.rb +22 -26
  22. data/lib/openstax/accounts/action_controller/base.rb +61 -0
  23. data/lib/openstax/accounts/api.rb +270 -0
  24. data/lib/openstax/accounts/configuration.rb +77 -0
  25. data/lib/openstax/accounts/engine.rb +13 -11
  26. data/lib/openstax/accounts/has_many_through_groups/active_record/base.rb +51 -0
  27. data/lib/openstax/accounts/version.rb +1 -1
  28. data/lib/openstax_accounts.rb +8 -331
  29. data/spec/dummy/app/controllers/api/users_controller.rb +4 -0
  30. data/spec/dummy/config/routes.rb +3 -1
  31. data/spec/dummy/log/test.log +152307 -0
  32. data/spec/lib/openstax/accounts/api_spec.rb +232 -0
  33. data/spec/lib/openstax/accounts/has_many_through_groups/active_record/base_spec.rb +57 -0
  34. data/spec/routines/openstax/accounts/sync_accounts_spec.rb +5 -9
  35. data/spec/routines/openstax/accounts/sync_groups_spec.rb +38 -39
  36. metadata +27 -16
  37. data/lib/openstax/accounts/extend_builtins.rb +0 -50
  38. data/lib/openstax/accounts/has_many_through_groups.rb +0 -47
  39. data/spec/lib/openstax/accounts/has_many_through_groups_spec.rb +0 -53
  40. 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
+ )
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Accounts
3
- VERSION = "4.1.1"
3
+ VERSION = "5.0.0"
4
4
  end
5
5
  end
@@ -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
@@ -7,5 +7,9 @@ module Api
7
7
  def update
8
8
  dummy(:update)
9
9
  end
10
+
11
+ def create
12
+ dummy(:create)
13
+ end
10
14
  end
11
15
  end