ucb_rails_user 8.0.5 → 8.1.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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -19
  3. data/app/assets/javascripts/ucb_rails_user/datatables.js +16891 -0
  4. data/app/assets/javascripts/ucb_rails_user/esm/bloodhound.js +953 -0
  5. data/app/assets/javascripts/ucb_rails_user/esm/datatables.js +28437 -0
  6. data/app/assets/javascripts/ucb_rails_user/esm/typeahead.js +1538 -0
  7. data/app/assets/javascripts/ucb_rails_user/typeahead.bundle.js +2451 -0
  8. data/app/assets/javascripts/ucb_rails_user/ucb_rails_user.js +56 -0
  9. data/app/assets/stylesheets/ucb_rails_user/components/impersonations.css +0 -26
  10. data/app/assets/stylesheets/ucb_rails_user/components/users_table.css +3 -52
  11. data/app/assets/stylesheets/ucb_rails_user/pagy_tailwind.css +21 -0
  12. data/app/controllers/concerns/ucb_rails_user/sessions_controller_concerns.rb +3 -3
  13. data/app/controllers/concerns/ucb_rails_user/users_controller_concerns.rb +5 -24
  14. data/app/views/ucb_rails_user/impersonations/index.html.erb +5 -17
  15. data/app/views/ucb_rails_user/sessions/new.html.erb +21 -0
  16. data/app/views/ucb_rails_user/users/_user.html.erb +3 -1
  17. data/app/views/ucb_rails_user/users/edit.html.erb +2 -4
  18. data/app/views/ucb_rails_user/users/index.html.erb +30 -115
  19. data/app/views/ucb_rails_user/users/new.html.erb +17 -15
  20. data/config/routes.rb +2 -2
  21. data/lib/ucb_rails_user/configuration/cas.rb +9 -0
  22. data/lib/ucb_rails_user/spec_helpers.rb +1 -0
  23. data/lib/ucb_rails_user/version.rb +1 -1
  24. metadata +19 -15
  25. data/app/views/ucb_rails_user/users/impersonate_search.html.erb +0 -25
  26. data/app/views/ucb_rails_user/users/search.html.erb +0 -15
  27. data/config/importmap.rb +0 -2
@@ -35,6 +35,20 @@ var addDatatablesToUsersTable = function () {
35
35
  $('.ucb-rails-users-table-wrapper #DataTables_Table_0_filter').append(addNewHtml)
36
36
  }
37
37
 
38
+ var resetImpersonateButton = function() {
39
+ var targetId = $('#ucb_rails_user_impersonation_target_id').val()
40
+ if (targetId != null && targetId.toString().length > 0) {
41
+ $('input[data-impersonate-button]').removeAttr('disabled')
42
+ } else {
43
+ $('input[data-impersonate-button]').attr('disabled', 'disabled')
44
+ }
45
+ }
46
+
47
+ var clearImpersonateSelection = function() {
48
+ $('#ucb_rails_user_impersonation_target_id').val('')
49
+ resetImpersonateButton()
50
+ }
51
+
38
52
  $( window ).on("load", function() {
39
53
  // the datatable calling was failing intermittently, but adding the timeout
40
54
  // seemed to fix it, so ¯\_(ツ)_/¯
@@ -44,4 +58,46 @@ $( window ).on("load", function() {
44
58
  $('.search-results').hide()
45
59
  $('.ucb-rails-user-loader').show()
46
60
  })
61
+
62
+ var usersSource = new Bloodhound({
63
+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
64
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
65
+ remote: {
66
+ url: '/admin/users/impersonate_search?q=%QUERY',
67
+ wildcard: '%QUERY'
68
+ }
69
+ });
70
+
71
+ $('#ucb_rails_user_impersonation_target').typeahead(null, {
72
+ name: 'users',
73
+ source: usersSource,
74
+ display: 'name',
75
+ limit: 7, // any higher than this, and the results don't display properly
76
+ templates: {
77
+ empty: [
78
+ '<div class="empty-message">',
79
+ 'No match found',
80
+ '</div>'
81
+ ].join('\n'),
82
+ suggestion: function (data) {
83
+ return '<div><strong>' + data.name + '</strong> (' + data.uid + ')</div>'
84
+ }
85
+ }
86
+ });
87
+
88
+ $('#ucb_rails_user_impersonation_target').keyup(function(event) {
89
+ if ($(event.target).val().length == 0) {
90
+ clearImpersonateSelection()
91
+ }
92
+ })
93
+
94
+ $('#ucb_rails_user_impersonation_target').bind('typeahead:open', function(event, suggestion) {
95
+ clearImpersonateSelection()
96
+ })
97
+
98
+ $('#ucb_rails_user_impersonation_target').bind('typeahead:select', function(event, suggestion) {
99
+ $('#ucb_rails_user_impersonation_target_id').val(suggestion.id)
100
+ resetImpersonateButton()
101
+ })
102
+
47
103
  })
