openstax_accounts 2.0.0 → 3.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 +8 -8
- data/README.md +1 -0
- data/Rakefile +6 -6
- data/app/models/openstax/accounts/account.rb +34 -24
- data/app/models/openstax/accounts/application_group.rb +7 -0
- data/app/models/openstax/accounts/group.rb +132 -0
- data/app/models/openstax/accounts/group_member.rb +40 -0
- data/app/models/openstax/accounts/group_nesting.rb +62 -0
- data/app/models/openstax/accounts/group_owner.rb +40 -0
- data/app/representers/openstax/accounts/api/v1/application_group_representer.rb +25 -0
- data/app/representers/openstax/accounts/api/v1/application_groups_representer.rb +16 -0
- data/app/representers/openstax/accounts/api/v1/group_nesting_representer.rb +18 -0
- data/app/representers/openstax/accounts/api/v1/group_representer.rb +50 -0
- data/app/representers/openstax/accounts/api/v1/group_user_representer.rb +21 -0
- data/app/routines/openstax/accounts/search_accounts.rb +7 -14
- data/app/routines/openstax/accounts/sync_accounts.rb +32 -18
- data/app/routines/openstax/accounts/sync_groups.rb +61 -0
- data/app/routines/openstax/accounts/update_group_caches.rb +27 -0
- data/app/views/openstax/accounts/shared/accounts/_index.html.erb +0 -3
- data/config/initializers/action_interceptor.rb +1 -1
- data/db/migrate/20140811182433_create_openstax_accounts_groups.rb +16 -0
- data/db/migrate/20140811182505_create_openstax_accounts_group_members.rb +13 -0
- data/db/migrate/20140811182527_create_openstax_accounts_group_owners.rb +13 -0
- data/db/migrate/20140811182553_create_openstax_accounts_group_nestings.rb +13 -0
- data/lib/generators/openstax/accounts/schedule/templates/schedule.rb +1 -0
- data/lib/openstax/accounts/current_user_manager.rb +2 -2
- data/lib/openstax/accounts/has_many_through_groups.rb +45 -0
- data/lib/openstax/accounts/version.rb +1 -1
- data/lib/openstax_accounts.rb +165 -11
- data/spec/controllers/openstax/accounts/dev/accounts_controller_spec.rb +1 -1
- data/spec/controllers/openstax/accounts/sessions_controller_spec.rb +1 -1
- data/spec/dummy/app/controllers/api/application_groups_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/dummy_controller.rb +2 -1
- data/spec/dummy/app/controllers/api/group_members_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/group_nestings_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/group_owners_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/groups_controller.rb +15 -0
- data/spec/dummy/app/controllers/api/users_controller.rb +4 -0
- data/spec/dummy/app/models/ownership.rb +7 -0
- data/spec/dummy/app/models/user.rb +11 -8
- data/spec/dummy/config/application.rb +0 -33
- data/spec/dummy/config/boot.rb +4 -9
- data/spec/dummy/config/database.yml +8 -8
- data/spec/dummy/config/environment.rb +3 -3
- data/spec/dummy/config/environments/development.rb +20 -12
- data/spec/dummy/config/environments/production.rb +42 -29
- data/spec/dummy/config/environments/test.rb +16 -12
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +6 -5
- data/spec/dummy/config/initializers/mime_types.rb +0 -1
- data/spec/dummy/config/initializers/session_store.rb +1 -6
- data/spec/dummy/config/initializers/wrap_parameters.rb +6 -6
- data/spec/dummy/config/routes.rb +23 -0
- data/spec/dummy/config/secrets.yml +8 -0
- data/spec/dummy/db/migrate/1_create_users.rb +2 -2
- data/spec/dummy/db/migrate/2_create_ownerships.rb +11 -0
- data/spec/dummy/db/schema.rb +72 -20
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +186 -0
- data/spec/dummy/log/test.log +2078 -0
- data/spec/factories/openstax_accounts_account.rb +3 -2
- data/spec/factories/openstax_accounts_group.rb +7 -0
- data/spec/factories/openstax_accounts_group_member.rb +6 -0
- data/spec/factories/openstax_accounts_group_nesting.rb +6 -0
- data/spec/factories/openstax_accounts_group_owner.rb +6 -0
- data/spec/lib/openstax/accounts/current_user_manager_spec.rb +9 -3
- data/spec/lib/openstax/accounts/has_many_through_groups_spec.rb +53 -0
- data/spec/lib/openstax_accounts_spec.rb +189 -25
- data/spec/models/openstax/accounts/account_spec.rb +16 -1
- data/spec/models/openstax/accounts/anonymous_account_spec.rb +1 -1
- data/spec/models/openstax/accounts/group_spec.rb +20 -0
- data/spec/routines/openstax/accounts/sync_accounts_spec.rb +70 -0
- data/spec/routines/openstax/accounts/sync_groups_spec.rb +125 -0
- metadata +73 -56
- data/spec/dummy/config/initializers/secret_token.rb +0 -7
@@ -0,0 +1,18 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class GroupNestingRepresenter < Roar::Decorator
|
6
|
+
include Roar::Representer::JSON
|
7
|
+
|
8
|
+
property :container_group_id,
|
9
|
+
type: Integer
|
10
|
+
|
11
|
+
property :member_group_id,
|
12
|
+
type: Integer
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class GroupRepresenter < Roar::Decorator
|
6
|
+
include Roar::Representer::JSON
|
7
|
+
|
8
|
+
property :openstax_uid,
|
9
|
+
as: :id,
|
10
|
+
type: Integer
|
11
|
+
|
12
|
+
property :name,
|
13
|
+
type: String
|
14
|
+
|
15
|
+
property :is_public
|
16
|
+
|
17
|
+
collection :group_owners,
|
18
|
+
as: :owners,
|
19
|
+
class: GroupOwner,
|
20
|
+
decorator: GroupUserRepresenter
|
21
|
+
|
22
|
+
collection :group_members,
|
23
|
+
as: :members,
|
24
|
+
class: GroupMember,
|
25
|
+
decorator: GroupUserRepresenter
|
26
|
+
|
27
|
+
collection :member_group_nestings,
|
28
|
+
as: :nestings,
|
29
|
+
class: GroupNesting,
|
30
|
+
decorator: GroupNestingRepresenter
|
31
|
+
|
32
|
+
property :cached_supertree_group_ids,
|
33
|
+
as: :supertree_group_ids,
|
34
|
+
type: Array,
|
35
|
+
schema_info: {
|
36
|
+
items: "integer"
|
37
|
+
}
|
38
|
+
|
39
|
+
property :cached_subtree_group_ids,
|
40
|
+
as: :subtree_group_ids,
|
41
|
+
type: Array,
|
42
|
+
schema_info: {
|
43
|
+
items: "integer"
|
44
|
+
}
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class GroupUserRepresenter < Roar::Decorator
|
6
|
+
include Roar::Representer::JSON
|
7
|
+
|
8
|
+
property :group_id,
|
9
|
+
type: Integer
|
10
|
+
|
11
|
+
nested :user do
|
12
|
+
property :user_id,
|
13
|
+
as: :id,
|
14
|
+
type: Integer
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -65,7 +65,7 @@ module OpenStax
|
|
65
65
|
else
|
66
66
|
|
67
67
|
# Local search
|
68
|
-
accounts = OpenStax::Accounts::Account.
|
68
|
+
accounts = OpenStax::Accounts::Account.all
|
69
69
|
|
70
70
|
KeywordSearch.search(query) do |with|
|
71
71
|
|
@@ -73,7 +73,7 @@ module OpenStax
|
|
73
73
|
|
74
74
|
with.keyword :username do |usernames|
|
75
75
|
accounts = accounts.where{username
|
76
|
-
.like_any my{
|
76
|
+
.like_any my{prep_names(usernames)}}
|
77
77
|
end
|
78
78
|
|
79
79
|
with.keyword :first_name do |first_names|
|
@@ -103,7 +103,7 @@ module OpenStax
|
|
103
103
|
end
|
104
104
|
|
105
105
|
with.keyword :email do |emails|
|
106
|
-
accounts = OpenStax::Accounts::Account.
|
106
|
+
accounts = OpenStax::Accounts::Account.none
|
107
107
|
end
|
108
108
|
|
109
109
|
# Rerun the queries above for 'any' terms (which are ones without a
|
@@ -113,7 +113,7 @@ module OpenStax
|
|
113
113
|
names = prep_names(terms)
|
114
114
|
|
115
115
|
accounts = accounts.where{
|
116
|
-
(
|
116
|
+
(lower(username).like_any names) |
|
117
117
|
(lower(first_name).like_any names) |
|
118
118
|
(lower(last_name).like_any names) |
|
119
119
|
(lower(full_name).like_any names) |
|
@@ -175,21 +175,14 @@ module OpenStax
|
|
175
175
|
# Return no results if query exceeds maximum allowed number of matches
|
176
176
|
max_accounts = options[:max_matching_accounts] || \
|
177
177
|
OpenStax::Accounts.configuration.max_matching_accounts
|
178
|
-
outputs[:accounts] = OpenStax::Accounts::Account.
|
178
|
+
outputs[:accounts] = OpenStax::Accounts::Account.none \
|
179
179
|
if outputs[:num_matching_accounts] > max_accounts
|
180
180
|
|
181
181
|
end
|
182
182
|
|
183
|
-
# Downcase, and put a wildcard at the end.
|
184
|
-
# For the moment don't exclude characters.
|
183
|
+
# Downcase, remove all wildcards and put a wildcard at the end.
|
185
184
|
def prep_names(names)
|
186
|
-
names.collect{|name| name.downcase
|
187
|
-
end
|
188
|
-
|
189
|
-
def prep_usernames(usernames)
|
190
|
-
usernames.collect{|username| username.gsub(
|
191
|
-
OpenStax::Accounts::Account::USERNAME_DISCARDED_CHAR_REGEX, '')
|
192
|
-
.downcase + '%'}
|
185
|
+
names.collect{|name| "#{name.downcase.gsub('%', '')}%"}
|
193
186
|
end
|
194
187
|
|
195
188
|
end
|
@@ -16,28 +16,42 @@ module OpenStax
|
|
16
16
|
|
17
17
|
def exec(options={})
|
18
18
|
|
19
|
-
|
19
|
+
begin
|
20
|
+
OpenStax::Accounts.syncing = true
|
20
21
|
|
21
|
-
|
22
|
+
return if OpenStax::Accounts.configuration.enable_stubbing?
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
response = OpenStax::Accounts.get_application_account_updates
|
25
|
+
|
26
|
+
app_accounts = []
|
27
|
+
app_accounts_rep = OpenStax::Accounts::Api::V1::ApplicationAccountsRepresenter
|
25
28
|
.new(app_accounts)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
next unless account.update_attributes(
|
36
|
-
app_account.account.attributes.slice(*SYNC_ATTRIBUTES))
|
37
|
-
app_accounts_hash[app_account.id] = app_account.unread_updates
|
38
|
-
end
|
29
|
+
app_accounts_rep.from_json(response.body)
|
30
|
+
|
31
|
+
return if app_accounts.empty?
|
32
|
+
|
33
|
+
updated_app_accounts = []
|
34
|
+
app_accounts.each do |app_account|
|
35
|
+
account = OpenStax::Accounts::Account.where(
|
36
|
+
:openstax_uid => app_account.account.openstax_uid).first ||\
|
37
|
+
app_account.account
|
39
38
|
|
40
|
-
|
39
|
+
if account != app_account.account
|
40
|
+
SYNC_ATTRIBUTES.each do |attribute|
|
41
|
+
account.send("#{attribute}=", app_account.account.send(attribute))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
next unless account.save
|
46
|
+
|
47
|
+
updated_app_accounts << {user_id: account.openstax_uid,
|
48
|
+
read_updates: app_account.unread_updates}
|
49
|
+
end
|
50
|
+
|
51
|
+
OpenStax::Accounts.mark_account_updates_as_read(updated_app_accounts)
|
52
|
+
ensure
|
53
|
+
OpenStax::Accounts.syncing = false
|
54
|
+
end
|
41
55
|
|
42
56
|
end
|
43
57
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# Routine for getting group updates from the Accounts server
|
2
|
+
#
|
3
|
+
# Should be scheduled to run regularly
|
4
|
+
|
5
|
+
module OpenStax
|
6
|
+
module Accounts
|
7
|
+
|
8
|
+
class SyncGroups
|
9
|
+
|
10
|
+
SYNC_ATTRIBUTES = ['name', 'is_public', 'group_members',
|
11
|
+
'group_owners', 'member_group_nestings',
|
12
|
+
'cached_supertree_group_ids', 'cached_subtree_group_ids']
|
13
|
+
|
14
|
+
lev_routine transaction: :no_transaction
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def exec(options={})
|
19
|
+
|
20
|
+
begin
|
21
|
+
OpenStax::Accounts.syncing = true
|
22
|
+
|
23
|
+
return if OpenStax::Accounts.configuration.enable_stubbing?
|
24
|
+
|
25
|
+
response = OpenStax::Accounts.get_application_group_updates
|
26
|
+
|
27
|
+
app_groups = []
|
28
|
+
app_groups_rep = OpenStax::Accounts::Api::V1::ApplicationGroupsRepresenter
|
29
|
+
.new(app_groups)
|
30
|
+
app_groups_rep.from_json(response.body)
|
31
|
+
|
32
|
+
return if app_groups.empty?
|
33
|
+
|
34
|
+
updated_app_groups = []
|
35
|
+
app_groups.each do |app_group|
|
36
|
+
group = OpenStax::Accounts::Group.where(
|
37
|
+
:openstax_uid => app_group.group.openstax_uid).first || app_group.group
|
38
|
+
|
39
|
+
if group != app_group.group
|
40
|
+
SYNC_ATTRIBUTES.each do |attribute|
|
41
|
+
group.send("#{attribute}=", app_group.group.send(attribute))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
next unless group.save
|
46
|
+
|
47
|
+
updated_app_groups << {group_id: group.openstax_uid,
|
48
|
+
read_updates: app_group.unread_updates}
|
49
|
+
end
|
50
|
+
|
51
|
+
OpenStax::Accounts.mark_group_updates_as_read(updated_app_groups)
|
52
|
+
ensure
|
53
|
+
OpenStax::Accounts.syncing = false
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Routine for updating group caches when a group_nesting is created or destroyed
|
2
|
+
#
|
3
|
+
# Caller provides the group_nesting object
|
4
|
+
|
5
|
+
module OpenStax
|
6
|
+
module Accounts
|
7
|
+
|
8
|
+
class UpdateGroupCaches
|
9
|
+
|
10
|
+
# This transaction needs :repeatable_read to prevent missed updates
|
11
|
+
lev_routine transaction: :repeatable_read
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def exec(group_nesting)
|
16
|
+
subtree_group_ids = group_nesting.member_group.subtree_group_ids
|
17
|
+
supertree_group_ids = group_nesting.container_group.supertree_group_ids
|
18
|
+
tree_group_ids = (subtree_group_ids + supertree_group_ids).uniq
|
19
|
+
|
20
|
+
Group.where(id: subtree_group_ids).update_all(cached_supertree_group_ids: nil)
|
21
|
+
Group.where(id: supertree_group_ids).update_all(cached_subtree_group_ids: nil)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
<%
|
2
2
|
# Clients of this partial can override the following variables:
|
3
3
|
search_action_path ||= nil
|
4
|
-
results_list_id ||= 'search-results-list'
|
5
4
|
method ||= :post
|
6
5
|
remote ||= false
|
7
6
|
form_html ||= {id: 'search-form',
|
@@ -23,5 +22,3 @@
|
|
23
22
|
<%= f.submit 'Search', class: 'btn btn-primary' %>
|
24
23
|
|
25
24
|
<% end %>
|
26
|
-
|
27
|
-
<div id=<%= results_list_id %>></div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateOpenStaxAccountsGroups < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :openstax_accounts_groups do |t|
|
4
|
+
t.integer :openstax_uid, :null => false
|
5
|
+
t.boolean :is_public, null: false, default: false
|
6
|
+
t.string :name
|
7
|
+
t.text :cached_subtree_group_ids
|
8
|
+
t.text :cached_supertree_group_ids
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :openstax_accounts_groups, :openstax_uid, :unique => true
|
14
|
+
add_index :openstax_accounts_groups, :is_public
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateOpenStaxAccountsGroupMembers < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :openstax_accounts_group_members do |t|
|
4
|
+
t.references :group, null: false
|
5
|
+
t.references :user, null: false
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :openstax_accounts_group_members, [:group_id, :user_id], unique: true
|
11
|
+
add_index :openstax_accounts_group_members, :user_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateOpenStaxAccountsGroupOwners < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :openstax_accounts_group_owners do |t|
|
4
|
+
t.references :group, null: false
|
5
|
+
t.references :user, null: false
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :openstax_accounts_group_owners, [:group_id, :user_id], unique: true
|
11
|
+
add_index :openstax_accounts_group_owners, :user_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateOpenStaxAccountsGroupNestings < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :openstax_accounts_group_nestings do |t|
|
4
|
+
t.references :member_group, null: false
|
5
|
+
t.references :container_group, null: false
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :openstax_accounts_group_nestings, :member_group_id, unique: true
|
11
|
+
add_index :openstax_accounts_group_nestings, :container_group_id
|
12
|
+
end
|
13
|
+
end
|
@@ -50,7 +50,7 @@ module OpenStax
|
|
50
50
|
@cookies.delete(:secure_account_id)
|
51
51
|
else
|
52
52
|
@session[:account_id] = account.id
|
53
|
-
@cookies.
|
53
|
+
@cookies.encrypted[:secure_account_id] = { secure: true,
|
54
54
|
httponly: true, value: "secure#{account.id}" }
|
55
55
|
end
|
56
56
|
end
|
@@ -64,7 +64,7 @@ module OpenStax
|
|
64
64
|
# and the signed secure ID doesn't match the unsecure ID
|
65
65
|
# http://railscasts.com/episodes/356-dangers-of-session-hijacking
|
66
66
|
if @request.ssl? && \
|
67
|
-
@cookies.
|
67
|
+
@cookies.encrypted[:secure_account_id] != "secure#{@session[:account_id]}"
|
68
68
|
sign_out!
|
69
69
|
return
|
70
70
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module HasManyThroughGroups
|
4
|
+
module ActiveRecord
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def has_many_through_groups(groups_name, name, options = {})
|
11
|
+
options = {class_name: name.to_s.classify}.merge(options)
|
12
|
+
association_name = "direct_#{name.to_s}".to_sym
|
13
|
+
|
14
|
+
OpenStax::Accounts::Group.class_exec do
|
15
|
+
has_many association_name, options
|
16
|
+
|
17
|
+
define_method(name) do
|
18
|
+
OpenStax::Accounts::Group.includes(association_name)
|
19
|
+
.where(id: supertree_group_ids)
|
20
|
+
.collect{|g| g.send(association_name).to_a}.flatten.uniq
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class_exec do
|
25
|
+
has_many association_name, options if options[:as]
|
26
|
+
|
27
|
+
define_method(name) do
|
28
|
+
direct_records = respond_to?(association_name) ? \
|
29
|
+
send(association_name).to_a : []
|
30
|
+
indirect_records = OpenStax::Accounts::Group
|
31
|
+
.includes(association_name).where(
|
32
|
+
id: send(groups_name).collect{|g| g.supertree_group_ids}.flatten.uniq
|
33
|
+
)
|
34
|
+
.collect{|g| g.send(association_name).to_a}
|
35
|
+
(direct_records + indirect_records).flatten.uniq
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
ActiveRecord::Base.send :include, OpenStax::Accounts::HasManyThroughGroups::ActiveRecord
|