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.
- checksums.yaml +4 -4
- data/README.md +1 -19
- data/app/assets/javascripts/ucb_rails_user/datatables.js +16891 -0
- data/app/assets/javascripts/ucb_rails_user/esm/bloodhound.js +953 -0
- data/app/assets/javascripts/ucb_rails_user/esm/datatables.js +28437 -0
- data/app/assets/javascripts/ucb_rails_user/esm/typeahead.js +1538 -0
- data/app/assets/javascripts/ucb_rails_user/typeahead.bundle.js +2451 -0
- data/app/assets/javascripts/ucb_rails_user/ucb_rails_user.js +56 -0
- data/app/assets/stylesheets/ucb_rails_user/components/impersonations.css +0 -26
- data/app/assets/stylesheets/ucb_rails_user/components/users_table.css +3 -52
- data/app/assets/stylesheets/ucb_rails_user/pagy_tailwind.css +21 -0
- data/app/controllers/concerns/ucb_rails_user/sessions_controller_concerns.rb +3 -3
- data/app/controllers/concerns/ucb_rails_user/users_controller_concerns.rb +5 -24
- data/app/views/ucb_rails_user/impersonations/index.html.erb +5 -17
- data/app/views/ucb_rails_user/sessions/new.html.erb +21 -0
- data/app/views/ucb_rails_user/users/_user.html.erb +3 -1
- data/app/views/ucb_rails_user/users/edit.html.erb +2 -4
- data/app/views/ucb_rails_user/users/index.html.erb +30 -115
- data/app/views/ucb_rails_user/users/new.html.erb +17 -15
- data/config/routes.rb +2 -2
- data/lib/ucb_rails_user/configuration/cas.rb +9 -0
- data/lib/ucb_rails_user/spec_helpers.rb +1 -0
- data/lib/ucb_rails_user/version.rb +1 -1
- metadata +19 -15
- data/app/views/ucb_rails_user/users/impersonate_search.html.erb +0 -25
- data/app/views/ucb_rails_user/users/search.html.erb +0 -15
- 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:
|
|
3
|
+
margin-bottom: 16px; }
|
|
4
4
|
|
|
5
5
|
.ucb-rails-users-table-header a {
|
|
6
|
-
margin-top:
|
|
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:
|
|
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
|
-
#
|
|
8
|
+
# Renders login form for authentication provider
|
|
9
9
|
#
|
|
10
10
|
# @return [nil]
|
|
11
11
|
def new
|
|
12
|
-
provider = UcbRailsUser[:omniauth_provider] || :cas
|
|
13
|
-
|
|
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
|
-
@
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
<%=
|
|
10
|
-
<%= f.
|
|
11
|
-
<%= f.
|
|
12
|
-
|
|
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
|
|
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-
|
|
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,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
|
-
<%=
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
2
|
-
<h2>Add New User</h2>
|
|
1
|
+
<h2>Add New User</h2>
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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?
|