@@ -10,29 +10,3 @@
10
10
  .recent-impersonations li {
11
11
  list-style-type: none;
12
12
  font-size: 110%; }
13
-
14
- .impersonate_search_results_container {
15
- margin-top: 10px;
16
- }
17
-
18
- .impersonate_result_list {
19
- list-style: none;
20
- padding: 0;
21
- margin-top: 10px;
22
- }
23
-
24
- .impersonate_result_list_item {
25
- padding: 8px;
26
- border-bottom: 1px solid #eee;
27
- }
28
-
29
- .impersonate_no_results_found {
30
- margin-top: 10px;
31
- color: #999;
32
- }
33
-
34
- .impersonate_before_search {
35
- margin-top: 10px;
36
- color: #666;
37
- }
38
-
@@ -1,26 +1,13 @@
1
1
  .ucb-rails-users-table-header {
2
2
  margin-top: 16px;
3
- margin-bottom: 8px; }
3
+ margin-bottom: 16px; }
4
4
 
5
5
  .ucb-rails-users-table-header a {
6
- margin-top: 0px; }
7
-
8
- .ucb-rails-users-table-header form {
9
- display: flex !important;
10
- gap: 15px;
11
- align-items: center;
12
- flex-direction: row;
13
- }
14
-
15
- .ucb-rails-users-table-header form span,
16
- .ucb-rails-users-table-header form select,
17
- .ucb-rails-users-table-header form input {
18
- vertical-align: middle;
19
- }
6
+ margin-top: 16px; }
20
7
 
21
8
  table.ucb-rails-users-table {
22
9
  border-spacing: 0px;
23
- margin-top: 8px;
10
+ margin-top: 16px;
24
11
  }
25
12
 
