openstax_accounts 3.1.1 → 4.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/app/assets/stylesheets/openstax/accounts/dev.css.scss +4 -0
- data/app/controllers/openstax/accounts/dev/accounts_controller.rb +2 -2
- data/app/handlers/openstax/accounts/accounts_search.rb +66 -0
- data/app/handlers/openstax/accounts/dev/accounts_search.rb +10 -21
- data/app/models/openstax/accounts/group.rb +12 -8
- data/app/representers/openstax/accounts/api/v1/account_representer.rb +5 -0
- data/app/representers/openstax/accounts/api/v1/account_search_representer.rb +12 -17
- data/app/representers/openstax/accounts/api/v1/application_account_search_representer.rb +3 -1
- data/app/routines/openstax/accounts/dev/create_account.rb +1 -1
- data/app/routines/openstax/accounts/search_accounts.rb +16 -171
- data/app/routines/openstax/accounts/search_local_accounts.rb +101 -0
- data/app/views/openstax/accounts/dev/accounts/_search_results.html.erb +19 -45
- data/app/views/openstax/accounts/dev/accounts/index.html.erb +11 -8
- data/app/views/openstax/accounts/shared/accounts/_search.html.erb +9 -6
- data/db/migrate/{20140811182433_create_openstax_accounts_groups.rb → 1_create_openstax_accounts_groups.rb} +0 -0
- data/db/migrate/{20140811182505_create_openstax_accounts_group_members.rb → 2_create_openstax_accounts_group_members.rb} +0 -0
- data/db/migrate/{20140811182527_create_openstax_accounts_group_owners.rb → 3_create_openstax_accounts_group_owners.rb} +0 -0
- data/db/migrate/{20140811182553_create_openstax_accounts_group_nestings.rb → 4_create_openstax_accounts_group_nestings.rb} +0 -0
- data/lib/openstax/accounts/engine.rb +1 -0
- data/lib/openstax/accounts/has_many_through_groups.rb +4 -2
- data/lib/openstax/accounts/version.rb +1 -1
- data/lib/openstax_accounts.rb +11 -5
- 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/access_policies/account_access_policy.rb +11 -0
- data/spec/dummy/app/controllers/oauth_controller.rb +2 -0
- data/spec/dummy/config/environments/production.rb +1 -1
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/dummy/config/initializers/access_policies.rb +1 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +75 -0
- data/spec/dummy/config/initializers/openstax_accounts.rb +2 -1
- data/spec/dummy/db/migrate/{1_create_users.rb → 5_create_users.rb} +0 -0
- data/spec/dummy/db/migrate/{2_create_ownerships.rb → 6_create_ownerships.rb} +0 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/factories/openstax_accounts_account.rb +1 -1
- data/spec/factories/openstax_accounts_group.rb +1 -1
- data/spec/handlers/openstax/accounts/accounts_search_spec.rb +63 -0
- data/spec/handlers/openstax/accounts/dev/accounts_search_spec.rb +55 -0
- data/spec/lib/openstax_accounts_spec.rb +66 -66
- data/spec/routines/openstax/accounts/search_accounts_spec.rb +23 -23
- metadata +60 -15
- data/app/routines/openstax/accounts/dev/search_accounts.rb +0 -27
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OWY3YWZhMGEwYzY0NjgyZGNlOTUyOGY0MmNmOWJhOWI3ODJlZDc5NQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzE3MmRlOTlkNTdiM2FkNmUyYzQzYTI2YzA2NDA3NWU4MDRiZGQ3Nw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NjYxMmNmZmViMjBlMTU3MjJlOGRlYzA1NGNkNThlMDM1ZmU3ZWVhY2VkMmYx
|
10
|
+
YzBmZGY3Yjg0ZGI5ODI0MmQ5MDg0ZDZlMmI0Njg1NjVjZTk4OGI1ZDk5M2M1
|
11
|
+
Y2Q3MzhhMTU2NGRkZjVmYTM2NTE4ZDM0YzNlNDdjZDBhYjg2ODk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZjM4YTlkMzhmM2IxNGY1NGQ3OTllZjdlMjMwYjE4NWI0ZTQ0NWU3NWUyYjlk
|
14
|
+
YjQ4N2MzMzdjNzQ3MzQ0N2I4Zjg1ZjAxMTI3Nzk1NTk0MjY3YThhOGQ2NDk0
|
15
|
+
NTYxMjY1YmQ1OWM2N2NjOWEyY2ExZDBlMTYyNDk0M2JjOGMxNGQ=
|
@@ -12,11 +12,11 @@ module OpenStax
|
|
12
12
|
|
13
13
|
def create
|
14
14
|
handle_with(AccountsCreate,
|
15
|
-
complete: lambda {
|
15
|
+
complete: lambda { redirect_to dev_accounts_path })
|
16
16
|
end
|
17
17
|
|
18
18
|
def become
|
19
|
-
@account = Account.
|
19
|
+
@account = Account.find_by(openstax_uid: params[:id])
|
20
20
|
sign_in(@account)
|
21
21
|
redirect_back
|
22
22
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
class AccountsSearch
|
4
|
+
|
5
|
+
lev_handler
|
6
|
+
|
7
|
+
paramify :search do
|
8
|
+
attribute :type, type: String
|
9
|
+
attribute :query, type: String
|
10
|
+
attribute :order_by, type: String
|
11
|
+
attribute :page, type: Integer
|
12
|
+
attribute :per_page, type: Integer
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@min_characters = \
|
19
|
+
OpenStax::Accounts.configuration.min_search_characters
|
20
|
+
@max_items = OpenStax::Accounts.configuration.max_search_items
|
21
|
+
end
|
22
|
+
|
23
|
+
def authorized?
|
24
|
+
OSU::AccessPolicy.action_allowed?(:search, caller, Account)
|
25
|
+
end
|
26
|
+
|
27
|
+
def handle
|
28
|
+
case search_params.type
|
29
|
+
when 'Username'
|
30
|
+
query = "username:\"#{search_params.query}\""
|
31
|
+
when 'Name'
|
32
|
+
query = "name:\"#{search_params.query}\""
|
33
|
+
when 'First Name'
|
34
|
+
query = "first_name:\"#{search_params.query}\""
|
35
|
+
when 'Last Name'
|
36
|
+
query = "last_name:\"#{search_params.query}\""
|
37
|
+
when 'Email'
|
38
|
+
query = "email:\"#{search_params.query}\""
|
39
|
+
else
|
40
|
+
query = search_params.query || ''
|
41
|
+
end
|
42
|
+
|
43
|
+
fatal_error(code: :query_too_short,
|
44
|
+
message: "The provided query is too short (minimum #{
|
45
|
+
@min_characters} characters).") \
|
46
|
+
if !@min_characters.nil? && query.length < @min_characters
|
47
|
+
|
48
|
+
params = {query: search_params.query,
|
49
|
+
order_by: search_params.order_by,
|
50
|
+
page: search_params.page,
|
51
|
+
per_page: search_params.per_page}
|
52
|
+
out = run(OpenStax::Accounts::SearchAccounts, params).outputs
|
53
|
+
outputs[:total_count] = out[:total_count]
|
54
|
+
|
55
|
+
if !@max_items.nil? && outputs[:total_count] > @max_items
|
56
|
+
fatal_error(code: :too_many_items,
|
57
|
+
message: "The number of matches exceeded the allowed limit of #{
|
58
|
+
@max_items} matches. Please refine your query and try again.")
|
59
|
+
end
|
60
|
+
|
61
|
+
outputs[:items] = out[:items].to_a
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,39 +1,28 @@
|
|
1
1
|
module OpenStax
|
2
2
|
module Accounts
|
3
3
|
module Dev
|
4
|
-
class AccountsSearch
|
5
|
-
|
6
|
-
lev_handler transaction: :no_transaction
|
4
|
+
class AccountsSearch < OpenStax::Accounts::AccountsSearch
|
7
5
|
|
8
6
|
paramify :search do
|
9
|
-
attribute :terms, type: String
|
10
7
|
attribute :type, type: String
|
8
|
+
attribute :query, type: String
|
9
|
+
attribute :order_by, type: String
|
11
10
|
attribute :page, type: Integer
|
11
|
+
attribute :per_page, type: Integer
|
12
12
|
end
|
13
13
|
|
14
|
-
uses_routine OpenStax::Accounts::Dev::SearchAccounts,
|
15
|
-
as: :search_accounts,
|
16
|
-
translations: { outputs: {type: :verbatim} }
|
17
|
-
|
18
14
|
protected
|
19
15
|
|
20
|
-
def
|
21
|
-
|
16
|
+
def initialize
|
17
|
+
@min_characters = nil
|
18
|
+
@max_items = nil
|
22
19
|
end
|
23
20
|
|
24
|
-
def
|
25
|
-
|
26
|
-
when 'Name'
|
27
|
-
query = "name:#{search_params.terms.gsub(/\s/,',')}"
|
28
|
-
when 'Username'
|
29
|
-
query = "username:#{search_params.terms.gsub(/\s/,',')}"
|
30
|
-
else
|
31
|
-
query = search_params.terms || ''
|
32
|
-
end
|
33
|
-
run(:search_accounts, query, page: search_params.page || 0)
|
21
|
+
def authorized?
|
22
|
+
!Rails.env.production?
|
34
23
|
end
|
35
24
|
|
36
25
|
end
|
37
26
|
end
|
38
27
|
end
|
39
|
-
end
|
28
|
+
end
|
@@ -84,10 +84,12 @@ module OpenStax::Accounts
|
|
84
84
|
return [] unless persisted?
|
85
85
|
reload
|
86
86
|
|
87
|
-
gids = [
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
gids = [openstax_uid] + (Group.includes(:member_group_nestings)
|
88
|
+
.where(member_group_nestings: {
|
89
|
+
member_group_id: openstax_uid
|
90
|
+
})
|
91
|
+
.first.try(:supertree_group_ids) || [])
|
92
|
+
update_column(:cached_supertree_group_ids, gids)
|
91
93
|
self.cached_supertree_group_ids = gids
|
92
94
|
end
|
93
95
|
|
@@ -96,10 +98,12 @@ module OpenStax::Accounts
|
|
96
98
|
return [] unless persisted?
|
97
99
|
reload
|
98
100
|
|
99
|
-
gids = [
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
gids = [openstax_uid] + Group.includes(:container_group_nesting)
|
102
|
+
.where(container_group_nesting: {
|
103
|
+
container_group_id: openstax_uid
|
104
|
+
})
|
105
|
+
.collect{|g| g.subtree_group_ids}.flatten
|
106
|
+
update_column(:cached_subtree_group_ids, gids)
|
103
107
|
self.cached_subtree_group_ids = gids
|
104
108
|
end
|
105
109
|
|
@@ -2,26 +2,21 @@ module OpenStax
|
|
2
2
|
module Accounts
|
3
3
|
module Api
|
4
4
|
module V1
|
5
|
-
class AccountSearchRepresenter <
|
6
|
-
include Roar::Representer::JSON
|
5
|
+
class AccountSearchRepresenter < OpenStax::Api::V1::AbstractSearchRepresenter
|
7
6
|
|
8
|
-
property :
|
9
|
-
|
10
|
-
|
7
|
+
property :total_count,
|
8
|
+
inherit: true,
|
9
|
+
schema_info: {
|
10
|
+
description: "The number of accounts matching the query; can be more than the number returned"
|
11
|
+
}
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
property :per_page,
|
16
|
-
type: Integer
|
17
|
-
|
18
|
-
property :order_by,
|
19
|
-
type: String
|
20
|
-
|
21
|
-
collection :accounts,
|
22
|
-
as: :users,
|
13
|
+
collection :items,
|
14
|
+
inherit: true,
|
23
15
|
class: Account,
|
24
|
-
decorator: AccountRepresenter
|
16
|
+
decorator: Api::V1::AccountRepresenter,
|
17
|
+
schema_info: {
|
18
|
+
description: "The accounts matching the query or a subset thereof when paginating"
|
19
|
+
}
|
25
20
|
|
26
21
|
end
|
27
22
|
end
|
@@ -8,8 +8,10 @@ module OpenStax
|
|
8
8
|
as: :application_users,
|
9
9
|
class: OpenStax::Accounts::ApplicationAccount,
|
10
10
|
decorator: ApplicationAccountRepresenter,
|
11
|
+
writeable: true,
|
12
|
+
readable: true,
|
11
13
|
schema_info: {
|
12
|
-
description: "The matching
|
14
|
+
description: "The accounts of matching users that have used this app",
|
13
15
|
minItems: 0
|
14
16
|
}
|
15
17
|
|
@@ -1,191 +1,36 @@
|
|
1
|
-
# Routine for searching for accounts
|
2
|
-
#
|
3
|
-
# Caller provides a query and some options. The query follows the rules of
|
4
|
-
# https://github.com/bruce/keyword_search , e.g.:
|
5
|
-
#
|
6
|
-
# "username:jps,richb" --> returns the "jps" and "richb" accounts
|
7
|
-
# "name:John" --> returns accounts with first, last, or full name
|
8
|
-
# starting with "John"
|
9
|
-
#
|
10
|
-
# Query terms can be combined, e.g. "username:jp first_name:john"
|
11
|
-
#
|
12
|
-
# There are currently two options to control query pagination:
|
13
|
-
#
|
14
|
-
# :per_page -- the max number of results to return per page (default: 20)
|
15
|
-
# :page -- the zero-indexed page to return (default: 0)
|
16
|
-
#
|
17
|
-
# There is also an option to control the ordering:
|
18
|
-
#
|
19
|
-
# :order_by -- comma-separated list of fields to sort by, with an optional
|
20
|
-
# space-separated sort direction (default: "username ASC")
|
21
|
-
#
|
22
|
-
# Finally, you can also specify a maximum allowed number of results:
|
23
|
-
#
|
24
|
-
# :max_matching_accounts -- the max number of results allowed (default: 10)
|
25
|
-
#
|
26
|
-
# This routine will return an empty relation if the number of results exceeds
|
27
|
-
# max_matching_accounts. You can tell that this situation happened when
|
28
|
-
# the result has an empty accounts array, but a non-zero num_matching_accounts.
|
29
|
-
|
30
1
|
module OpenStax
|
31
2
|
module Accounts
|
32
3
|
class SearchAccounts
|
33
4
|
|
34
5
|
lev_routine transaction: :no_transaction
|
6
|
+
|
7
|
+
uses_routine SearchLocalAccounts,
|
8
|
+
as: :local_search,
|
9
|
+
translations: { outputs: { type: :verbatim } }
|
35
10
|
|
36
11
|
protected
|
37
|
-
|
38
|
-
SORTABLE_FIELDS = ['username', 'first_name', 'last_name', 'id']
|
39
|
-
SORT_ASCENDING = 'ASC'
|
40
|
-
SORT_DESCENDING = 'DESC'
|
41
12
|
|
42
|
-
def exec(
|
13
|
+
def exec(*args)
|
14
|
+
params = args.last.is_a?(Hash) ? args.pop : {}
|
15
|
+
params[:q] ||= args[0]
|
16
|
+
params[:ob] ||= args[1]
|
17
|
+
params[:pp] ||= args[2]
|
18
|
+
params[:p] ||= args[3]
|
43
19
|
|
44
|
-
|
45
|
-
|
20
|
+
query = params[:query] || params[:q]
|
21
|
+
if !OpenStax::Accounts.configuration.enable_stubbing? && \
|
22
|
+
query =~ /email:/
|
46
23
|
# Delegate to Accounts
|
47
|
-
|
48
24
|
response = OpenStax::Accounts.search_application_accounts(query)
|
49
|
-
|
50
|
-
|
51
|
-
search = OpenStruct.new
|
52
|
-
search_rep = OpenStax::Accounts::Api::V1::AccountSearchRepresenter.new(search)
|
53
|
-
search_rep.from_json(response.body)
|
54
|
-
|
55
|
-
# Need to query local database in order to obtain ID's (primary keys)
|
56
|
-
outputs[:accounts] = OpenStax::Accounts::Account.where {
|
57
|
-
openstax_uid.in search.accounts.collect{ |u| u.openstax_uid }
|
58
|
-
}
|
59
|
-
outputs[:query] = search.q
|
60
|
-
outputs[:per_page] = search.per_page
|
61
|
-
outputs[:page] = search.page
|
62
|
-
outputs[:order_by] = search.order_by
|
63
|
-
outputs[:num_matching_accounts] = search.num_matching_accounts
|
64
|
-
|
25
|
+
OpenStax::Accounts::Api::V1::AccountSearchRepresenter \
|
26
|
+
.new(outputs).from_json(response.body)
|
65
27
|
else
|
66
|
-
|
67
28
|
# Local search
|
68
|
-
|
69
|
-
|
70
|
-
KeywordSearch.search(query) do |with|
|
71
|
-
|
72
|
-
with.default_keyword :any
|
73
|
-
|
74
|
-
with.keyword :username do |usernames|
|
75
|
-
accounts = accounts.where{username
|
76
|
-
.like_any my{prep_names(usernames)}}
|
77
|
-
end
|
78
|
-
|
79
|
-
with.keyword :first_name do |first_names|
|
80
|
-
accounts = accounts.where{lower(first_name)
|
81
|
-
.like_any my{prep_names(first_names)}}
|
82
|
-
end
|
83
|
-
|
84
|
-
with.keyword :last_name do |last_names|
|
85
|
-
accounts = accounts.where{lower(last_name)
|
86
|
-
.like_any my{prep_names(last_names)}}
|
87
|
-
end
|
88
|
-
|
89
|
-
with.keyword :full_name do |full_names|
|
90
|
-
accounts = accounts.where{lower(full_name)
|
91
|
-
.like_any my{prep_names(full_names)}}
|
92
|
-
end
|
93
|
-
|
94
|
-
with.keyword :name do |names|
|
95
|
-
names = prep_names(names)
|
96
|
-
accounts = accounts.where{ (lower(full_name).like_any names) |
|
97
|
-
(lower(last_name).like_any names) |
|
98
|
-
(lower(first_name).like_any names) }
|
99
|
-
end
|
100
|
-
|
101
|
-
with.keyword :id do |ids|
|
102
|
-
accounts = accounts.where{openstax_uid.in ids}
|
103
|
-
end
|
104
|
-
|
105
|
-
with.keyword :email do |emails|
|
106
|
-
accounts = OpenStax::Accounts::Account.none
|
107
|
-
end
|
108
|
-
|
109
|
-
# Rerun the queries above for 'any' terms (which are ones without a
|
110
|
-
# prefix).
|
111
|
-
|
112
|
-
with.keyword :any do |terms|
|
113
|
-
names = prep_names(terms)
|
114
|
-
|
115
|
-
accounts = accounts.where{
|
116
|
-
(lower(username).like_any names) |
|
117
|
-
(lower(first_name).like_any names) |
|
118
|
-
(lower(last_name).like_any names) |
|
119
|
-
(lower(full_name).like_any names) |
|
120
|
-
(id.in terms)
|
121
|
-
}
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
# Pagination
|
127
|
-
|
128
|
-
page = options[:page] || 0
|
129
|
-
per_page = options[:per_page] || 20
|
130
|
-
|
131
|
-
accounts = accounts.limit(per_page).offset(per_page*page)
|
132
|
-
|
133
|
-
#
|
134
|
-
# Ordering
|
135
|
-
#
|
136
|
-
|
137
|
-
# Parse the input
|
138
|
-
order_bys = (options[:order_by] || 'username').split(',')
|
139
|
-
.collect{|ob| ob.strip.split(' ')}
|
140
|
-
|
141
|
-
# Toss out bad input, provide default direction
|
142
|
-
order_bys = order_bys.collect do |order_by|
|
143
|
-
field, direction = order_by
|
144
|
-
next if !SORTABLE_FIELDS.include?(field)
|
145
|
-
direction ||= SORT_ASCENDING
|
146
|
-
next if direction != SORT_ASCENDING && direction != SORT_DESCENDING
|
147
|
-
[field, direction]
|
148
|
-
end
|
149
|
-
|
150
|
-
order_bys.compact!
|
151
|
-
|
152
|
-
# Use a default sort if none provided
|
153
|
-
order_bys = ['username', SORT_ASCENDING] if order_bys.empty?
|
154
|
-
|
155
|
-
# Convert to query style
|
156
|
-
order_bys = order_bys.collect{|order_by| "#{order_by[0]} #{order_by[1]}"}
|
157
|
-
|
158
|
-
# Make the ordering call
|
159
|
-
order_bys.each do |order_by|
|
160
|
-
accounts = accounts.order(order_by)
|
161
|
-
end
|
162
|
-
|
163
|
-
# Translate to routine outputs
|
164
|
-
|
165
|
-
outputs[:accounts] = accounts
|
166
|
-
outputs[:query] = query
|
167
|
-
outputs[:per_page] = per_page
|
168
|
-
outputs[:page] = page
|
169
|
-
outputs[:order_by] = order_bys.join(', ') # Convert back to String
|
170
|
-
outputs[:num_matching_accounts] = accounts
|
171
|
-
.except(:offset, :limit, :order).count
|
172
|
-
|
29
|
+
run(:local_search, params)
|
173
30
|
end
|
174
31
|
|
175
|
-
# Return no results if query exceeds maximum allowed number of matches
|
176
|
-
max_accounts = options[:max_matching_accounts] || \
|
177
|
-
OpenStax::Accounts.configuration.max_matching_accounts
|
178
|
-
outputs[:accounts] = OpenStax::Accounts::Account.none \
|
179
|
-
if outputs[:num_matching_accounts] > max_accounts
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
# Downcase, remove all wildcards and put a wildcard at the end.
|
184
|
-
def prep_names(names)
|
185
|
-
names.collect{|name| "#{name.downcase.gsub('%', '')}%"}
|
186
32
|
end
|
187
33
|
|
188
34
|
end
|
189
|
-
|
190
35
|
end
|
191
36
|
end
|