rails_base 0.58.0 → 0.70.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/app/controllers/rails_base/admin_controller.rb +2 -2
- data/app/controllers/rails_base/errors_controller.rb +1 -1
- data/app/controllers/rails_base/mfa_auth_controller.rb +1 -1
- data/app/controllers/rails_base/secondary_authentication_controller.rb +1 -1
- data/app/controllers/rails_base/switch_user_controller.rb +1 -0
- data/app/controllers/rails_base/user_settings_controller.rb +1 -1
- data/app/controllers/rails_base_application_controller.rb +157 -0
- data/app/helpers/rails_base/user_settings_helper.rb +1 -1
- data/app/models/admin_action.rb +2 -1
- data/app/models/rails_base/application_record.rb +1 -1
- data/app/services/rails_base/admin_risky_mfa_send.rb +1 -1
- data/app/services/rails_base/authentication/mfa_set_encrypt_token.rb +1 -1
- data/app/services/rails_base/authentication/send_login_mfa_to_user.rb +1 -1
- data/app/services/rails_base/authentication/send_verification_email.rb +1 -1
- data/app/services/rails_base/authentication/single_sign_on_create.rb +1 -1
- data/app/services/rails_base/authentication/single_sign_on_send.rb +1 -1
- data/app/services/rails_base/authentication/single_sign_on_verify.rb +1 -1
- data/app/services/rails_base/encryption.rb +2 -2
- data/app/views/layouts/rails_base/application.html.erb +27 -15
- data/app/views/rails_base/devise/passwords/new.html.erb +16 -4
- data/app/views/rails_base/shared/_appearance_mode_selector.html.erb +4 -4
- data/app/views/rails_base/shared/_standardized_collapse.html.erb +62 -0
- data/db/seeds.rb +7 -4
- data/lib/rails_base/admin/action_helper.rb +7 -4
- data/lib/rails_base/configuration/active_job.rb +1 -0
- data/lib/rails_base/configuration/admin.rb +4 -3
- data/lib/rails_base/configuration/app.rb +10 -5
- data/lib/rails_base/engine.rb +17 -6
- data/lib/rails_base/switch_user_helper.rb +36 -0
- data/lib/rails_base/version.rb +1 -1
- data/lib/rails_base.rb +7 -1
- metadata +10 -9
- data/app/controllers/rails_base/application_controller.rb +0 -153
- data/config/initializers/switch_user_helper.rb +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b65060d8d2fc37e4df2c2cb83deda894be73dc4504570573580f2cf3b1c02919
|
|
4
|
+
data.tar.gz: 2bb0dc7ab74728e1cde281efa69362f21234dadaf4cd5edec1bec8f3c9a2bba0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b4b519cd757c9513509e3141bdb429bb1be7eba89c91a67f7d7c23973d4d1869870651fd7d3aae95fea5ac625bc883c58ef630744687d1bad942b3eac4a39780
|
|
7
|
+
data.tar.gz: ba271fdbbab552800f0aa31052a1bd9e69342a365bbebfa7ec02bbbcc09d45b07f6c65055b2d321dccdca2ee21f115b92e8c91746c15463bdc07ba5c8c1d9fa8
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module RailsBase
|
|
2
|
-
class AdminController <
|
|
2
|
+
class AdminController < RailsBaseApplicationController
|
|
3
3
|
before_action :authenticate_user!, except: [:sso_retrieve]
|
|
4
4
|
before_action :admin_user?, only: [:index, :config, :sso_send]
|
|
5
5
|
before_action :validate_token!, only: [:update_email, :update_phone]
|
|
6
|
-
skip_before_action :admin_reset_impersonation_session
|
|
6
|
+
skip_before_action :admin_reset_impersonation_session!, raise: false
|
|
7
7
|
|
|
8
8
|
include AdminHelper
|
|
9
9
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module RailsBase
|
|
2
|
-
class SecondaryAuthenticationController <
|
|
2
|
+
class SecondaryAuthenticationController < RailsBaseApplicationController
|
|
3
3
|
before_action :authenticate_user!, only: [:remove_phone_mfa, :confirm_phone_registration]
|
|
4
4
|
|
|
5
5
|
before_action :validate_token!, only: [:resend_email, :wait, :confirm_phone_registration]
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
class RailsBaseApplicationController < ActionController::Base
|
|
2
|
+
layout 'rails_base/application'
|
|
3
|
+
|
|
4
|
+
before_action :configure_permitted_parameters, if: :devise_controller?
|
|
5
|
+
before_action :set_time_zone
|
|
6
|
+
before_action :is_timeout_error?
|
|
7
|
+
before_action :admin_reset_impersonation_session!
|
|
8
|
+
before_action :footer_mode_case
|
|
9
|
+
|
|
10
|
+
before_action :populate_admin_actions, if: -> { RailsBase.config.admin.enable_actions? }
|
|
11
|
+
after_action :capture_admin_action
|
|
12
|
+
|
|
13
|
+
include RailsBase::ApplicationHelper
|
|
14
|
+
helper_method :mfa_fallback?, :is_safari?, :is_mobile?
|
|
15
|
+
|
|
16
|
+
include RailsBase::AppearanceHelper
|
|
17
|
+
helper_method :appearance_text_class, :footer_mode_case, :appearance_mode_drop_down, :appearance_text_class
|
|
18
|
+
|
|
19
|
+
include RailsBase::CaptureReferenceHelper
|
|
20
|
+
|
|
21
|
+
def set_time_zone
|
|
22
|
+
return unless RailsBase.config.user.tz_user_defined?
|
|
23
|
+
return if current_user.nil?
|
|
24
|
+
|
|
25
|
+
# esape this since this is not signed
|
|
26
|
+
offset = cookies[TIMEZONE_OFFSET_COOKIE].to_i
|
|
27
|
+
|
|
28
|
+
cookie_tz = ActiveSupport::TimeZone[((offset * -1) / 60.0)]
|
|
29
|
+
|
|
30
|
+
if session_tz = session[TIMEZONE_SESSION_NAME]
|
|
31
|
+
# if session exists
|
|
32
|
+
if cookie_tz && session_tz != cookie_tz.name
|
|
33
|
+
# if cookie exists and cookie_tz does not match, update db and session
|
|
34
|
+
current_user.update_tz(tz_name: cookie_tz.name)
|
|
35
|
+
session[TIMEZONE_SESSION_NAME] = cookie_tz.name
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
# if session timezone does not exist, attempt to push to DB and set to session
|
|
39
|
+
current_user.update_tz(tz_name: cookie_tz.name)
|
|
40
|
+
session[TIMEZONE_SESSION_NAME] = cookie_tz.name
|
|
41
|
+
end
|
|
42
|
+
Thread.current[TIMEZONE_THREAD_NAME] = session[TIMEZONE_SESSION_NAME]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def is_timeout_error?
|
|
46
|
+
return if current_user || !params.keys.include?('timeout')
|
|
47
|
+
|
|
48
|
+
flash[:notice] = nil
|
|
49
|
+
flash[:alert] = 'Your session expired. Please sign in again to continue.'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def admin_impersonation_session?
|
|
53
|
+
return false if current_user.nil?
|
|
54
|
+
return false unless encrypted_val = session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].presence
|
|
55
|
+
|
|
56
|
+
token = admin_get_token(encrypted_val: encrypted_val)
|
|
57
|
+
if token.failure?
|
|
58
|
+
logger.warn "Failed to parse encrypted token. Either expired or was not present"
|
|
59
|
+
flash[:alert] = 'Failed to retrieve Session token. Retry action'
|
|
60
|
+
redirect_to RailsBase.url_routes.admin_base_path
|
|
61
|
+
return false
|
|
62
|
+
else
|
|
63
|
+
logger.info "Found original_admin_user_id"
|
|
64
|
+
@original_admin_user_id = token.user_id
|
|
65
|
+
end
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def admin_reset_impersonation_session!
|
|
70
|
+
return unless admin_impersonation_session?
|
|
71
|
+
|
|
72
|
+
# at this point we know there is an impersonation
|
|
73
|
+
admin_user = User.find @original_admin_user_id
|
|
74
|
+
admin_set_token_on_session(admin_user: admin_user, other_user: current_user)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def admin_user?
|
|
78
|
+
return if RailsBase.config.admin.view_admin_page?(current_user)
|
|
79
|
+
|
|
80
|
+
session.clear
|
|
81
|
+
sign_out(current_user)
|
|
82
|
+
|
|
83
|
+
flash[:alert] = 'Unauthorized action. You have been signed out'
|
|
84
|
+
redirect_to RailsBase.url_routes.unauthenticated_root_path
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def populate_admin_actions
|
|
88
|
+
return if session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].present?
|
|
89
|
+
return if current_user.nil?
|
|
90
|
+
return unless request.fullpath == RailsBase.url_routes.authenticated_root_path
|
|
91
|
+
|
|
92
|
+
@__admin_actions_array = AdminAction.get_cache_items(user: current_user, alltime: true)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def capture_admin_action
|
|
96
|
+
# ToDo: Turn this into a service
|
|
97
|
+
# ToDo: All admin actions come there here: Allow this to be confirugable on or off
|
|
98
|
+
_controller = ActiveSupport::Inflector.camelize("#{params[:controller]}_controller")
|
|
99
|
+
admin_user =
|
|
100
|
+
if _controller == RailsBase::AdminController.to_s
|
|
101
|
+
current_user
|
|
102
|
+
else
|
|
103
|
+
@original_admin_user_id ? User.find(@original_admin_user_id) : nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Means we are not in the admin controller or we are not impersonating
|
|
107
|
+
return if admin_user.nil? || @_admin_action_struct == false
|
|
108
|
+
|
|
109
|
+
# Admin action for all routes
|
|
110
|
+
(RailsBase::Admin::ActionHelper.actions.dig(RailsBase::Admin::ActionHelper::ACTIONS_KEY) || []).each do |helper|
|
|
111
|
+
Rails.logger.warn("Admin Action for every action")
|
|
112
|
+
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Admin action for all controller routes
|
|
116
|
+
object = RailsBase::Admin::ActionHelper.actions.dig(_controller, RailsBase::Admin::ActionHelper::CONTROLLER_ACTIONS_KEY) || []
|
|
117
|
+
object.each do |helper|
|
|
118
|
+
Rails.logger.warn("Admin Action for #{_controller}")
|
|
119
|
+
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Admin action for all controller action specific routes
|
|
123
|
+
(RailsBase::Admin::ActionHelper.actions.dig(_controller, params[:action].to_s) || []).each do |helper|
|
|
124
|
+
Rails.logger.warn("Admin Action for #{_controller}##{params[:action]}")
|
|
125
|
+
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
protected
|
|
130
|
+
|
|
131
|
+
def admin_get_token(encrypted_val:)
|
|
132
|
+
params = {
|
|
133
|
+
mfa_randomized_token: encrypted_val,
|
|
134
|
+
purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
|
|
135
|
+
}
|
|
136
|
+
RailsBase::Authentication::SessionTokenVerifier.call(params)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def admin_set_token_on_session(admin_user:, other_user:)
|
|
140
|
+
if admin_user.id != other_user.id #dont do this if you are yourself
|
|
141
|
+
logger.warn { "Admin user [#{admin_user.id}] is impersonating user #{other_user.id}" }
|
|
142
|
+
params = {
|
|
143
|
+
user: admin_user,
|
|
144
|
+
purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
|
|
145
|
+
expires_at: RailsBase::Authentication::Constants::ADMIN_MAX_IDLE_TIME.from_now
|
|
146
|
+
}
|
|
147
|
+
encrpytion = RailsBase::Authentication::MfaSetEncryptToken.call(params)
|
|
148
|
+
session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON] = encrpytion.encrypted_val
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def configure_permitted_parameters
|
|
153
|
+
added_attrs = [:phone_number, :email, :password, :password_confirmation, :remember_me]
|
|
154
|
+
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
|
|
155
|
+
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
|
|
156
|
+
end
|
|
157
|
+
end
|
data/app/models/admin_action.rb
CHANGED
|
@@ -20,6 +20,7 @@ class AdminAction < RailsBase::ApplicationRecord
|
|
|
20
20
|
|
|
21
21
|
class << self
|
|
22
22
|
include ActionView::Helpers::DateHelper
|
|
23
|
+
|
|
23
24
|
def action(admin_user:, action:, user: nil, original_attribute: nil, new_attribute: nil, long_action: nil)
|
|
24
25
|
params = { admin_user_id: admin_user.id, action: action }
|
|
25
26
|
params[:user_id] = user.id if user
|
|
@@ -27,7 +28,7 @@ class AdminAction < RailsBase::ApplicationRecord
|
|
|
27
28
|
params[:change_to] = new_attribute.to_s unless new_attribute.nil?
|
|
28
29
|
params[:long_action] = long_action unless long_action.nil?
|
|
29
30
|
begin
|
|
30
|
-
instance = AdminAction.create!(params)
|
|
31
|
+
instance = AdminAction.create!(**params)
|
|
31
32
|
ship_to_cache!(instance: instance, user: user, created_at: Time.zone.now) if user
|
|
32
33
|
instance
|
|
33
34
|
rescue StandardError => e
|
|
@@ -8,7 +8,7 @@ module RailsBase
|
|
|
8
8
|
|
|
9
9
|
# This is actually pretty cool. If you set the thread corectly, you can
|
|
10
10
|
define_method("#{column.name}") do
|
|
11
|
-
thread_tz = Thread.current[
|
|
11
|
+
thread_tz = Thread.current[RailsBaseApplicationController::TIMEZONE_THREAD_NAME]
|
|
12
12
|
return super() if thread_tz.nil?
|
|
13
13
|
time = self[column.name].in_time_zone(thread_tz) rescue self[column.name]
|
|
14
14
|
|
|
@@ -32,7 +32,7 @@ module RailsBase::Authentication
|
|
|
32
32
|
token_type: token_type,
|
|
33
33
|
url_redirect: url_redirect
|
|
34
34
|
}
|
|
35
|
-
datum = SingleSignOnCreate.call(params)
|
|
35
|
+
datum = SingleSignOnCreate.call(**params)
|
|
36
36
|
context.fail!(message: 'Failed to create SSO token. Try again') if datum.failure?
|
|
37
37
|
|
|
38
38
|
url = sso_url(data: datum.data.data)
|
|
@@ -26,7 +26,7 @@ class RailsBase::Encryption
|
|
|
26
26
|
raise "expires_at && expires_in are both nil" if expires_in.nil? && expires_at.nil?
|
|
27
27
|
|
|
28
28
|
log(level: :info, msg: "Encoding [#{value}] with params #{params}")
|
|
29
|
-
token = verifier.generate(value, params)
|
|
29
|
+
token = verifier.generate(value, **params)
|
|
30
30
|
token = CGI.escape(token) if url_safe
|
|
31
31
|
token
|
|
32
32
|
end
|
|
@@ -40,7 +40,7 @@ class RailsBase::Encryption
|
|
|
40
40
|
# TODO: matt-taylor
|
|
41
41
|
# Check if the message is valid and untampered with
|
|
42
42
|
# https://api.rubyonrails.org/classes/ActiveSupport/MessageVerifier.html#method-i-valid_message-3F
|
|
43
|
-
decoded = verifier.verified(value, params)
|
|
43
|
+
decoded = verifier.verified(value, **params)
|
|
44
44
|
if decoded.nil?
|
|
45
45
|
log(level: :warn, msg: "Failed to decode value: value: #{value}, purpose: #{purpose}")
|
|
46
46
|
end
|
|
@@ -50,20 +50,16 @@
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
<%
|
|
53
|
+
<% RailsBaseApplicationController::VIEWPORT_SIZES.each do |name, max_width| %>
|
|
54
54
|
function viewport_at_least_<%= name %>(){
|
|
55
55
|
return getViewportWidth() >= <%= max_width || 99_999 %>
|
|
56
56
|
|
|
57
57
|
}
|
|
58
|
-
<% if name == RailsBase::ApplicationController::VIEWPORT_MOBILE_MAX %>
|
|
59
|
-
<% puts "Rendering #{name} for viewport_probable_mobile" %>
|
|
60
|
-
|
|
61
|
-
<% end %>
|
|
62
58
|
<% end %>
|
|
63
59
|
|
|
64
60
|
<%
|
|
65
|
-
k =
|
|
66
|
-
size =
|
|
61
|
+
k = RailsBaseApplicationController::VIEWPORT_MOBILE_MAX
|
|
62
|
+
size = RailsBaseApplicationController::VIEWPORT_SIZES[k] || 99_999
|
|
67
63
|
%>
|
|
68
64
|
function viewport_probable_mobile(){
|
|
69
65
|
return getViewportWidth() <= <%= size %>
|
|
@@ -178,15 +174,31 @@
|
|
|
178
174
|
# dont load these when error page happens. The full stack of librarires are not
|
|
179
175
|
# rendered and jquery/bootstrap are missing
|
|
180
176
|
%>
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
<% when :bottom %>
|
|
185
|
-
if($('#_body_base_container').height() <= window.innerHeight){
|
|
177
|
+
function _rails_base_reload_base_footer(){
|
|
178
|
+
<% case footer_mode_case %>
|
|
179
|
+
<% when :sticky %>
|
|
186
180
|
$('#base-footer').addClass('fixed-bottom')
|
|
181
|
+
<% when :bottom %>
|
|
182
|
+
if($('#_body_base_container').height() <= window.innerHeight){
|
|
183
|
+
$('#base-footer').addClass('fixed-bottom')
|
|
184
|
+
} else {
|
|
185
|
+
$('#base-footer').removeClass('fixed-bottom')
|
|
186
|
+
}
|
|
187
|
+
<% else %>
|
|
188
|
+
<% end %>
|
|
187
189
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
|
|
191
|
+
function _rails_base_toggle_base_footer(status){
|
|
192
|
+
if(status=='show') {
|
|
193
|
+
$('#base-footer').show()
|
|
194
|
+
} else if(status=='hide') {
|
|
195
|
+
$('#base-footer').hide()
|
|
196
|
+
} else {
|
|
197
|
+
$('#base-footer').toggle()
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
_rails_base_reload_base_footer();
|
|
190
202
|
|
|
191
203
|
<% unless defined?(@error_page) %>
|
|
192
204
|
$(document).ready(function(){
|
|
@@ -196,7 +208,7 @@
|
|
|
196
208
|
$('.tableFixHead').stickyTableHeaders();
|
|
197
209
|
|
|
198
210
|
// Attempt to set timezone on every request
|
|
199
|
-
set_cookie('<%=
|
|
211
|
+
set_cookie('<%= RailsBaseApplicationController::TIMEZONE_OFFSET_COOKIE %>', new Date().getTimezoneOffset())
|
|
200
212
|
});
|
|
201
213
|
<% end %>
|
|
202
214
|
<% if Rails.env == 'production' %>
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
<h2 class='text-center'>Forgot your password?</h2>
|
|
2
2
|
<%= render "devise/shared/error_messages", resource: resource %>
|
|
3
3
|
|
|
4
|
+
<% submit_id = "submit_id_#{Time.now.to_i}" %>
|
|
4
5
|
|
|
5
|
-
<%= form_for(:user, as: :user, url: RailsBase.url_routes.user_password_path, html: { method: :post }) do |f| %>
|
|
6
|
+
<%= form_for(:user, as: :user, url: RailsBase.url_routes.user_password_path, html: { method: :post, class: 'forgot_password' }) do |f| %>
|
|
6
7
|
|
|
7
8
|
<div class="field form-group row">
|
|
8
9
|
<div class="col-md-10 offset-md-1">
|
|
9
|
-
<%= f.label :email, class: 'text-center' %><br
|
|
10
|
+
<%= f.label :email, class: 'text-center' %><br>
|
|
10
11
|
<%= f.email_field :email, autofocus: true, autocomplete: "email", placeholder: :email, class: 'form-control'%>
|
|
11
|
-
|
|
12
|
+
<div class="invalid-feedback">
|
|
13
|
+
Password Confirmation does not match Password
|
|
14
|
+
</div>
|
|
12
15
|
</div>
|
|
13
16
|
</div>
|
|
14
17
|
|
|
@@ -16,7 +19,7 @@
|
|
|
16
19
|
<div class="col-md-10 offset-md-1 text-center">
|
|
17
20
|
<div class="row">
|
|
18
21
|
<div class="col-md-9">
|
|
19
|
-
<%= f.submit "Send me reset password instructions", class: "btn btn_success btn-block" %>
|
|
22
|
+
<%= f.submit "Send me reset password instructions", class: "btn btn_success btn-block #{submit_id}" %>
|
|
20
23
|
</div>
|
|
21
24
|
<div class="col-md-3">
|
|
22
25
|
<a class="btn btn_primary btn-block" href="<%= RailsBase.url_routes.new_user_session_path %>" role="button">Sign in</a>
|
|
@@ -25,3 +28,12 @@
|
|
|
25
28
|
</div>
|
|
26
29
|
</div>
|
|
27
30
|
<% end %>
|
|
31
|
+
|
|
32
|
+
<%
|
|
33
|
+
values = [
|
|
34
|
+
{ name: '#user_email', criteria: { required: true, pattern: :email }}
|
|
35
|
+
]
|
|
36
|
+
function_name = 'forgot_password'
|
|
37
|
+
%>
|
|
38
|
+
|
|
39
|
+
<%= render partial: 'rails_base/shared/custom_form_validation_javascript', locals: { function_name: function_name, values: values } %>
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
<% light = RailsBase::Configuration::Appearance::LIGHT_MODE %>
|
|
54
54
|
var type_mapping = JSON.parse('<%= raw RailsBase::Configuration::Appearance::APPEARANCE_TYPES.to_json %>')
|
|
55
55
|
|
|
56
|
-
var cookie_name = `<%=
|
|
57
|
-
var cookie_actual_name = `<%=
|
|
56
|
+
var cookie_name = `<%= RailsBaseApplicationController::APPEARANCE_MODE_COOKIE %>`;
|
|
57
|
+
var cookie_actual_name = `<%= RailsBaseApplicationController::APPEARANCE_MODE_ACTUAL_COOKIE %>`;
|
|
58
58
|
var dark_mode_changes = [
|
|
59
59
|
{
|
|
60
60
|
'descriptor': 'thead',
|
|
@@ -151,11 +151,11 @@
|
|
|
151
151
|
})
|
|
152
152
|
// This function MUST be called outside of document ready
|
|
153
153
|
// to ensure dark mode does not activate after document is loaded
|
|
154
|
-
set_and_toggle_mode( `<%= cookies[
|
|
154
|
+
set_and_toggle_mode( `<%= cookies[RailsBaseApplicationController::APPEARANCE_MODE_COOKIE] || RailsBase.appearance.default_mode %>`)
|
|
155
155
|
$('#appearance_mode_selector').appendTo('body');
|
|
156
156
|
$(document).ready(function(){
|
|
157
157
|
// differentiation of load order means we need to call this twice
|
|
158
|
-
set_and_toggle_mode( `<%= cookies[
|
|
158
|
+
set_and_toggle_mode( `<%= cookies[RailsBaseApplicationController::APPEARANCE_MODE_COOKIE] || RailsBase.appearance.default_mode %>`)
|
|
159
159
|
$(document).ajaxComplete(function () {
|
|
160
160
|
set_and_toggle_mode()
|
|
161
161
|
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
<%
|
|
3
|
+
id = options.fetch(:id)
|
|
4
|
+
title = options.fetch(:title_id)
|
|
5
|
+
body = options.fetch(:body_id)
|
|
6
|
+
use_fa_icon = options[:fa_icon] != false
|
|
7
|
+
if use_fa_icon
|
|
8
|
+
fa_icon_open = options.dig(:fa_icon, :open) || 'fa-caret-right'
|
|
9
|
+
fa_icon_closed = options.dig(:fa_icon, :closed) || 'fa-caret-down'
|
|
10
|
+
fa_icon_only = options.dig(:fa_icon, :collapse_only) || false
|
|
11
|
+
fa_icon_span_class = "fa-icon-span-class-#{rand(100..100_000)}_id-#{id}"
|
|
12
|
+
fa_icon_span_id = "id-#{fa_icon_span_class}"
|
|
13
|
+
end
|
|
14
|
+
start_open = !(options[:default_closed] || false)
|
|
15
|
+
close_display = start_open ? 'inline' : 'none'
|
|
16
|
+
open_display = !start_open ? 'inline' : 'none'
|
|
17
|
+
id_transposed = "id_transposed_#{rand(100_000..999_999)}"
|
|
18
|
+
%>
|
|
19
|
+
|
|
20
|
+
<% if use_fa_icon %>
|
|
21
|
+
<span id="<%= fa_icon_span_id %>" class="float-md-left fa-icon-span <%= fa_icon_span_class %> ">
|
|
22
|
+
<i class="fa <%= fa_icon_open %> open" aria-hidden="true" style="display:<%= open_display %>"></i>
|
|
23
|
+
<i class="fa <%= fa_icon_closed %> closed" aria-hidden="true" style="display:<%= close_display %>"></i>
|
|
24
|
+
</span>
|
|
25
|
+
<% end %>
|
|
26
|
+
|
|
27
|
+
<script type="text/javascript">
|
|
28
|
+
$(`#<%= body %>`).addClass('collapse')
|
|
29
|
+
<% if start_open %>
|
|
30
|
+
$(`#<%= body %>`).addClass('show')
|
|
31
|
+
<% end %>
|
|
32
|
+
<% if use_fa_icon %>
|
|
33
|
+
// Initialize fa <%= id %>
|
|
34
|
+
$(`#<%= fa_icon_span_id %>`).prependTo(`#<%= title %>`);
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<% if use_fa_icon && fa_icon_only %>
|
|
38
|
+
var <%= id_transposed %> = `#<%= fa_icon_span_id %>`
|
|
39
|
+
<% else %>
|
|
40
|
+
var <%= id_transposed %> = `#<%= title %>`
|
|
41
|
+
<% end %>
|
|
42
|
+
|
|
43
|
+
$(<%= id_transposed %>).click(function(event){
|
|
44
|
+
_rails_base_toggle_base_footer('hide')
|
|
45
|
+
$(`#<%= body %>`).collapse('toggle')
|
|
46
|
+
<% if use_fa_icon %>
|
|
47
|
+
$(`#<%= fa_icon_span_id %> .open`).toggle()
|
|
48
|
+
$(`#<%= fa_icon_span_id %> .closed`).toggle()
|
|
49
|
+
<% end %>
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
$(`#<%= body %>`).on('shown.bs.collapse', function () {
|
|
53
|
+
_rails_base_reload_base_footer();
|
|
54
|
+
_rails_base_toggle_base_footer('show')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
$(`#<%= body %>`).on('hidden.bs.collapse', function () {
|
|
58
|
+
_rails_base_reload_base_footer();
|
|
59
|
+
_rails_base_toggle_base_footer('show')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
</script>
|
data/db/seeds.rb
CHANGED
|
@@ -3,12 +3,14 @@ params = {
|
|
|
3
3
|
email: "mattius.taylor@gmail.com",
|
|
4
4
|
first_name: 'Some',
|
|
5
5
|
last_name: 'Guy',
|
|
6
|
-
phone_number: '
|
|
6
|
+
phone_number: ENV.fetch("PHONE_NUMBER", '6509410795'),
|
|
7
7
|
password: "password1",
|
|
8
|
-
password_confirmation: "password1"
|
|
8
|
+
password_confirmation: "password1",
|
|
9
|
+
email_validated: true,
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
User.create!(params)
|
|
12
|
+
user = User.create!(params)
|
|
13
|
+
user.admin_owner!
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
params = {
|
|
@@ -17,7 +19,8 @@ params = {
|
|
|
17
19
|
last_name: 'Guy2',
|
|
18
20
|
phone_number: '6508675309',
|
|
19
21
|
password: "password2",
|
|
20
|
-
password_confirmation: "password2"
|
|
22
|
+
password_confirmation: "password2",
|
|
23
|
+
email_validated: true,
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
User.create!(params)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
require 'switch_user'
|
|
2
|
+
|
|
1
3
|
module RailsBase::Admin
|
|
2
4
|
class ActionHelper
|
|
3
5
|
ACTIONS_KEY = "___all_actions_#{(rand*10**10).to_i}___"
|
|
4
6
|
CONTROLLER_ACTIONS_KEY = "___all_controller_actions__#{(rand*10**10).to_i}___"
|
|
5
|
-
DEFAULT_ALLOWED_KLASSES = [ApplicationController,
|
|
7
|
+
DEFAULT_ALLOWED_KLASSES = [ApplicationController, RailsBaseApplicationController, ::SwitchUserController]
|
|
6
8
|
class << self
|
|
7
9
|
def allowed_inherited_klasses
|
|
8
10
|
DEFAULT_ALLOWED_KLASSES + (@allowed_klasses || [])
|
|
@@ -60,7 +62,7 @@ module RailsBase::Admin
|
|
|
60
62
|
class InvalidTitleError < StandardError; end;
|
|
61
63
|
|
|
62
64
|
attr_accessor :controller, :action, :proc, :title, :default
|
|
63
|
-
# controller is the controller class inherited by
|
|
65
|
+
# controller is the controller class inherited by RailsBaseApplicationController
|
|
64
66
|
# action is the method name on the controller
|
|
65
67
|
# title should be the AdminAction.action
|
|
66
68
|
# if proc available,
|
|
@@ -88,10 +90,11 @@ module RailsBase::Admin
|
|
|
88
90
|
action_params = proc.call(req, params, admin_user, user, title, struct)
|
|
89
91
|
return if action_params.nil?
|
|
90
92
|
|
|
91
|
-
AdminAction.action(action_params)
|
|
93
|
+
AdminAction.action(**action_params)
|
|
92
94
|
else
|
|
93
95
|
default_call(request: request, admin_user: admin_user, user: user, struct: struct)
|
|
94
96
|
end
|
|
97
|
+
|
|
95
98
|
rescue StandardError => e
|
|
96
99
|
Rails.logger.error(e.message)
|
|
97
100
|
Rails.logger.error(e.backtrace)
|
|
@@ -108,7 +111,7 @@ module RailsBase::Admin
|
|
|
108
111
|
change_from: struct&.original_attribute,
|
|
109
112
|
change_to: struct&.new_attribute,
|
|
110
113
|
}
|
|
111
|
-
AdminAction.action(action_params)
|
|
114
|
+
AdminAction.action(**action_params)
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
def valid_controller!
|
|
@@ -5,6 +5,7 @@ module RailsBase
|
|
|
5
5
|
if val.is_a?(Symbol)
|
|
6
6
|
begin
|
|
7
7
|
::ActiveJob::QueueAdapters.lookup(val)
|
|
8
|
+
RailsBase::ApplicationJob.queue_adapter = val.to_sym
|
|
8
9
|
Rails.configuration.active_job.queue_adapter = val.to_sym
|
|
9
10
|
rescue StandardError => e
|
|
10
11
|
raise ArgumentError, "config.app.active_job_adapter=#{val} is not a defined active job"
|
|
@@ -192,12 +192,12 @@ module RailsBase
|
|
|
192
192
|
},
|
|
193
193
|
admin_impersonate_redirect:{
|
|
194
194
|
type: :proc,
|
|
195
|
-
default: ->(
|
|
196
|
-
description: 'Redirection to impersonation -- Landing page when having an identity
|
|
195
|
+
default: ->(*) { RailsBase.url_routes.authenticated_root_path },
|
|
196
|
+
description: 'Redirection to impersonation -- Landing page when having an identity crisis',
|
|
197
197
|
},
|
|
198
198
|
admin_impersonate_return:{
|
|
199
199
|
type: :proc,
|
|
200
|
-
default: ->(
|
|
200
|
+
default: ->(*) { RailsBase.url_routes.admin_base_path },
|
|
201
201
|
description: 'Redirection from impersonation -- Page to return from when you have found yourself',
|
|
202
202
|
}
|
|
203
203
|
}
|
|
@@ -230,6 +230,7 @@ module RailsBase
|
|
|
230
230
|
# User.admin_owner
|
|
231
231
|
# User.admin_owners
|
|
232
232
|
# This is 100% dependent upon keeping `admin_types` in order of precedence
|
|
233
|
+
require RailsBase::Engine.root.join('app','models', 'user.rb')
|
|
233
234
|
admin_types.each do |type|
|
|
234
235
|
::User._def_admin_convenience_method!(admin_method: type)
|
|
235
236
|
end
|
|
@@ -4,6 +4,11 @@ module RailsBase
|
|
|
4
4
|
module Configuration
|
|
5
5
|
class App < Base
|
|
6
6
|
DEFAULT_VALUES = {
|
|
7
|
+
app_name: {
|
|
8
|
+
type: :string_proc,
|
|
9
|
+
default: ->(*) { RailsBase.default_app_name },
|
|
10
|
+
description: 'Name of the application when authenticated user is present. Name in the tab of the browser. Allows for dynamic tab names'
|
|
11
|
+
},
|
|
7
12
|
base_url: {
|
|
8
13
|
type: :string,
|
|
9
14
|
default: ENV.fetch('BASE_URL', 'http://localhost'),
|
|
@@ -16,27 +21,27 @@ module RailsBase
|
|
|
16
21
|
},
|
|
17
22
|
web_name_logged_in: {
|
|
18
23
|
type: :string_proc,
|
|
19
|
-
default: ->(
|
|
24
|
+
default: ->(*) { RailsBase.config.app.app_name },
|
|
20
25
|
description: 'Name of the application when authenticated user is present. Name in the tab of the browser. Allows for dynamic tab names'
|
|
21
26
|
},
|
|
22
27
|
web_name_logged_out: {
|
|
23
28
|
type: :string_proc,
|
|
24
|
-
default: ->(*) { RailsBase.app_name },
|
|
29
|
+
default: ->(*) { RailsBase.config.app.app_name },
|
|
25
30
|
description: 'Name of the application when no authenticated user. Name in the tab of the browser. Allows for dynamic tab names'
|
|
26
31
|
},
|
|
27
32
|
web_title_logged_in: {
|
|
28
33
|
type: :string_proc,
|
|
29
|
-
default: ->(user) { RailsBase.app_name },
|
|
34
|
+
default: ->(user) { RailsBase.config.app.app_name },
|
|
30
35
|
description: 'Title in nav for the web when logged in. String or proc accepted. When proc, current user will be passed in.'
|
|
31
36
|
},
|
|
32
37
|
web_title_logged_out: {
|
|
33
38
|
type: :string_proc,
|
|
34
|
-
default: ->(*) { RailsBase.app_name },
|
|
39
|
+
default: ->(*) { RailsBase.config.app.app_name },
|
|
35
40
|
description: 'Title in nav for the web when logged in. String or proc accepted. When proc, current user will be passed in.'
|
|
36
41
|
},
|
|
37
42
|
communication_name: {
|
|
38
43
|
type: :string_proc,
|
|
39
|
-
default: ->(*) { RailsBase.app_name },
|
|
44
|
+
default: ->(*) { RailsBase.config.app.app_name },
|
|
40
45
|
description: 'Name used when communicating with users.'
|
|
41
46
|
},
|
|
42
47
|
favicon_path: {
|
data/lib/rails_base/engine.rb
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
module RailsBase
|
|
2
2
|
class Engine < ::Rails::Engine
|
|
3
3
|
isolate_namespace RailsBase
|
|
4
|
+
|
|
5
|
+
# config.autoload_paths << File.expand_path("app", __dir__)
|
|
6
|
+
|
|
4
7
|
ActiveSupport::Reloader.to_prepare do
|
|
5
8
|
if RailsBase.___execute_initializer___?
|
|
6
9
|
RailsBase.config.admin.convenience_methods
|
|
7
10
|
|
|
11
|
+
Dir[RailsBase::Engine.root.join('app','models','**', '*.rb')].each {|f| require f }
|
|
8
12
|
RailsBase::ApplicationRecord.descendants.each do |model|
|
|
9
13
|
model._magically_defined_time_objects
|
|
10
14
|
end
|
|
11
15
|
end
|
|
12
16
|
end
|
|
13
17
|
|
|
14
|
-
initializer '
|
|
18
|
+
initializer 'rails_base.config.intantiate' do |_app|
|
|
15
19
|
RailsBase.config if RailsBase.___execute_initializer___?
|
|
16
20
|
end
|
|
17
21
|
|
|
18
|
-
initializer '
|
|
22
|
+
initializer 'rails_base.config.remove_write_acess', after: 'after_initialize' do |app|
|
|
19
23
|
RailsBase::Configuration::Base._unset_allow_write! if RailsBase.___execute_initializer___?
|
|
20
24
|
end
|
|
21
25
|
|
|
22
|
-
initializer '
|
|
26
|
+
initializer 'rails_base.magic_convenience_methods.model', after: 'active_record.initialize_database' do |app|
|
|
23
27
|
if RailsBase.___execute_initializer___?
|
|
24
28
|
# need to eager load Models
|
|
25
29
|
Rails.application.eager_load!
|
|
@@ -28,18 +32,17 @@ module RailsBase
|
|
|
28
32
|
ActiveRecord::Base.retrieve_connection
|
|
29
33
|
|
|
30
34
|
#explicitly load engine routes
|
|
31
|
-
Dir.entries(RailsBase::Engine.root.join('app','models')).select{|s| s.ends_with?('.rb')}.each {|f| require f}
|
|
32
35
|
RailsBase::ApplicationRecord.descendants.each do |model|
|
|
33
36
|
model._magically_defined_time_objects
|
|
34
37
|
end
|
|
35
38
|
end
|
|
36
39
|
end
|
|
37
40
|
|
|
38
|
-
initializer '
|
|
41
|
+
initializer 'rails_base.switch_user.remove_routes', after: 'add_routing_paths' do |app|
|
|
39
42
|
app.routes_reloader.paths.delete_if{ |path| path.include?('switch_user') }
|
|
40
43
|
end
|
|
41
44
|
|
|
42
|
-
initializer '
|
|
45
|
+
initializer 'rails_base.append_engine_migrations' do |app|
|
|
43
46
|
unless app.root.to_s.match root.to_s
|
|
44
47
|
config.paths["db/migrate"].expanded.each do |expanded_path|
|
|
45
48
|
app.config.paths["db/migrate"] << expanded_path
|
|
@@ -47,6 +50,14 @@ module RailsBase
|
|
|
47
50
|
end
|
|
48
51
|
end
|
|
49
52
|
|
|
53
|
+
initializer 'rails_base.switch_user.view' do
|
|
54
|
+
config.to_prepare do
|
|
55
|
+
ActiveSupport.on_load(:action_view) do
|
|
56
|
+
require RailsBase::Engine.root.join('lib', 'rails_base', 'switch_user_helper.rb')
|
|
50
57
|
|
|
58
|
+
include RailsBase::SwitchUserHelper
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
51
62
|
end
|
|
52
63
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'switch_user'
|
|
2
|
+
|
|
3
|
+
module RailsBase
|
|
4
|
+
module SwitchUserHelper
|
|
5
|
+
def switch_user_custom(options = {})
|
|
6
|
+
return unless available?
|
|
7
|
+
|
|
8
|
+
selected_user = nil
|
|
9
|
+
|
|
10
|
+
grouped_options_container =
|
|
11
|
+
{}.tap do |h|
|
|
12
|
+
SwitchUser.all_users.each do |record|
|
|
13
|
+
scope = record.is_a?(SwitchUser::GuestRecord) ? :Guest : record.scope.to_s.capitalize
|
|
14
|
+
h[scope] ||= []
|
|
15
|
+
h[scope] << [record.label, record.scope_id]
|
|
16
|
+
|
|
17
|
+
next unless selected_user.nil?
|
|
18
|
+
next if record.is_a?(SwitchUser::GuestRecord)
|
|
19
|
+
|
|
20
|
+
selected_user = record.scope_id if provider.current_user?(record.user, record.scope)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
option_tags = grouped_options_for_select(grouped_options_container.to_a, selected_user)
|
|
25
|
+
|
|
26
|
+
render partial: 'rails_base/switch_user/widget',
|
|
27
|
+
locals: { option_tags: option_tags, classes: options[:class], styles: options[:style] }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def available?
|
|
33
|
+
SwitchUser.guard_class.new(controller, provider).view_available?
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/rails_base/version.rb
CHANGED
data/lib/rails_base.rb
CHANGED
|
@@ -18,8 +18,10 @@ require 'rails_base/config'
|
|
|
18
18
|
|
|
19
19
|
module RailsBase
|
|
20
20
|
|
|
21
|
-
# Rails 6 does not play nice with this function -- Find a different work around
|
|
22
21
|
def self.___execute_initializer___?
|
|
22
|
+
# Fixes rails 6 changes to ARGV's -- dont reun initializers during rake tasks
|
|
23
|
+
return false if Rake.application.top_level_tasks.any? { |task| task.include?(":") } rescue nil
|
|
24
|
+
|
|
23
25
|
# Only execute when not doing DB actions
|
|
24
26
|
boolean = defined?(ARGV) ? true : false # for when no ARGVs are provided, we know its a railsc or rails s explicit
|
|
25
27
|
boolean = false if boolean && ARGV[0]&.include?('db') # when its the DB rake tasks
|
|
@@ -35,6 +37,10 @@ module RailsBase
|
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def self.app_name
|
|
40
|
+
config.app.app_name
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.default_app_name
|
|
38
44
|
if ::Rails::VERSION::MAJOR >= 6
|
|
39
45
|
::Rails.application.class.module_parent_name
|
|
40
46
|
else
|
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_base
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.70.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matt Taylor
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-03-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: mysql2
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -420,7 +420,6 @@ files:
|
|
|
420
420
|
- app/assets/stylesheets/rails_base/secondary_authentication.scss
|
|
421
421
|
- app/assets/stylesheets/rails_base/user_settings.scss
|
|
422
422
|
- app/controllers/rails_base/admin_controller.rb
|
|
423
|
-
- app/controllers/rails_base/application_controller.rb
|
|
424
423
|
- app/controllers/rails_base/errors_controller.rb
|
|
425
424
|
- app/controllers/rails_base/mfa_auth_controller.rb
|
|
426
425
|
- app/controllers/rails_base/secondary_authentication_controller.rb
|
|
@@ -429,6 +428,7 @@ files:
|
|
|
429
428
|
- app/controllers/rails_base/users/passwords_controller.rb
|
|
430
429
|
- app/controllers/rails_base/users/registrations_controller.rb
|
|
431
430
|
- app/controllers/rails_base/users/sessions_controller.rb
|
|
431
|
+
- app/controllers/rails_base_application_controller.rb
|
|
432
432
|
- app/helpers/rails_base/admin_helper.rb
|
|
433
433
|
- app/helpers/rails_base/appearance_helper.rb
|
|
434
434
|
- app/helpers/rails_base/application_helper.rb
|
|
@@ -531,6 +531,7 @@ files:
|
|
|
531
531
|
- app/views/rails_base/shared/_reset_password_form.html.erb
|
|
532
532
|
- app/views/rails_base/shared/_session_create_form.html.erb
|
|
533
533
|
- app/views/rails_base/shared/_session_timeout_modal.html.erb
|
|
534
|
+
- app/views/rails_base/shared/_standardized_collapse.html.erb
|
|
534
535
|
- app/views/rails_base/switch_user/_widget.html.erb
|
|
535
536
|
- app/views/rails_base/user_settings/_confirm_destroy_user.html.erb
|
|
536
537
|
- app/views/rails_base/user_settings/_destroy_user.html.erb
|
|
@@ -545,7 +546,6 @@ files:
|
|
|
545
546
|
- config/initializers/devise.rb
|
|
546
547
|
- config/initializers/encryption.rb
|
|
547
548
|
- config/initializers/switch_user.rb
|
|
548
|
-
- config/initializers/switch_user_helper.rb
|
|
549
549
|
- config/locales/devise.en.yml
|
|
550
550
|
- config/locales/en.yml
|
|
551
551
|
- config/routes.rb
|
|
@@ -593,6 +593,7 @@ files:
|
|
|
593
593
|
- lib/rails_base/configuration/templates.rb
|
|
594
594
|
- lib/rails_base/configuration/user.rb
|
|
595
595
|
- lib/rails_base/engine.rb
|
|
596
|
+
- lib/rails_base/switch_user_helper.rb
|
|
596
597
|
- lib/rails_base/version.rb
|
|
597
598
|
- lib/tasks/rails_base_tasks.rake
|
|
598
599
|
- lib/twilio_helper.rb
|
|
@@ -616,7 +617,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
616
617
|
- !ruby/object:Gem::Version
|
|
617
618
|
version: '0'
|
|
618
619
|
requirements: []
|
|
619
|
-
rubygems_version: 3.2.
|
|
620
|
+
rubygems_version: 3.2.32
|
|
620
621
|
signing_key:
|
|
621
622
|
specification_version: 4
|
|
622
623
|
summary: Rails engine that takes care of the stuff you dont want to!
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
module RailsBase
|
|
2
|
-
class ApplicationController < ActionController::Base
|
|
3
|
-
before_action :configure_permitted_parameters, if: :devise_controller?
|
|
4
|
-
before_action :set_time_zone
|
|
5
|
-
before_action :is_timeout_error?
|
|
6
|
-
before_action :admin_reset_impersonation_session!
|
|
7
|
-
before_action :footer_mode_case
|
|
8
|
-
|
|
9
|
-
before_action :populate_admin_actions, if: -> { RailsBase.config.admin.enable_actions? }
|
|
10
|
-
after_action :capture_admin_action
|
|
11
|
-
|
|
12
|
-
include ApplicationHelper
|
|
13
|
-
include AppearanceHelper
|
|
14
|
-
include CaptureReferenceHelper
|
|
15
|
-
|
|
16
|
-
def set_time_zone
|
|
17
|
-
return unless RailsBase.config.user.tz_user_defined?
|
|
18
|
-
return if current_user.nil?
|
|
19
|
-
|
|
20
|
-
# esape this since this is not signed
|
|
21
|
-
offset = cookies[TIMEZONE_OFFSET_COOKIE].to_i
|
|
22
|
-
|
|
23
|
-
cookie_tz = ActiveSupport::TimeZone[((offset * -1) / 60.0)]
|
|
24
|
-
|
|
25
|
-
if session_tz = session[TIMEZONE_SESSION_NAME]
|
|
26
|
-
# if session exists
|
|
27
|
-
if cookie_tz && session_tz != cookie_tz.name
|
|
28
|
-
# if cookie exists and cookie_tz does not match, update db and session
|
|
29
|
-
current_user.update_tz(tz_name: cookie_tz.name)
|
|
30
|
-
session[TIMEZONE_SESSION_NAME] = cookie_tz.name
|
|
31
|
-
end
|
|
32
|
-
else
|
|
33
|
-
# if session timezone does not exist, attempt to push to DB and set to session
|
|
34
|
-
current_user.update_tz(tz_name: cookie_tz.name)
|
|
35
|
-
session[TIMEZONE_SESSION_NAME] = cookie_tz.name
|
|
36
|
-
end
|
|
37
|
-
Thread.current[TIMEZONE_THREAD_NAME] = session[TIMEZONE_SESSION_NAME]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def is_timeout_error?
|
|
41
|
-
return if current_user || !params.keys.include?('timeout')
|
|
42
|
-
|
|
43
|
-
flash[:notice] = nil
|
|
44
|
-
flash[:alert] = 'Your session expired. Please sign in again to continue.'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def admin_impersonation_session?
|
|
48
|
-
return false if current_user.nil?
|
|
49
|
-
return false unless encrypted_val = session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].presence
|
|
50
|
-
|
|
51
|
-
token = admin_get_token(encrypted_val: encrypted_val)
|
|
52
|
-
if token.failure?
|
|
53
|
-
logger.warn "Failed to parse encrypted token. Either expired or was not present"
|
|
54
|
-
flash[:alert] = 'Failed to retrieve Session token. Retry action'
|
|
55
|
-
redirect_to RailsBase.url_routes.admin_base_path
|
|
56
|
-
return false
|
|
57
|
-
else
|
|
58
|
-
logger.info "Found original_admin_user_id"
|
|
59
|
-
@original_admin_user_id = token.user_id
|
|
60
|
-
end
|
|
61
|
-
true
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def admin_reset_impersonation_session!
|
|
65
|
-
return unless admin_impersonation_session?
|
|
66
|
-
|
|
67
|
-
# at this point we know there is an impersonation
|
|
68
|
-
admin_user = User.find @original_admin_user_id
|
|
69
|
-
admin_set_token_on_session(admin_user: admin_user, other_user: current_user)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def admin_user?
|
|
73
|
-
return if RailsBase.config.admin.view_admin_page?(current_user)
|
|
74
|
-
|
|
75
|
-
session.clear
|
|
76
|
-
sign_out(current_user)
|
|
77
|
-
|
|
78
|
-
flash[:alert] = 'Unauthorized action. You have been signed out'
|
|
79
|
-
redirect_to RailsBase.url_routes.unauthenticated_root_path
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def populate_admin_actions
|
|
83
|
-
return if session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].present?
|
|
84
|
-
return if current_user.nil?
|
|
85
|
-
return unless request.fullpath == RailsBase.url_routes.authenticated_root_path
|
|
86
|
-
|
|
87
|
-
@__admin_actions_array = AdminAction.get_cache_items(user: current_user, alltime: true)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def capture_admin_action
|
|
91
|
-
# ToDo: Turn this into a service
|
|
92
|
-
# ToDo: All admin actions come there here: Allow this to be confirugable on or off
|
|
93
|
-
_controller = ActiveSupport::Inflector.camelize("#{params[:controller]}_controller")
|
|
94
|
-
admin_user =
|
|
95
|
-
if _controller == RailsBase::AdminController.to_s
|
|
96
|
-
current_user
|
|
97
|
-
else
|
|
98
|
-
@original_admin_user_id ? User.find(@original_admin_user_id) : nil
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# Means we are not in the admin controller or we are not impersonating
|
|
102
|
-
return if admin_user.nil? || @_admin_action_struct == false
|
|
103
|
-
|
|
104
|
-
# Admin action for all routes
|
|
105
|
-
(RailsBase::Admin::ActionHelper.actions.dig(RailsBase::Admin::ActionHelper::ACTIONS_KEY) || []).each do |helper|
|
|
106
|
-
Rails.logger.warn("Admin Action for every action")
|
|
107
|
-
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Admin action for all controller routes
|
|
111
|
-
object = RailsBase::Admin::ActionHelper.actions.dig(_controller, RailsBase::Admin::ActionHelper::CONTROLLER_ACTIONS_KEY) || []
|
|
112
|
-
object.each do |helper|
|
|
113
|
-
Rails.logger.warn("Admin Action for #{_controller}")
|
|
114
|
-
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Admin action for all controller action specific routes
|
|
118
|
-
(RailsBase::Admin::ActionHelper.actions.dig(_controller, params[:action].to_s) || []).each do |helper|
|
|
119
|
-
Rails.logger.warn("Admin Action for #{_controller}##{params[:action]}")
|
|
120
|
-
helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
protected
|
|
125
|
-
|
|
126
|
-
def admin_get_token(encrypted_val:)
|
|
127
|
-
params = {
|
|
128
|
-
mfa_randomized_token: encrypted_val,
|
|
129
|
-
purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
|
|
130
|
-
}
|
|
131
|
-
RailsBase::Authentication::SessionTokenVerifier.call(params)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def admin_set_token_on_session(admin_user:, other_user:)
|
|
135
|
-
if admin_user.id != other_user.id #dont do this if you are yourself
|
|
136
|
-
logger.warn { "Admin user [#{admin_user.id}] is impersonating user #{other_user.id}" }
|
|
137
|
-
params = {
|
|
138
|
-
user: admin_user,
|
|
139
|
-
purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
|
|
140
|
-
expires_at: RailsBase::Authentication::Constants::ADMIN_MAX_IDLE_TIME.from_now
|
|
141
|
-
}
|
|
142
|
-
encrpytion = RailsBase::Authentication::MfaSetEncryptToken.call(params)
|
|
143
|
-
session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON] = encrpytion.encrypted_val
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def configure_permitted_parameters
|
|
148
|
-
added_attrs = [:phone_number, :email, :password, :password_confirmation, :remember_me]
|
|
149
|
-
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
|
|
150
|
-
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
require 'switch_user'
|
|
2
|
-
require SwitchUser::Engine.root.join('app', 'helpers', 'switch_user_helper.rb')
|
|
3
|
-
|
|
4
|
-
module SwitchUserHelper
|
|
5
|
-
def switch_user_custom(options = {})
|
|
6
|
-
return unless available?
|
|
7
|
-
|
|
8
|
-
selected_user = nil
|
|
9
|
-
|
|
10
|
-
grouped_options_container =
|
|
11
|
-
{}.tap do |h|
|
|
12
|
-
SwitchUser.all_users.each do |record|
|
|
13
|
-
scope = record.is_a?(SwitchUser::GuestRecord) ? :Guest : record.scope.to_s.capitalize
|
|
14
|
-
h[scope] ||= []
|
|
15
|
-
h[scope] << [record.label, record.scope_id]
|
|
16
|
-
|
|
17
|
-
next unless selected_user.nil?
|
|
18
|
-
next if record.is_a?(SwitchUser::GuestRecord)
|
|
19
|
-
|
|
20
|
-
selected_user = record.scope_id if provider.current_user?(record.user, record.scope)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
option_tags = grouped_options_for_select(grouped_options_container.to_a, selected_user)
|
|
25
|
-
|
|
26
|
-
render partial: 'rails_base/switch_user/widget',
|
|
27
|
-
locals: { option_tags: option_tags, classes: options[:class], styles: options[:style] }
|
|
28
|
-
end
|
|
29
|
-
end
|