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.
Files changed (43) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/stylesheets/openstax/accounts/dev.css.scss +4 -0
  3. data/app/controllers/openstax/accounts/dev/accounts_controller.rb +2 -2
  4. data/app/handlers/openstax/accounts/accounts_search.rb +66 -0
  5. data/app/handlers/openstax/accounts/dev/accounts_search.rb +10 -21
  6. data/app/models/openstax/accounts/group.rb +12 -8
  7. data/app/representers/openstax/accounts/api/v1/account_representer.rb +5 -0
  8. data/app/representers/openstax/accounts/api/v1/account_search_representer.rb +12 -17
  9. data/app/representers/openstax/accounts/api/v1/application_account_search_representer.rb +3 -1
  10. data/app/routines/openstax/accounts/dev/create_account.rb +1 -1
  11. data/app/routines/openstax/accounts/search_accounts.rb +16 -171
  12. data/app/routines/openstax/accounts/search_local_accounts.rb +101 -0
  13. data/app/views/openstax/accounts/dev/accounts/_search_results.html.erb +19 -45
  14. data/app/views/openstax/accounts/dev/accounts/index.html.erb +11 -8
  15. data/app/views/openstax/accounts/shared/accounts/_search.html.erb +9 -6
  16. data/db/migrate/{20140811182433_create_openstax_accounts_groups.rb → 1_create_openstax_accounts_groups.rb} +0 -0
  17. data/db/migrate/{20140811182505_create_openstax_accounts_group_members.rb → 2_create_openstax_accounts_group_members.rb} +0 -0
  18. data/db/migrate/{20140811182527_create_openstax_accounts_group_owners.rb → 3_create_openstax_accounts_group_owners.rb} +0 -0
  19. data/db/migrate/{20140811182553_create_openstax_accounts_group_nestings.rb → 4_create_openstax_accounts_group_nestings.rb} +0 -0
  20. data/lib/openstax/accounts/engine.rb +1 -0
  21. data/lib/openstax/accounts/has_many_through_groups.rb +4 -2
  22. data/lib/openstax/accounts/version.rb +1 -1
  23. data/lib/openstax_accounts.rb +11 -5
  24. data/spec/controllers/openstax/accounts/dev/accounts_controller_spec.rb +1 -1
  25. data/spec/controllers/openstax/accounts/sessions_controller_spec.rb +1 -1
  26. data/spec/dummy/app/access_policies/account_access_policy.rb +11 -0
  27. data/spec/dummy/app/controllers/oauth_controller.rb +2 -0
  28. data/spec/dummy/config/environments/production.rb +1 -1
  29. data/spec/dummy/config/environments/test.rb +1 -1
  30. data/spec/dummy/config/initializers/access_policies.rb +1 -0
  31. data/spec/dummy/config/initializers/doorkeeper.rb +75 -0
  32. data/spec/dummy/config/initializers/openstax_accounts.rb +2 -1
  33. data/spec/dummy/db/migrate/{1_create_users.rb → 5_create_users.rb} +0 -0
  34. data/spec/dummy/db/migrate/{2_create_ownerships.rb → 6_create_ownerships.rb} +0 -0
  35. data/spec/dummy/db/schema.rb +1 -1
  36. data/spec/factories/openstax_accounts_account.rb +1 -1
  37. data/spec/factories/openstax_accounts_group.rb +1 -1
  38. data/spec/handlers/openstax/accounts/accounts_search_spec.rb +63 -0
  39. data/spec/handlers/openstax/accounts/dev/accounts_search_spec.rb +55 -0
  40. data/spec/lib/openstax_accounts_spec.rb +66 -66
  41. data/spec/routines/openstax/accounts/search_accounts_spec.rb +23 -23
  42. metadata +60 -15
  43. data/app/routines/openstax/accounts/dev/search_accounts.rb +0 -27
