openstax_accounts 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +1 -0
  3. data/Rakefile +6 -6
  4. data/app/models/openstax/accounts/account.rb +34 -24
  5. data/app/models/openstax/accounts/application_group.rb +7 -0
  6. data/app/models/openstax/accounts/group.rb +132 -0
  7. data/app/models/openstax/accounts/group_member.rb +40 -0
  8. data/app/models/openstax/accounts/group_nesting.rb +62 -0
  9. data/app/models/openstax/accounts/group_owner.rb +40 -0
  10. data/app/representers/openstax/accounts/api/v1/application_group_representer.rb +25 -0
  11. data/app/representers/openstax/accounts/api/v1/application_groups_representer.rb +16 -0
  12. data/app/representers/openstax/accounts/api/v1/group_nesting_representer.rb +18 -0
  13. data/app/representers/openstax/accounts/api/v1/group_representer.rb +50 -0
  14. data/app/representers/openstax/accounts/api/v1/group_user_representer.rb +21 -0
  15. data/app/routines/openstax/accounts/search_accounts.rb +7 -14
  16. data/app/routines/openstax/accounts/sync_accounts.rb +32 -18
  17. data/app/routines/openstax/accounts/sync_groups.rb +61 -0
  18. data/app/routines/openstax/accounts/update_group_caches.rb +27 -0
  19. data/app/views/openstax/accounts/shared/accounts/_index.html.erb +0 -3
  20. data/config/initializers/action_interceptor.rb +1 -1
  21. data/db/migrate/20140811182433_create_openstax_accounts_groups.rb +16 -0
  22. data/db/migrate/20140811182505_create_openstax_accounts_group_members.rb +13 -0
  23. data/db/migrate/20140811182527_create_openstax_accounts_group_owners.rb +13 -0
  24. data/db/migrate/20140811182553_create_openstax_accounts_group_nestings.rb +13 -0
  25. data/lib/generators/openstax/accounts/schedule/templates/schedule.rb +1 -0
  26. data/lib/openstax/accounts/current_user_manager.rb +2 -2
  27. data/lib/openstax/accounts/has_many_through_groups.rb +45 -0
  28. data/lib/openstax/accounts/version.rb +1 -1
  29. data/lib/openstax_accounts.rb +165 -11
  30. data/spec/controllers/openstax/accounts/dev/accounts_controller_spec.rb +1 -1
  31. data/spec/controllers/openstax/accounts/sessions_controller_spec.rb +1 -1
  32. data/spec/dummy/app/controllers/api/application_groups_controller.rb +11 -0
  33. data/spec/dummy/app/controllers/api/dummy_controller.rb +2 -1
  34. data/spec/dummy/app/controllers/api/group_members_controller.rb +11 -0
  35. data/spec/dummy/app/controllers/api/group_nestings_controller.rb +11 -0
  36. data/spec/dummy/app/controllers/api/group_owners_controller.rb +11 -0
  37. data/spec/dummy/app/controllers/api/groups_controller.rb +15 -0
  38. data/spec/dummy/app/controllers/api/users_controller.rb +4 -0
  39. data/spec/dummy/app/models/ownership.rb +7 -0
  40. data/spec/dummy/app/models/user.rb +11 -8
  41. data/spec/dummy/config/application.rb +0 -33
  42. data/spec/dummy/config/boot.rb +4 -9
  43. data/spec/dummy/config/database.yml +8 -8
  44. data/spec/dummy/config/environment.rb +3 -3
  45. data/spec/dummy/config/environments/development.rb +20 -12
  46. data/spec/dummy/config/environments/production.rb +42 -29
  47. data/spec/dummy/config/environments/test.rb +16 -12
  48. data/spec/dummy/config/initializers/assets.rb +8 -0
  49. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  50. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  51. data/spec/dummy/config/initializers/inflections.rb +6 -5
  52. data/spec/dummy/config/initializers/mime_types.rb +0 -1
  53. data/spec/dummy/config/initializers/session_store.rb +1 -6
  54. data/spec/dummy/config/initializers/wrap_parameters.rb +6 -6
  55. data/spec/dummy/config/routes.rb +23 -0
  56. data/spec/dummy/config/secrets.yml +8 -0
  57. data/spec/dummy/db/migrate/1_create_users.rb +2 -2
  58. data/spec/dummy/db/migrate/2_create_ownerships.rb +11 -0
  59. data/spec/dummy/db/schema.rb +72 -20
  60. data/spec/dummy/db/test.sqlite3 +0 -0
  61. data/spec/dummy/log/development.log +186 -0
  62. data/spec/dummy/log/test.log +2078 -0
  63. data/spec/factories/openstax_accounts_account.rb +3 -2
  64. data/spec/factories/openstax_accounts_group.rb +7 -0
  65. data/spec/factories/openstax_accounts_group_member.rb +6 -0
  66. data/spec/factories/openstax_accounts_group_nesting.rb +6 -0
  67. data/spec/factories/openstax_accounts_group_owner.rb +6 -0
  68. data/spec/lib/openstax/accounts/current_user_manager_spec.rb +9 -3
  69. data/spec/lib/openstax/accounts/has_many_through_groups_spec.rb +53 -0
  70. data/spec/lib/openstax_accounts_spec.rb +189 -25
  71. data/spec/models/openstax/accounts/account_spec.rb +16 -1
  72. data/spec/models/openstax/accounts/anonymous_account_spec.rb +1 -1
  73. data/spec/models/openstax/accounts/group_spec.rb +20 -0
  74. data/spec/routines/openstax/accounts/sync_accounts_spec.rb +70 -0
  75. data/spec/routines/openstax/accounts/sync_groups_spec.rb +125 -0
  76. metadata +73 -56
  77. data/spec/dummy/config/initializers/secret_token.rb +0 -7
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Accounts
3
- VERSION = "2.0.0"
3
+ VERSION = "3.0.0"
4
4
  end