26
13
  table.ucb-rails-users-table th {
@@ -65,39 +52,3 @@ h1 {
65
52
  padding-left: 10px;
66
53
  padding-right: 10px;
67
54
  }
68
-
69
- .user_sort {
70
- text-decoration: none;
71
- color: inherit;
72
- }
73
-
74
- .user_form_container {
75
- margin-top: 10px;
76
- overflow: auto;
77
- margin-bottom: 10px;
78
- vertical-align: middle;
79
- }
80
-
81
- .user_form_base_style {
82
- display: flex;
83
- gap: 10px;
84
- align-items:
85
- center; flex-grow: 1;
86
- }
87
-
88
- .user_form_return_count {
89
- float: left;
90
- padding-right: 15px;
91
- }
92
-
93
- .user_form_search_box {
94
- float: left;
95
- }
96
-
97
- .user_form_add_user_link {
98
- float: right;
99
- }
100
-
101
- .user_turbo_frame_users {
102
- margin-bottom: 10px;
103
- }
@@ -0,0 +1,21 @@
1
+ .pagy {
2
+ @apply flex space-x-1 font-semibold text-sm text-gray-500;
3
+ a:not(.gap) {
4
+ @apply block rounded-lg px-3 py-1 bg-gray-200;
5
+ &:hover {
6
+ @apply bg-gray-300;
7
+ }
8
+ &:not([href]) { /* disabled links */
9
+ @apply text-gray-300 bg-gray-100 cursor-default;
10
+ }
11
+ &.current {
12
+ @apply text-white bg-gray-400;
13
+ }
14
+ }
15
+ label {
16
+ @apply inline-block whitespace-nowrap bg-gray-200 rounded-lg px-3 py-0.5;
17
+ input {
18
+ @apply bg-gray-100 border-none rounded-md;
19
+ }
20
+ }
21
+ }
@@ -5,12 +5,12 @@ module UcbRailsUser::SessionsControllerConcerns
5
5
  skip_before_action :ensure_authenticated_user, :log_request, raise: false
6
6
  end
7
7
 
8
- # Redirects to authentication provider
8
+ # Renders login form for authentication provider
9
9
  #
10
10
  # @return [nil]
11
11
  def new
12
- provider = UcbRailsUser[:omniauth_provider] || :cas
13
- redirect_to "/auth/#{provider}"
12
+ @provider = UcbRailsUser[:omniauth_provider] || :cas
13
+ render 'ucb_rails_user/sessions/new'
14
14
  end
15
15
 
16
16
  # Login user after authentication by provider
@@ -9,20 +9,7 @@ module UcbRailsUser::UsersControllerConcerns
9
9
  end
10
10
 
11
11
  def index
12
- @sort = params[:sort] || "last_name"
13
- @sort_dir = params[:dir] || "asc"
14
-
15
- # Build the query
16
- users = if !params[:query].blank?
17
- search_user_table(params[:query])
18
- else
19
- UcbRailsUser.user_class.all
20
- end
21
-
22
- # Apply sorting
23
- users = users.order("#{@sort} #{@sort_dir}")
24
-
25
- @pagy, @users = pagy(users, limit: params[:count])
12
+ @pagy, @users = pagy(UcbRailsUser.user_class.all, limit: params[:count])
26
13
  end
27
14
 
28
15
  def search
@@ -37,12 +24,8 @@ module UcbRailsUser::UsersControllerConcerns
37
24
  end
38
25
 
39
26
  def impersonate_search
40
- @query = params[:q]
41
- @results = if @query.present? && @query.length >= 2
42
- UcbRailsUser::UserSearch.find_users_by_name(@query)
43
- else
44
- []
45
- end
27
+ result = UcbRailsUser::UserSearch.find_users_by_name(params[:q])
28
+ render json: result.map { |u| { name: u.full_name, id: u.id, uid: u.ldap_uid } }
46
29
  end
47
30
 
48
31
  def edit
@@ -108,6 +91,7 @@ module UcbRailsUser::UsersControllerConcerns
108
91
  @lps_existing_uids = UcbRailsUser.user_class.where(ldap_uid: uid_strings).pluck(:uid)
109
92
  render 'ucb_rails_user/lps/search'
110
93
  end
94
+
111
95
  end
112
96
 
113
97
  def typeahead_search
@@ -127,10 +111,6 @@ module UcbRailsUser::UsersControllerConcerns
127
111
 
128
112
  private
129
113
 
130
- def search_user_table(query)
131
- UcbRailsUser.user_class.where('lower(first_name) like lower(:q) or lower(last_name) like lower(:q) or lower(email) like lower(:q) or lower(alternate_email) like lower(:q) or ldap_uid like :q or ldap_uid like :q or employee_id like :q', q: '%' + query + '%')
132
- end
133
-
134
114
  def user_params(extra_params = [])
135
115
  params.require(:user).permit([
136
116
  :superuser_flag,
@@ -150,4 +130,5 @@ module UcbRailsUser::UsersControllerConcerns
150
130
  def find_user
151
131
  @user ||= UcbRailsUser.user_class.find(params.fetch(:id))
152
132
  end
133
+
153
134
  end
@@ -6,22 +6,10 @@
6
6
  </div>
7
7
  <% else %>
8
8
  <div class="impersonation-form">
9
- <%= form_with url: admin_user_impersonate_search_path, method: :get, data: { turbo_frame: "search_results" } do |f| %>
10
- <%= f.label :q, "Search for user:" %>
11
- <%= f.search_field :q, placeholder: "Enter name...", oninput: "
12
- clearTimeout(window.impersonateSearchTimer);
13
- window.impersonateSearchTimer = setTimeout(() => {
14
- if (this.value.length >= 2) {
15
- this.form.requestSubmit();
16
- }
17
- }, 300);
18
- " %>
19
- <% end %>
20
-
21
- <%= turbo_frame_tag "search_results" do %>
22
- <div style="margin-top: 10px; color: #666;">
23
- Type at least 2 characters to search for a user...
24
- </div>
9
+ <%= simple_form_for UcbRailsUser::Impersonation.new, url: admin_impersonations_path, method: :post do |f| %>
10
+ <%= f.input :target, label: "User", input_html: { class: "typeahead" } %>
11
+ <%= f.input :target_id, as: :hidden %>
12
+ <%= f.button :submit, value: "Impersonate", class: "btn btn-primary", disabled: true, data: { impersonate_button: true } %>
25
13
  <% end %>
26
14
  </div>
27
15
  <% end %>
@@ -32,7 +20,7 @@
32
20
  <ul>
33
21
  <% current_user.recent_impersonations.each do |imp| %>
34
22
  <li>
35
- <%= link_to full_name_with_uid(imp.target), admin_impersonations_path(ucb_rails_user_impersonation: { target_id: imp.target.id }), data: { turbo_method: :post, turbo_frame: "_top" } %>
23
+ <%= link_to full_name_with_uid(imp.target), "#{admin_impersonations_path}?ucb_rails_user_impersonation[target_id]=#{imp.target.id}", method: :post %>
36
24
  </li>
37
25
  <% end %>
38
26
  </ul>
@@ -0,0 +1,21 @@
1
+ <div style="display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f5f5f5;">
2
+ <div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; max-width: 400px; width: 100%;">
3
+ <h1 style="margin-bottom: 1.5rem; color: #333;">Sign In Required</h1>
4
+
5
+ <p style="margin-bottom: 2rem; color: #666;">Please sign in to continue</p>
6
+
7
+ <%= button_to "/auth/#{@provider}",
8
+ method: :post,
9
+ data: { turbo: false },
10
+ style: "background-color: #003262; color: white; padding: 12px 24px; font-size: 16px; border: none; border-radius: 4px; cursor: pointer; width: 100%; font-weight: 500;" do %>
11
+ Sign in with CalNet
12
+ <% end %>
13
+
14
+ <% if Rails.env.development? %>
15
+ <p style="margin-top: 2rem; font-size: 12px; color: #999;">
16
+ Environment: Development<br>
17
+ Provider: <%= @provider %>
18
+ </p>
19
+ <% end %>
20
+ </div>
21
+ </div>
@@ -1,3 +1,4 @@
1
+ <%= turbo_frame_tag "users" do %>
1
2
  <tr id="user_<%=user.id%>" class="user">
2
3
  <td><%= checkmark(user.superuser?) %></td>
3
4
  <td><%= checkmark(user.inactive?) %></td>
@@ -8,9 +9,10 @@
8
9
  <td class="min"><%= user.ldap_uid %></td>
9
10
  <td class="min"><%= user.employee_id %></td>
10
11
  <td>
11
- <%= link_to 'edit', edit_admin_user_path(user), class: 'btn btn-primary', id: dom_id(user, 'edit'), role: 'button', data: { turbo_frame: "users" } %>
12
+ <%= link_to 'edit', edit_admin_user_path(user), class: 'btn btn-blue', id: dom_id(user, 'edit') %>
12
13
  </td>
13
14
  <td>
14
15
  <%= button_to 'delete', admin_user_path(user), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-danger" %>
15
16
  </td>
16
17
  </tr>
18
+ <% end %>
@@ -1,5 +1,3 @@
1
- <%= turbo_frame_tag "users" do %>
2
- <h1>Edit User</h1>
1
+ <h1>Edit User</h1>
3
2
 
4
- <%= render partial: 'form', locals: { url: admin_user_path(@user), method: :put } %>
5
- <% end %>
3
+ <%= render partial: 'form', locals: { url: admin_user_path(@user), method: :put } %>
@@ -1,119 +1,34 @@
1
- <div class="ucb-rails-users-table-header">
1
+ <div class="ucb-rails-users-table-header clearfix">
2
2
  <h1>Users</h1>
3
3
  </div>
4
4
 
5
- <%= turbo_frame_tag "users" do %>
6
- <% if flash[:notice] || flash[:error] || flash[:alert] %>
7
- <div class="user_turbo_frame_users">
8
- <% if flash[:notice] %>
9
- <div class="alert alert-info"><%= flash[:notice] %></div>
10
- <% end %>
11
- <% if flash[:error] %>
12
- <div class="alert alert-danger"><%= flash[:error] %></div>
13
- <% end %>
14
- <% if flash[:alert] %>
15
- <div class="alert alert-warning"><%= flash[:alert] %></div>
16
- <% end %>
17
- </div>
18
- <% end %>
19
- <div class="user_form_container">
20
- <%= form_with url: "", method: :get, data: { turbo_frame: "users" }, class: "user_form_base_style" do |form| %>
21
- <%= form.hidden_field :sort, value: @sort %>
22
- <%= form.hidden_field :dir, value: @sort_dir %>
23
- <div class="user_form_return_count">
24
- Show <%= form.select :count, options_for_select([10, 25, 50, 100], selected: params[:count]), {}, { onchange: "this.form.requestSubmit()" } %>
25
- </div>
26
- <div class="user_form_search_box">
27
- Search <%= form.search_field :query, value: params[:query], id: "user_search_field", placeholder: "Search users...", data: { turbo_permanent: true }, oninput: "
28
- clearTimeout(window.searchTimer);
29
- window.searchTimer = setTimeout(() => {
30
- this.form.requestSubmit();
31
- }, 300);
32
- " %>
33
- </div>
34
- <% end %>
35
- <div class="user_form_add_user_link">
36
- <%= link_to "Add User", new_admin_user_path, class: "btn btn-primary" %>
37
- </div>
38
- </div>
39
- <div class="table-responsive ucb-rails-users-table-wrapper">
40
- <table class="table table-striped table-bordered table-hover ucb-rails-users-table">
41
- <thead>
42
- <tr>
43
- <th class="min">
44
- <%= link_to admin_users_path(sort: "superuser_flag", dir: @sort == "superuser_flag" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
45
- Superuser?
46
- <% if @sort == "superuser_flag" %>
47
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
48
- <% end %>
49
- <% end %>
50
- </th>
51
- <th class="min">
52
- <%= link_to admin_users_path(sort: "inactive_flag", dir: @sort == "inactive_flag" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
53
- Inactive?
54
- <% if @sort == "inactive_flag" %>
55
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
56
- <% end %>
57
- <% end %>
58
- </th>
59
- <th>
60
- <%= link_to admin_users_path(sort: "first_name", dir: @sort == "first_name" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
61
- First Name
62
- <% if @sort == "first_name" %>
63
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
64
- <% end %>
65
- <% end %>
66
- </th>
67
- <th>
68
- <%= link_to admin_users_path(sort: "last_name", dir: @sort == "last_name" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
69
- Last Name
70
- <% if @sort == "last_name" %>
71
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
72
- <% end %>
73
- <% end %>
74
- </th>
75
- <th>
76
- <%= link_to admin_users_path(sort: "email", dir: @sort == "email" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
77
- Email
78
- <% if @sort == "email" %>
79
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
80
- <% end %>
81
- <% end %>
82
- </th>
83
- <th class="dt">
84
- <%= link_to admin_users_path(sort: "last_login_at", dir: @sort == "last_login_at" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
85
- Last Login
86
- <% if @sort == "last_login_at" %>
87
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
88
- <% end %>
89
- <% end %>
90
- </th>
91
- <th>
92
- <%= link_to admin_users_path(sort: "ldap_uid", dir: @sort == "ldap_uid" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
93
- UID
94
- <% if @sort == "ldap_uid" %>
95
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
96
- <% end %>
97
- <% end %>
98
- </th>
99
- <th>
100
- <%= link_to admin_users_path(sort: "employee_id", dir: @sort == "employee_id" && @sort_dir == "asc" ? "desc" : "asc", query: params[:query], count: params[:count]), data: { turbo_frame: "users" }, class: "user_sort" do %>
101
- Employee ID
102
- <% if @sort == "employee_id" %>
103
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
104
- <% end %>
105
- <% end %>
106
- </th>
107
- <th class="min unsorted">Edit</th>
108
- <th class="min unsorted">Delete</th>
109
- </tr>
110
- </thead>
111
- <tbody class="highlight">
112
- <%= render partial: "ucb_rails_user/users/user", collection: @users %>
113
- </tbody>
114
- </table>
115
- <div class="ucb-rails-user">
116
- <%= pagy_nav(@pagy, pagy_url_for: ->(page, pagy) { admin_users_path(page: page, count: params[:count], query: params[:query], sort: @sort, dir: @sort_dir) }).html_safe %>
117
- </div>
118
- </div>
5
+ <%= form_with url: "", method: :get, data: { turbo_frame: "users", turbo_action: "advance" } do |form| %>
6
+ Show <%= form.select :count, options_for_select([10, 25, 50, 100], selected: params[:count]), {}, { onchange: "this.form.requestSubmit()" } %>
7
+
8
+ Search <%= form.search_field :query, value: params[:query], oninput: "this.form.requestSubmit()" %>
119
9
  <% end %>
10
+
11
+ <div class="table-responsive ucb-rails-users-table-wrapper">
12
+ <table class="table table-striped table-bordered table-hover ucb-rails-users-table">
13
+ <thead>
14
+ <tr>
15
+ <th class="min">Superuser?</th>
16
+ <th class="min">Inactive?</th>
17
+ <th>First Name</th>
18
+ <th>Last Name</th>
19
+ <th>Email</th>
20
+ <th class="dt">Last Login</th>
21
+ <th>UID</th>
22
+ <th>Employee ID</th>
23
+ <th class="min unsorted">Edit</th>
24
+ <th class="min unsorted">Delete</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody class="highlight">
28
+ <%= render partial: "ucb_rails_user/users/user", collection: @users %>
29
+ </tbody>
30
+ </table>
31
+ <div class="ucb-rails-user">
32
+ <%= pagy_nav(@pagy).html_safe %>
33
+ </div>
34
+ </div>
@@ -1,17 +1,19 @@
1
- <%= turbo_frame_tag "users" do %>
2
- <h2>Add New User</h2>
1
+ <h2>Add New User</h2>
3
2
 
4
- <%= form_tag admin_user_search_path, method: :get, class: "form-inline user-search-form" do %>
5
- <%= text_field_tag :first_name, "", placeholder: "First name", class: "form-control" %>
6
- <%= text_field_tag :last_name, "", placeholder: "Last name", class: "form-control" %>
7
- <%= text_field_tag :employee_id, "", placeholder: "Employee ID", class: "form-control" %>
8
- <%= submit_tag "Search", class: "btn btn-primary", data: { turbo_submits_with: "Searching..." } %>
9
- <%= link_to "Cancel", admin_users_path, class: "btn btn-default" %>
10
- <% end %>
11
-
12
- <div class="search-results">
13
- <% if @results %>
14
- <%= render "results" %>
15
- <% end %>
16
- </div>
3
+ <%= form_tag admin_user_search_path, method: :get, remote: true, class: "form-inline user-search-form" do %>
4
+ <%= text_field_tag :first_name, "", placeholder: "First name", class: "form-control" %>
5
+ <%= text_field_tag :last_name, "", placeholder: "Last name", class: "form-control" %>
6
+ <%= text_field_tag :employee_id, "", placeholder: "Employee ID", class: "form-control" %>
7
+ <%= submit_tag "Search", class: "btn btn-primary" %>
8
+ <%= link_to "Cancel", admin_users_path, class: "btn btn-default" %>
17
9
  <% end %>
10
+
11
+ <div class="ucb-rails-user-loader">
12
+ Loading...
13
+ </div>
14
+
15
+ <div class="search-results">
16
+ <% if @results %>
17
+ <%= render "results" %>
18
+ <% end %>
19
+ </div>
data/config/routes.rb CHANGED
@@ -5,8 +5,8 @@ Rails.application.routes.draw do
5
5
  match "/logout", to: UcbRailsUser::SessionsController.action(:destroy),
6
6
  as: "logout", via: [:all]
7
7
  match "/auth/:omniauth_provider/callback", to: UcbRailsUser::SessionsController.action(:create),
8
- via: [:get]
9
- match "/auth/failure", to: UcbRailsUser::SessionsController.action(:failure), via: [:get]
8
+ via: [:get, :post]
9
+ match "/auth/failure", to: UcbRailsUser::SessionsController.action(:failure), via: [:get, :post]
10
10
  match "/not_authorized", to: UcbRailsUser::SessionsController.action(:not_authorized),
11
11
  as: "not_authorized", via: [:get]
12
12
 
@@ -15,6 +15,15 @@ module UcbRailsUser
15
15
 
16
16
  def configure_omniauth
17
17
  host_name = host
18
+
19
+ # Configure OmniAuth to only accept POST requests for security (CVE-2015-9284)
20
+ OmniAuth.config.allowed_request_methods = [:post]
21
+ OmniAuth.config.silence_get_warning = true
22
+
23
+ # Disable CSRF protection for OmniAuth - we handle security through POST-only
24
+ # This is safe because we're only allowing POST requests and CAS provides its own security
25
+ OmniAuth.config.request_validation_phase = nil
26
+
18
27
  Rails.application.config.middleware.use OmniAuth::Builder do
19
28
 
20
29
  unless Rails.env.production?
@@ -13,6 +13,7 @@ module UcbRailsUser
13
13
  OmniAuth.config.test_mode = true
14
14
  auth_mock(user.ldap_uid)
15
15
  visit login_path()
16
+ click_on "Sign in with CalNet"
16
17
  end
17
18
 
18
19
  def auth_mock(uid)
@@ -1,3 +1,3 @@
1
1
  module UcbRailsUser
2
- VERSION = '8.0.5'
2
+ VERSION = '8.1.0'
3
3
  end