@@ -0,0 +1,101 @@
1
+ module OpenStax
2
+ module Accounts
3
+ class SearchLocalAccounts
4
+
5
+ SORTABLE_FIELDS = {
6
+ 'username' => :username,
7
+ 'first_name' => :first_name,
8
+ 'last_name' => :last_name,
9
+ 'full_name' => :full_name,
10
+ 'id' => :openstax_uid,
11
+ 'created_at' => :created_at
12
+ }
13
+
14
+ lev_routine
15
+
16
+ uses_routine OSU::SearchAndOrganizeRelation, as: :search,
17
+ translations: { outputs: { type: :verbatim } }
18
+
19
+ def exec(*args)
20
+ params = args.last.is_a?(Hash) ? args.pop : {}
21
+ params[:q] ||= args[0]
22
+ params[:ob] ||= args[1]
23
+ params[:pp] ||= args[2]
24
+ params[:p] ||= args[3]
25
+
26
+ run(:search, :relation => OpenStax::Accounts::Account.unscoped,
27
+ :sortable_fields => SORTABLE_FIELDS,
28
+ :params => params) do |with|
29
+
30
+ with.default_keyword :any
31
+
32
+ with.keyword :username do |names|
33
+ names.each do |name|
34
+ sanitized_names = to_string_array(name, append_wildcard: true)
35
+ next @items = @items.none if sanitized_names.empty?
36
+ @items = @items.where{username.like_any sanitized_names}
37
+ end
38
+ end
39
+
40
+ with.keyword :first_name do |names|
41
+ names.each do |name|
42
+ sanitized_names = to_string_array(name, append_wildcard: true)
43
+ next @items = @items.none if sanitized_names.empty?
44
+ @items = @items.where{first_name.like_any sanitized_names}
45
+ end
46
+ end
47
+
48
+ with.keyword :last_name do |names|
49
+ names.each do |name|
50
+ sanitized_names = to_string_array(name, append_wildcard: true)
51
+ next @items = @items.none if sanitized_names.empty?
52
+ @items = @items.where{last_name.like_any sanitized_names}
53
+ end
54
+ end
55
+
56
+ with.keyword :full_name do |names|
57
+ names.each do |name|
58
+ sanitized_names = to_string_array(name, append_wildcard: true)
59
+ next @items = @items.none if sanitized_names.empty?
60
+ @items = @items.where{full_name.like_any sanitized_names}
61
+ end
62
+ end
63
+
64
+ with.keyword :name do |names|
65
+ names.each do |name|
66
+ sanitized_names = to_string_array(name, append_wildcard: true)
67
+ next @items = @items.none if sanitized_names.empty?
68
+ @items = @items.where{(username.like_any sanitized_names) | \
69
+ (first_name.like_any sanitized_names) | \
70
+ (last_name.like_any sanitized_names) | \
71
+ (full_name.like_any sanitized_names)}
72
+ end
73
+ end
74
+
75
+ with.keyword :id do |ids|
76
+ ids.each do |id|
77
+ sanitized_ids = to_string_array(id)
78
+ next @items = @items.none if sanitized_ids.empty?
79
+ @items = @items.where{(openstax_uid.eq_any sanitized_ids)}
80
+ end
81
+ end
82
+
83
+ with.keyword :any do |terms|
84
+ terms.each do |term|
85
+ sanitized_names = to_string_array(term, append_wildcard: true)
86
+ sanitized_ids = to_string_array(term)
87
+ next @items = @items.none if sanitized_names.empty? || sanitized_ids.empty?
88
+
89
+ @items = @items.where{(username.like_any sanitized_names) | \
90
+ (first_name.like_any sanitized_names) | \
91
+ (last_name.like_any sanitized_names) | \
92
+ (full_name.like_any sanitized_names) | \
93
+ (openstax_uid.eq_any sanitized_ids)}
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -1,52 +1,26 @@
1
- <%
2
- page = @handler_result.outputs[:page]
3
- num_accounts = @handler_result.outputs[:num_matching_accounts]
4
- per_page = @handler_result.outputs[:per_page]
5
- pages = (num_accounts * 1.0 / per_page).ceil
6
- accounts = @handler_result.outputs[:accounts]
7
- %>
1
+ <% total_count = @handler_result.outputs[:total_count]
2
+ accounts = @handler_result.outputs[:items] %>
8
3
 