5
5
  end
@@ -2,6 +2,7 @@ require 'openstax/accounts/version'
2
2
  require 'openstax/accounts/engine'
3
3
  require 'openstax/accounts/default_account_user_mapper'
4
4
  require 'openstax/accounts/current_user_manager'
5
+ require 'openstax/accounts/has_many_through_groups'
5
6
  require 'openstax_utilities'
6
7
 
7
8
  require 'oauth2'
@@ -14,6 +15,8 @@ module OpenStax
14
15
 
15
16
  class << self
16
17
 
18
+ mattr_accessor :syncing
19
+
17
20
  ###########################################################################
18
21
  #
19
22
  # Configuration machinery.
@@ -143,6 +146,20 @@ module OpenStax
143
146
  api_call(:get, 'users', options)
144
147
  end
145
148
 
149
+ # Updates a user account in the Accounts server.
150
+ # The account is determined by the OAuth access token.
151
+ # Also takes an optional API version parameter.
152
+ # API version currently defaults to :v1 (may change in the future).
153
+ # On failure, throws an Exception, just like api_call.
154
+ # On success, returns an OAuth2::Response object.
155
+ def update_account(account, version = DEFAULT_API_VERSION)
156
+ options = {:access_token => account.access_token,
157
+ :api_version => version,
158
+ :body => account.attributes.slice('username', 'first_name',
159
+ 'last_name', 'full_name', 'title').to_json}
160
+ api_call(:put, 'user', options)
161
+ end
162
+
146
163
  # Performs an account search in the Accounts server.
147
164
  # Results are limited to accounts that have used the current app.
148
165
  # Takes a query parameter and an optional API version parameter.
@@ -166,29 +183,166 @@ module OpenStax
166
183
  end
167
184
 
168
185
  # Marks account updates as "read".
169
- # The uid_map parameter is a hash that maps account openstax_uid's
170
- # to the value of the last received unread_updates for that uid.
171
- # Can only be called for accounts that have used the current app.
186
+ # The application_users parameter is an array of hashes.
187
+ # Each hash has 2 required fields: 'id', which should contain the
188
+ # application_user's id, and 'read_updates', which should contain
189
+ # the last received value of unread_updates for that application_user.
190
+ # Can only be called for application_users that belong to the current app.
172
191
  # On failure, throws an Exception, just like api_call.
173
192
  # On success, returns an OAuth2::Response object.
174
- def mark_updates_as_read(uid_map, version = DEFAULT_API_VERSION)
193
+ def mark_account_updates_as_read(application_users, version = DEFAULT_API_VERSION)
175
194
  options = {:api_version => version,
176
- :body => {:application_users => uid_map}}
195
+ :body => application_users.to_json}
177
196
  api_call(:put, 'application_users/updated', options)
178
197
  end
179
198
 
