openstax_accounts 4.1.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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