9
- <div id='search-results-pagination'>
10
- <%= pluralize(num_accounts, 'user') %> found.
11
-
12
- <% if pages > 0 %>
13
- Page:
14
-
15
- <%
16
- linked_page_numbers = [page+1]
17
- linked_page_numbers.push(1)
18
- linked_page_numbers.push(pages)
19
- linked_page_numbers.push(page+1-1, page+1-2, page+1+1, page+1+2)
20
- linked_page_numbers.reject!{|pp| pp < 1 || pp > pages}
21
- linked_page_numbers.uniq!
22
- linked_page_numbers.sort!
23
- %>
24
-
25
- <% linked_page_numbers.each do |lpn| %>
26
- <%= link_to_unless lpn == page + 1,
27
- lpn,
28
- dev_accounts_path(search: {terms: @handler_result.outputs[:query], page: lpn-1, per_page: per_page}), remote: true %>
29
- <% end %>
30
- <% end %>
4
+ <div id='search-results-count'>
5
+ <%= pluralize(total_count, 'user') %> found.
31
6
  </div>
32
7
 
33
8
  <div id='search-results-list'>
34
9
  <%= osu.action_list(
35
- records: accounts,
36
- list: {
37
- headings: ['Username', 'Title', 'Name', 'Actions'],
38
- widths: ['30%', '10%', '40%', '20%'],
39
- data_procs:
40
- [
41
- lambda { |account| account.username },
42
- lambda { |account| account.title || '---' },
43
- lambda { |account| account.name || '---' },
44
- lambda { |account|
45
- link_to 'Sign in as',
46
- with_interceptor { become_dev_account_path(account) },
10
+ records: accounts,
11
+ list: {
12
+ headings: ['UID', 'Username (click to sign in as)', 'Name'],
13
+ widths: ['20%', '40%', '40%'],
14
+ data_procs: [
15
+ lambda { |account| account.openstax_uid },
16
+ lambda { |account|
17
+ link_to account.username,
18
+ with_interceptor { become_dev_account_path(
19
+ account.openstax_uid) },
47
20
  method: :post
48
- }
49
- ]
50
- }
51
- ) %>
21
+ },
22
+ lambda { |account| account.name || '---' }
23
+ ]
24
+ }
25
+ ) %>
52
26
  </div>
@@ -1,24 +1,25 @@
1
1
  <div class="openstax-accounts development-login">
2
2
 
3
- <% handler_errors.each do |error| %>
4
- <%= error.translate %>
5
- <% end %>
3
+ <%= render partial: 'openstax/accounts/shared/attention' %>
6
4
 
7
5
  <h3>Create an Account</h3>
8
6
 
9
7
  <%= lev_form_for :create,
10
8
  url: openstax_accounts.dev_accounts_path,
11
- method: :post do |f| %>
9
+ method: :post,
10
+ html: {class: 'form-inline'} do |f| %>
12
11
 
13
- Username
14
- <%= f.text_field :username, style: 'width:300px' %>
15
- <%= f.submit 'Create', class: 'btn btn-primary' %>
12
+ <%= f.label :username %>&nbsp;
13
+ <div class="form-group">
14
+ <%= f.text_field :username %>&nbsp;
15
+ <%= f.submit 'Create', class: 'btn btn-primary' %>
16
+ </div>
16
17
 
17
18
  <% end %>
18
19
 
19
20
  <h3>Development Login</h3>
20
21
 
21
- <p>You need to login, but we're not connected to the Accounts server.
22
+ <p>You need to login, but we're not connected to the Accounts server.<br>
22
23
  Search for a user below and click the sign in link next to him or her.</p>
23
24
 
24
25
  <%= with_interceptor {
@@ -27,5 +28,7 @@
27
28
  :remote => true, :method => :get } } %>
28
29
 
29
30
  <br>
31
+
30
32
  <div id="search-results"></div>
33
+
31
34
  </div>
@@ -5,7 +5,8 @@
5
5
  remote ||= false
6
6
  form_html ||= {id: 'search-form',
7
7
  class: 'form-inline'}
8
- search_types ||= ['Any', 'Username', 'Email']
8
+ search_types ||= ['Any', 'Username', 'Name',
9
+ 'First Name', 'Last Name', 'Email']
9
10
  %>
10
11
 
11
12
  <%= lev_form_for :search,
@@ -14,11 +15,13 @@
14
15
  method: method,
15
16
  html: form_html do |f| %>
16
17
 
