ucb_rails_user 8.0.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7dfe2bed6cddf061bb3792211ef87bf6c09aa4de9a71b1896aefe3d3b2cd5fe
4
- data.tar.gz: c91dc9d3272bcbfa11ea36c55f3fc20dacaa97bbf845980bd8686fa31ed2df86
3
+ metadata.gz: '09287b7395b9051f836da163e113b19e79b97f2ca1a4244ac647fb01de4ef398'
4
+ data.tar.gz: 91ed2a6b9f2d2aa7a1a8d41c16bca50d179e17eeaec497fce684d606eef3d9ce
5
5
  SHA512:
6
- metadata.gz: a8d53e14084804c70c9f45d0047d1bbc42675119152f13e8ad623c71a1bc794bc8c1ec12a87a4eae7e85a59d0e33d8acc972612e9552bd3b098df731ef784f3f
7
- data.tar.gz: d617d72f9956670b894e91268e9574410a00413db4e0b1e1873bd980a928173f8a2a8dc8334e8d9d3de6d7a02a3220859f9f1c8e1ef4abc5fae22d6308a3cb28
6
+ metadata.gz: 14686fd6c41309f33ae5d16d427c7d6270f6a0f1601d2f2ded8d22562c4cfd124e92f2ca3e3d59a5079309cc1413514c1448c1ce6583b3c51e005c02d5799cb7
7
+ data.tar.gz: 5273939befe8db63989e4e4f6940ec23e93f9cecaf1a7aeb20c7acbcad60cd415154b0e4b87b25391bb7dc3a05f3e80c04759d64e7fcc5ce335d6e17a0bc9ff1
data/README.md CHANGED
@@ -89,23 +89,7 @@ And in `application.js` add this line:
89
89
  //= require ucb_rails_user/scripts