180
- # Updates the current account in the Accounts server.
181
- # The current account is determined by the OAuth access token.
199
+ # Retrieves information about groups that have been
200
+ # recently updated.
201
+ # Results are limited to groups that users of the current app have access to.
202
+ # On failure, throws an Exception, just like api_call.
203
+ # On success, returns an OAuth2::Response object.
204
+ def get_application_group_updates(version = DEFAULT_API_VERSION)
205
+ options = {:api_version => version}
206
+ api_call(:get, 'application_groups/updates', options)
207
+ end
208
+
209
+ # Marks group updates as "read".
210
+ # The application_groups parameter is an array of hashes.
211
+ # Each hash has 2 required fields: 'id', which should contain the
212
+ # application_group's id, and 'read_updates', which should contain
213
+ # the last received value of unread_updates for that application_group.
214
+ # Can only be called for application_groups that belong to the current app.
215
+ # On failure, throws an Exception, just like api_call.
216
+ # On success, returns an OAuth2::Response object.
217
+ def mark_group_updates_as_read(application_groups, version = DEFAULT_API_VERSION)
218
+ options = {:api_version => version,
219
+ :body => application_groups.to_json}
220
+ api_call(:put, 'application_groups/updated', options)
221
+ end
222
+
223
+ # Creates a group in the Accounts server.
224
+ # The given account will be the owner of the group.
182
225
  # Also takes an optional API version parameter.
183
226
  # API version currently defaults to :v1 (may change in the future).
184
227
  # On failure, throws an Exception, just like api_call.
185
228
  # On success, returns an OAuth2::Response object.
186
- def update_account(account, version = DEFAULT_API_VERSION)
229
+ def create_group(account, group, version = DEFAULT_API_VERSION)
187
230
  options = {:access_token => account.access_token,
188
231
  :api_version => version,
189
- :body => account.attributes.slice('username', 'first_name',
190
- 'last_name', 'full_name', 'title').to_json}
191
- api_call(:put, 'user', options)
232
+ :body => group.attributes.slice('name', 'is_public').to_json}
233
+ response = ActiveSupport::JSON.decode(api_call(
234
+ :post, 'groups', options).body)
235
+ group.openstax_uid = response['id']
236
+ response
237
+ end
238
+
239
+ # Updates a group in the Accounts server.
240
+ # The given account must own the group.
241
+ # Also takes an optional API version parameter.
242
+ # API version currently defaults to :v1 (may change in the future).
243
+ # On failure, throws an Exception, just like api_call.
244
+ # On success, returns an OAuth2::Response object.
245
+ def update_group(account, group, version = DEFAULT_API_VERSION)
246
+ options = {:access_token => account.access_token,
247
+ :api_version => version,
248
+ :body => group.attributes.slice('name', 'is_public').to_json}
249
+ api_call(:put, "groups/#{group.openstax_uid}", options)
250
+ end
251
+
252
+ # Deletes a group from the Accounts server.
253
+ # The given account must own the group.
254
+ # Also takes an optional API version parameter.
255
+ # API version currently defaults to :v1 (may change in the future).
256
+ # On failure, throws an Exception, just like api_call.
257
+ # On success, returns an OAuth2::Response object.
258
+ def destroy_group(account, group, version = DEFAULT_API_VERSION)
259
+ options = {:access_token => account.access_token,
260
+ :api_version => version}
261
+ api_call(:delete, "groups/#{group.openstax_uid}", options)
262
+ end
263
+
264
+ # Creates a group_member in the Accounts server.
265
+ # The given account must own the group.
266
+ # Also takes an optional API version parameter.
267
+ # API version currently defaults to :v1 (may change in the future).
268
+ # On failure, throws an Exception, just like api_call.
269
+ # On success, returns an OAuth2::Response object.
270
+ def create_group_member(account, group_member, version = DEFAULT_API_VERSION)
271
+ options = {:access_token => account.access_token,
272
+ :api_version => version}
273
+ api_call(:post,
274
+ "groups/#{group_member.group_id}/members/#{group_member.user_id}",
275
+ options)
276
+ end
277
+
278
+ # Deletes a group_member from the Accounts server.
279
+ # The given account must own the group.
280
+ # Also takes an optional API version parameter.
281
+ # API version currently defaults to :v1 (may change in the future).
282
+ # On failure, throws an Exception, just like api_call.
283
+ # On success, returns an OAuth2::Response object.
284
+ def destroy_group_member(account, group_member, version = DEFAULT_API_VERSION)
285
+ options = {:access_token => account.access_token,
286
+ :api_version => version}
287
+ api_call(:delete,
288
+ "groups/#{group_member.group_id}/members/#{group_member.user_id}",
289
+ options)
290
+ end
291
+
292
+ # Creates a group_owner in the Accounts server.
293
+ # The given account must own the group.
294
+ # Also takes an optional API version parameter.
295
+ # API version currently defaults to :v1 (may change in the future).
296
+ # On failure, throws an Exception, just like api_call.
297
+ # On success, returns an OAuth2::Response object.
298
+ def create_group_owner(account, group_owner, version = DEFAULT_API_VERSION)
299
+ options = {:access_token => account.access_token,
300
+ :api_version => version}
301
+ api_call(:post,
302
+ "groups/#{group_owner.group_id}/owners/#{group_owner.user_id}",
303
+ options)
304
+ end
305
+
306
+ # Deletes a group_owner from the Accounts server.
307
+ # The given account must own the group.
308
+ # Also takes an optional API version parameter.
309
+ # API version currently defaults to :v1 (may change in the future).
310
+ # On failure, throws an Exception, just like api_call.
311
+ # On success, returns an OAuth2::Response object.
312
+ def destroy_group_owner(account, group_owner, version = DEFAULT_API_VERSION)
313
+ options = {:access_token => account.access_token,
314
+ :api_version => version}
315
+ api_call(:delete,
316
+ "groups/#{group_owner.group_id}/owners/#{group_owner.user_id}",
317
+ options)
318
+ end
319
+
320
+ # Creates a group_nesting in the Accounts server.
321
+ # The given account must own both groups.
322
+ # Also takes an optional API version parameter.
323
+ # API version currently defaults to :v1 (may change in the future).
324
+ # On failure, throws an Exception, just like api_call.
325
+ # On success, returns an OAuth2::Response object.
326
+ def create_group_nesting(account, group_nesting, version = DEFAULT_API_VERSION)
327
+ options = {:access_token => account.access_token,
328
+ :api_version => version}
329
+ api_call(:post,
330
+ "groups/#{group_nesting.container_group_id}/nestings/#{group_nesting.member_group_id}",
331
+ options)
332
+ end
333
+
334
+ # Deletes a group_nesting from the Accounts server.
335
+ # The given account must own either group.
336
+ # Also takes an optional API version parameter.
337
+ # API version currently defaults to :v1 (may change in the future).
338
+ # On failure, throws an Exception, just like api_call.
339
+ # On success, returns an OAuth2::Response object.
340
+ def destroy_group_nesting(account, group_nesting, version = DEFAULT_API_VERSION)
341
+ options = {:access_token => account.access_token,
342
+ :api_version => version}
343
+ api_call(:delete,
344
+ "groups/#{group_nesting.container_group_id}/nestings/#{group_nesting.member_group_id}",
345
+ options)
192
346
  end
