rails_base 0.58.0 → 0.70.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|