17
- Search for
18
- <%= f.search_field :terms, style: 'width:300px' %>
19
- in
20
- <%= f.select :type, search_types, {}, {style: 'width: 150px'} %>
18
+ <div class="form-group">
19
+ <%= f.label :query, 'Search for' %>&nbsp;
20
+ <%= f.search_field :query, style: 'width:300px' %>&nbsp;
21
+ <%= f.label :type, 'in' %>&nbsp;
22
+ <%= f.select :type, search_types, {}, {style: 'width: 150px'} %>&nbsp;
21
23
 
22
- <%= f.submit 'Search', class: 'btn btn-primary' %>
24
+ <%= f.submit 'Search', class: 'btn btn-primary' %>
25
+ </div>
23
26
 
24
27
  <% end %>
@@ -7,6 +7,7 @@ require 'keyword_search'
7
7
  require 'squeel'
8
8
  require 'action_interceptor'
9
9
  require 'openstax/accounts/extend_builtins'
10
+ require 'doorkeeper'
10
11
 
11
12
  ActiveSupport::Inflector.inflections do |inflect|
12
13
  inflect.acronym 'OpenStax'
@@ -16,7 +16,7 @@ module OpenStax
16
16
 
17
17
  define_method(name) do
18
18
  OpenStax::Accounts::Group.includes(association_name)
19
- .where(id: supertree_group_ids)
19
+ .where(openstax_uid: supertree_group_ids)
20
20
  .collect{|g| g.send(association_name).to_a}.flatten.uniq
21
21
  end
22
22
  end
@@ -29,7 +29,9 @@ module OpenStax
29
29
  send(association_name).to_a : []
30
30
  indirect_records = OpenStax::Accounts::Group
31
31
  .includes(association_name).where(
32
- id: send(groups_name).collect{|g| g.supertree_group_ids}.flatten.uniq
32
+ openstax_uid: send(groups_name).collect{|g|
33
+ g.supertree_group_ids
34
+ }.flatten.uniq
33
35
  )
34
36
  .collect{|g| g.send(association_name).to_a}
35
37
  (direct_records + indirect_records).flatten.uniq
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Accounts
3
- VERSION = "3.1.1"
3
+ VERSION = "4.0.0"
4
4
  end
5
5
  end
@@ -74,12 +74,17 @@ module OpenStax
74
74
  # See the "account_user_mapper" discussion in the README
75
75
  attr_accessor :account_user_mapper
76
76
 
77
- # max_matching_accounts
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
78
84
  # The maximum number of accounts that can be returned
79
- # in a call to SearchAccounts
85
+ # in a call to the AccountsSearch handler
80
86
  # If more would be returned, the result will be empty instead
81
- # Can also be passed directly to SearchAccounts
82
- attr_accessor :max_matching_accounts
87
+ attr_accessor :max_search_items
83
88
 
84
89
  def openstax_accounts_url=(url)
85
90
  url.gsub!(/https|http/,'https') if !(url =~ /localhost/)
@@ -98,7 +103,8 @@ module OpenStax
98
103
  @default_errors_added_trigger = 'openstax-accounts-errors-added'
99
104
  @security_transgression_exception = SecurityTransgression
100
105
  @account_user_mapper = OpenStax::Accounts::DefaultAccountUserMapper
101
- @max_matching_accounts = 10
106
+ @min_search_characters = 3
107
+ @max_search_items = 10
102
108
  super
103
109
  end
104
110
 
@@ -12,7 +12,7 @@ module OpenStax::Accounts
12
12
  it 'should allow users not in production to become other users' do
13
13
  expect(controller.current_account).to eq(AnonymousAccount.instance)
14
14
  expect(controller.current_account.is_anonymous?).to eq(true)
15
- post :become, id: account.id
15
+ post :become, id: account.openstax_uid
16
16
  expect(controller.current_account).to eq(account)
17
17
  expect(controller.current_account.is_anonymous?).to eq(false)
18
18
  end
@@ -12,7 +12,7 @@ module OpenStax::Accounts
12
12
  c = controller
13
13
  get :new
14
14
  expect(response).to redirect_to(
15
- c.send(:with_interceptor) { c.dev_accounts_path })
15
+ c.send(:with_interceptor) { url_for(c.dev_accounts_path) })
16
16
  expect(response.code).to eq('302')
17
17
  end
18
18
 