193
347
 
194
348
  protected
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module OpenStax::Accounts
4
4
  module Dev
5
- describe AccountsController do
5
+ describe AccountsController, type: :controller do
6
6
  routes { Engine.routes }
7
7
 
8
8
  let!(:account) { FactoryGirl.create :openstax_accounts_account,
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module OpenStax::Accounts
4
- describe SessionsController do
4
+ describe SessionsController, type: :controller do
5
5
  routes { Engine.routes }
6
6
 
7
7
  let!(:account) { FactoryGirl.create :openstax_accounts_account,
@@ -0,0 +1,11 @@
1
+ module Api
2
+ class ApplicationGroupsController < DummyController
3
+ def updates
4
+ dummy(:updates)
5
+ end
6
+
7
+ def updated
8
+ dummy(:updated)
9
+ end
10
+ end
11
+ end
@@ -1,10 +1,11 @@
1
1
  module Api
2
2
  class DummyController < ApplicationController
3
- class << self; attr_accessor :last_action, :last_params end
3
+ class << self; attr_accessor :last_action, :last_params, :last_json end
4
4
 
5
5
  def dummy(action_name = :dummy)
6
6
  self.class.last_action = action_name
7
7
  self.class.last_params = params
8
+ self.class.last_json = ActiveSupport::JSON.decode(request.body.read) rescue nil
8
9
  render :json => { :head => :no_content }
9
10
  end
10
11
  end
@@ -0,0 +1,11 @@
1
+ module Api
2
+ class GroupMembersController < DummyController
3
+ def create
4
+ dummy(:create)
5
+ end
6
+
7
+ def destroy
8
+ dummy(:destroy)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Api
2
+ class GroupNestingsController < DummyController
3
+ def create
4
+ dummy(:create)
5
+ end
6
+
7
+ def destroy
8
+ dummy(:destroy)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Api
2
+ class GroupOwnersController < DummyController
3
+ def create
4
+ dummy(:create)
5
+ end
6
+
7
+ def destroy
8
+ dummy(:destroy)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Api
2
+ class GroupsController < DummyController
3
+ def create
4
+ dummy(:create)
5
+ end
6
+
7
+ def update
8
+ dummy(:update)
9
+ end
10
+
11
+ def destroy
12
+ dummy(:destroy)
13
+ end
14
+ end
15
+ end
@@ -3,5 +3,9 @@ module Api
3
3
  def index
4
4
  dummy(:index)
5
5
  end
6
+
7
+ def update
8
+ dummy(:update)
9
+ end
6
10
  end
7
11
  end
@@ -0,0 +1,7 @@
1
+ class Ownership < ActiveRecord::Base
2
+
3
+ belongs_to :owner, polymorphic: true
4
+
5
+ validates :owner, presence: true
6
+
7
+ end
@@ -1,10 +1,13 @@
1
1
  class User < ActiveRecord::Base
2
- belongs_to :openstax_accounts_account,
3
- class_name: "OpenStax::Accounts::Account",
4
- dependent: :destroy
2
+
3
+ belongs_to :account,
4
+ class_name: "OpenStax::Accounts::Account"
5
+ has_many :groups_as_member, through: :account
6
+ has_many_through_groups :groups_as_member, :ownerships,
7
+ as: :owner, dependent: :destroy
5
8
 
6
9
  delegate :username, :first_name, :last_name, :full_name, :title,
7
- :name, :casual_name, to: :openstax_accounts_account
10
+ :name, :casual_name, to: :account
8
11
 
9
12
  def is_anonymous?
10
13
  false
@@ -12,15 +15,15 @@ class User < ActiveRecord::Base
12
15
 
13
16
  # OpenStax Accounts "account_user_mapper" methods
14
17
 
15
- def self.account_to_user(account)
16
- account.is_anonymous? ? \
18
+ def self.account_to_user(acc)
19
+ acc.is_anonymous? ? \
17
20
  AnonymousUser.instance : \
18
- User.where(:openstax_accounts_account_id => account.id).first
21
+ User.where(:account_id => acc.id).first
19
22
  end
20
23
 
21
24
  def self.user_to_account(user)
22
25
  user.is_anonymous? ? \
23
26
  AnonymousAccount.instance : \
24
- user.openstax_accounts_account
27
+ user.account
25
28
  end
26
29
  end
@@ -11,16 +11,6 @@ module Dummy
11
11
  # Application configuration should go into files in config/initializers
12
12
  # -- all .rb files in that directory are automatically loaded.
13
13
 
14
- # Custom directories with classes and modules you want to be autoloadable.
15
- # config.autoload_paths += %W(#{config.root}/extras)
16
-
17
- # Only load the plugins named here, in the order given (default is alphabetical).
18
- # :all can be used as a placeholder for all plugins not explicitly named.
19
- # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
20
-
21
- # Activate observers that should always be running.
22
- # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
23
-
24
14
  # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
25
15
  # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
26
16
  # config.time_zone = 'Central Time (US & Canada)'
@@ -28,29 +18,6 @@ module Dummy
28
18
  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
29
19
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
30
20
  # config.i18n.default_locale = :de
31
-
32
- # Configure the default encoding used in templates for Ruby 1.9.
33
- config.encoding = "utf-8"
34
-
35
- # Configure sensitive parameters which will be filtered from the log file.
36
- config.filter_parameters += [:password]
37
-
38
- # Enable escaping HTML in JSON.
39
- config.active_support.escape_html_entities_in_json = true
40
-
41
- # Use SQL instead of Active Record's schema dumper when creating the database.
42
- # This is necessary if your schema can't be completely dumped by the schema dumper,
43
- # like if you have constraints or database-specific column types
44
- # config.active_record.schema_format = :sql
45
-
46
- # Enable the asset pipeline
47
- config.assets.enabled = true
48
-
49
- # Version of your assets, change this if you want to expire all your assets
50
- config.assets.version = '1.0'
51
-
52
- # Suppress warning
53
- config.i18n.enforce_available_locales = true
54
21
  end
55
22
  end
56
23
 
@@ -1,10 +1,5 @@
1
- require 'rubygems'
2
- gemfile = File.expand_path('../../../../Gemfile', __FILE__)
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
3
 
4
- if File.exist?(gemfile)
5
- ENV['BUNDLE_GEMFILE'] = gemfile
6
- require 'bundler'
7
- Bundler.setup
8
- end
9
-
10
- $:.unshift File.expand_path('../../../../lib', __FILE__)
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)