90
90
  ```
91
91
 
92
- 9. Enable Turbo (required for admin user search functionality)
93
-
94
- The admin user search uses Turbo Frames for seamless searching without page reloads. Add this to your application layout (typically `app/views/layouts/application.html.erb`):
95
-
96
- ```erb
97
- <%= turbo_include_tags %>
98
- ```
99
-
100
- Also update any `data-turbolinks-track` attributes to use `data-turbo-track` instead:
101
-
102
- ```erb
103
- <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
104
- ```
105
-
106
- If your app doesn't already include Turbo, make sure the `turbo-rails` gem is in your Gemfile (it's included as a dependency of this gem).
107
-
108
- 10. Restart your host app as usual
92
+ 9. Restart your host app as usual
109
93
 
110
94
  You should be able to access the following routes:
111
95
 
@@ -306,5 +290,3 @@ There is a new session timeout gem that can be used as well. It has a nice Javas
306
290
  ## Version 8+
307
291
 
308
292
  This version removes both the emailing setup functionality as well as the error reporting functionality. Those are both in the [UcbRailsDefaults] (https://gitlab.com/ucb-bit/cad/aa/ucb_rails_defaults) gem. This gem's dependencies have been slimmed down so that only the basics to run the gem are required. This makes it easier to upgrade the including apps.
309
-
310
- Versions 8.0.x use the new standard of Turbo, importmaps, and propshaft. The 8.0.x versions do not have the latest CAS upgrades in them and are used for Rails 8 apps that are in maintenance mode.
@@ -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 {
@@ -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
@@ -104,6 +91,7 @@ module UcbRailsUser::UsersControllerConcerns
104
91
  @lps_existing_uids = UcbRailsUser.user_class.where(ldap_uid: uid_strings).pluck(:uid)
105
92
  render 'ucb_rails_user/lps/search'
106
93
  end
94
+
107
95
  end
108
96
 
109
97
  def typeahead_search
@@ -123,11 +111,6 @@ module UcbRailsUser::UsersControllerConcerns
123
111
 
124
112
  private
125
113
 
126
- def search_user_table(query)
127
- UcbRailsUser.user_class.where('lower(first_name) like lower(:q) or lower(last_name) like lower(:q) or ldap_uid like :q or employee_id like :q',
128
- q: '%' + query + '%')
129
- end
130
-
131
114
  def user_params(extra_params = [])
132
115
  params.require(:user).permit([
133
116
  :superuser_flag,
@@ -147,4 +130,5 @@ module UcbRailsUser::UsersControllerConcerns
147
130
  def find_user
148
131
  @user ||= UcbRailsUser.user_class.find(params.fetch(:id))
149
132
  end
133
+
150
134
  end
@@ -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' %>
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,106 +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
- <div style="margin-top: 10px; overflow: auto; margin-bottom: 10px; vertical-align: middle; ">
4
- <%= form_with url: "", method: :get, data: { turbo_frame: "users" }, style: "display: flex; gap: 10px; align-items: center; flex-grow: 1;" do |form| %>
5
- <%= form.hidden_field :sort, value: @sort %>
6
- <%= form.hidden_field :dir, value: @sort_dir %>
7
- <div style="float: left; padding-right: 15px">
8
- Show <%= form.select :count, options_for_select([10, 25, 50, 100], selected: params[:count]), {}, { onchange: "this.form.requestSubmit()" } %>
9
- </div>
10
- <div style="float: left;">
11
- Search <%= form.search_field :query, value: params[:query], id: "user_search_field", placeholder: "Search users...", oninput: "
12
- clearTimeout(window.searchTimer);
13
- window.searchTimer = setTimeout(() => {
14
- this.form.requestSubmit();
15
- }, 300);
16
- " %>
17
- </div>
18
- <% end %>
19
- <div style="float: right;">
20
- <%= link_to "Add User", new_admin_user_path, class: "btn btn-primary" %>
21
- </div>
22
- </div>
23
3
  </div>
24
4
 
25
- <%= turbo_frame_tag "users" do %>
26
- <div class="table-responsive ucb-rails-users-table-wrapper">
27
- <table class="table table-striped table-bordered table-hover ucb-rails-users-table">
28
- <thead>
29
- <tr>
30
- <th class="min">
31
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
32
- Superuser?
33
- <% if @sort == "superuser_flag" %>
34
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
35
- <% end %>
36
- <% end %>
37
- </th>
38
- <th class="min">
39
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
40
- Inactive?
41
- <% if @sort == "inactive_flag" %>
42
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
43
- <% end %>
44
- <% end %>
45
- </th>
46
- <th>
47
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
48
- First Name
49
- <% if @sort == "first_name" %>
50
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
51
- <% end %>
52
- <% end %>
53
- </th>
54
- <th>
55
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
56
- Last Name
57
- <% if @sort == "last_name" %>
58
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
59
- <% end %>
60
- <% end %>
61
- </th>
62
- <th>
63
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
64
- Email
65
- <% if @sort == "email" %>
66
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
67
- <% end %>
68
- <% end %>
69
- </th>
70
- <th class="dt">
71
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
72
- Last Login
73
- <% if @sort == "last_login_at" %>
74
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
75
- <% end %>
76
- <% end %>
77
- </th>
78
- <th>
79
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
80
- UID
81
- <% if @sort == "ldap_uid" %>
82
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
83
- <% end %>
84
- <% end %>
85
- </th>
86
- <th>
87
- <%= 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" }, style: "text-decoration: none; color: inherit;" do %>
88
- Employee ID
89
- <% if @sort == "employee_id" %>
90
- <%= @sort_dir == "asc" ? "▲" : "▼" %>
91
- <% end %>
92
- <% end %>
93
- </th>
94
- <th class="min unsorted">Edit</th>
95
- <th class="min unsorted">Delete</th>
96
- </tr>
97
- </thead>
98
- <tbody class="highlight">
99
- <%= render partial: "ucb_rails_user/users/user", collection: @users %>
100
- </tbody>
101
- </table>
102
- <div class="ucb-rails-user">
103
- <%= 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 %>
104
- </div>
105
- </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()" %>
106
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,9 +1,6 @@
1
- <div class="ucb-rails-users-table-header">
2
- <h1>Users</h1>
3
- <h2>Add New User</h2>
4
- </div>
1
+ <h2>Add New User</h2>
5
2
 
6
- <%= form_tag admin_user_search_path, method: :get, class: "form-inline user-search-form" do %>
3
+ <%= form_tag admin_user_search_path, method: :get, remote: true, class: "form-inline user-search-form" do %>
7
4
  <%= text_field_tag :first_name, "", placeholder: "First name", class: "form-control" %>
8
5
  <%= text_field_tag :last_name, "", placeholder: "Last name", class: "form-control" %>
9
6
  <%= text_field_tag :employee_id, "", placeholder: "Employee ID", class: "form-control" %>
@@ -11,7 +8,7 @@
11
8
  <%= link_to "Cancel", admin_users_path, class: "btn btn-default" %>
12
9
  <% end %>
13
10
 
14
- <div class="ucb-rails-user-loader" style="display: none;">
11
+ <div class="ucb-rails-user-loader">
15
12
  Loading...
16
13
  </div>
17
14
 
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.2'
2
+ VERSION = '8.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ucb_rails_user
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.2
4
+ version: 8.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Downey
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2025-09-30 00:00:00.000000000 Z
16
+ date: 2025-08-28 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: rails
@@ -146,7 +146,7 @@ dependencies:
146
146
  version: '1.8'
147
147
  - - "<"
148
148
  - !ruby/object:Gem::Version
149
- version: '3.0'
149
+ version: '4.0'
150
150
  type: :runtime
151
151
  prerelease: false
152
152
  version_requirements: !ruby/object:Gem::Requirement
@@ -156,21 +156,21 @@ dependencies:
156
156
  version: '1.8'
157
157
  - - "<"
158
158
  - !ruby/object:Gem::Version
159
- version: '3.0'
159
+ version: '4.0'
160
160
  - !ruby/object:Gem::Dependency
161
161
  name: omniauth-cas
162
162
  requirement: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - "~>"
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
- version: '1.1'
166
+ version: '3.0'
167
167
  type: :runtime
168
168
  prerelease: false
169
169
  version_requirements: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - "~>"
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: '1.1'
173
+ version: '3.0'
174
174
  - !ruby/object:Gem::Dependency
175
175
  name: ucb_ldap
176
176
  requirement: !ruby/object:Gem::Requirement
@@ -189,16 +189,16 @@ dependencies:
189
189
  name: faraday
190
190
  requirement: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - "~>"
192
+ - - ">="
193
193
  - !ruby/object:Gem::Version
194
- version: 2.12.1
194
+ version: '2.12'
195
195
  type: :runtime
196
196
  prerelease: false
197
197
  version_requirements: !ruby/object:Gem::Requirement
198
198
  requirements:
199
- - - "~>"
199
+ - - ">="
200
200
  - !ruby/object:Gem::Version
201
- version: 2.12.1
201
+ version: '2.12'
202
202
  - !ruby/object:Gem::Dependency
203
203
  name: puma
204
204
  requirement: !ruby/object:Gem::Requirement
@@ -390,15 +390,14 @@ files:
390
390
  - app/views/ucb_rails_user/lps/_modal.html.erb
391
391
  - app/views/ucb_rails_user/lps/_results.html.erb
392
392
  - app/views/ucb_rails_user/lps/search.js.erb
393
+ - app/views/ucb_rails_user/sessions/new.html.erb
393
394
  - app/views/ucb_rails_user/users/_form.html.erb
394
395
  - app/views/ucb_rails_user/users/_search_results.html.erb
395
396
  - app/views/ucb_rails_user/users/_user.html.erb
396
397
  - app/views/ucb_rails_user/users/edit.html.erb
397
398
  - app/views/ucb_rails_user/users/index.html.erb
398
399
  - app/views/ucb_rails_user/users/new.html.erb
399
- - app/views/ucb_rails_user/users/search.html.erb
400
400
  - app/views/ucb_rails_user/users/search.js.erb
401
- - config/importmap.rb
402
401
  - config/initializers/simple_form.rb
403
402
  - config/initializers/simple_form_bootstrap.rb
404
403
  - config/locales/simple_form.en.yml
@@ -1,16 +0,0 @@
1
- <div class="ucb-rails-users-table-header">
2
- <h1>Users</h1>
3
- <h2>Add New User</h2>
4
- </div>
5
-
6
- <%= form_tag admin_user_search_path, method: :get, class: "form-inline user-search-form" do %>
7
- <%= text_field_tag :first_name, params[:first_name], placeholder: "First name", class: "form-control" %>
8
- <%= text_field_tag :last_name, params[:last_name], placeholder: "Last name", class: "form-control" %>
9
- <%= text_field_tag :employee_id, params[:employee_id], placeholder: "Employee ID", class: "form-control" %>
10
- <%= submit_tag "Search", class: "btn btn-primary" %>
11
- <%= link_to "Cancel", admin_users_path, class: "btn btn-default" %>
12
- <% end %>
13
-
14
- <div class="search-results">
15
- <%= render "search_results" %>
16
- </div>
data/config/importmap.rb DELETED
@@ -1,2 +0,0 @@
1
- # Pin npm packages for the engine
2
- pin_all_from File.expand_path("../app/assets/javascripts/ucb_rails_user", __dir__), under: "ucb_rails_user"