@@ -0,0 +1,11 @@
1
+ class AccountAccessPolicy
2
+ # Contains all the rules for which requestors can do what with which Account objects.
3
+
4
+ def self.action_allowed?(action, requestor, account)
5
+ case action
6
+ when :search # Anyone
7
+ true
8
+ end
9
+ end
10
+
11
+ end
@@ -1,3 +1,5 @@
1
+ require 'responders'
2
+
1
3
  class OauthController < ApplicationController
2
4
  respond_to :json
3
5
 
@@ -20,7 +20,7 @@ Dummy::Application.configure do
20
20
  # config.action_dispatch.rack_cache = true
21
21
 
22
22
  # Disable Rails's static asset server (Apache or nginx will already do this).
23
- config.serve_static_assets = false
23
+ config.serve_static_files = false
24
24
 
25
25
  # Compress JavaScripts and CSS.
26
26
  config.assets.js_compressor = :uglifier
@@ -13,7 +13,7 @@ Dummy::Application.configure do
13
13
  config.eager_load = false
14
14
 
15
15
  # Configure static asset server for tests with Cache-Control for performance.
16
- config.serve_static_assets = true
16
+ config.serve_static_files = true
17
17
  config.static_cache_control = 'public, max-age=3600'
18
18
 
19
19
  # Show full error reports and disable caching.
@@ -0,0 +1 @@
1
+ OSU::AccessPolicy.register(OpenStax::Accounts::Account, AccountAccessPolicy)
@@ -0,0 +1,75 @@
1
+ Doorkeeper.configure do
2
+ # Change the ORM that doorkeeper will use.
3
+ # Currently supported options are :active_record, :mongoid2, :mongoid3, :mongo_mapper
4
+ orm :active_record
5
+
6
+ # This block will be called to check whether the resource owner is authenticated or not.
7
+ resource_owner_authenticator do
8
+ raise "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
9
+ # Put your resource owner authentication logic here.
10
+ # Example implementation:
11
+ # User.find_by_id(session[:user_id]) || redirect_to(new_user_session_url)
12
+ end
13
+
14
+ # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
15
+ # admin_authenticator do
16
+ # # Put your admin authentication logic here.
17
+ # # Example implementation:
18
+ # Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url)
19
+ # end
20
+
21
+ # Authorization Code expiration time (default 10 minutes).
22
+ # authorization_code_expires_in 10.minutes
23
+
24
+ # Access token expiration time (default 2 hours).
25
+ # If you want to disable expiration, set this to nil.
26
+ # access_token_expires_in 2.hours
27
+
28
+ # Issue access tokens with refresh token (disabled by default)
29
+ # use_refresh_token
30
+
31
+ # Provide support for an owner to be assigned to each registered application (disabled by default)
32
+ # Optional parameter :confirmation => true (default false) if you want to enforce ownership of
33
+ # a registered application
34
+ # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
35
+ # enable_application_owner :confirmation => false
36
+
37
+ # Define access token scopes for your provider
38
+ # For more information go to https://github.com/applicake/doorkeeper/wiki/Using-Scopes
39
+ # default_scopes :public
40
+ # optional_scopes :write, :update
41
+
42
+ # Change the way client credentials are retrieved from the request object.
43
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
44
+ # falls back to the `:client_id` and `:client_secret` params from the `params` object.
45
+ # Check out the wiki for more information on customization
46
+ # client_credentials :from_basic, :from_params
47
+
48
+ # Change the way access token is authenticated from the request object.
49
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
50
+ # falls back to the `:access_token` or `:bearer_token` params from the `params` object.
51
+ # Check out the wiki for more information on customization
52
+ # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
53
+
54
+ # Change the test redirect uri for client apps
55
+ # When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
56
+ # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
57
+ # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
58
+ #
59
+ # test_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
60
+
61
+ # Under some circumstances you might want to have applications auto-approved,
62
+ # so that the user skips the authorization step.
63
+ # For example if dealing with trusted a application.
64
+ # skip_authorization do |resource_owner, client|
65
+ # client.superapp? or resource_owner.admin?
66
+ # end
67
+
68
+ #Â WWW-Authenticate Realm (default "Doorkeeper").
69
+ # realm "Doorkeeper"
70
+
71
+ # Allow dynamic query parameters (disabled by default)
72
+ # Some applications require dynamic query parameters on their request_uri
73
+ # set to true if you want this to be allowed
74
+ # wildcard_redirect_uri false
75
+ end