rails_base 0.61.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/rails_base/admin_controller.rb +2 -2
  3. data/app/controllers/rails_base/errors_controller.rb +1 -1
  4. data/app/controllers/rails_base/mfa_auth_controller.rb +1 -1
  5. data/app/controllers/rails_base/secondary_authentication_controller.rb +1 -1
  6. data/app/controllers/rails_base/switch_user_controller.rb +1 -0
  7. data/app/controllers/rails_base/user_settings_controller.rb +1 -1
  8. data/app/controllers/rails_base_application_controller.rb +157 -0
  9. data/app/helpers/rails_base/user_settings_helper.rb +1 -1
  10. data/app/models/admin_action.rb +2 -1
  11. data/app/models/rails_base/application_record.rb +1 -1
  12. data/app/services/rails_base/admin_risky_mfa_send.rb +1 -1
  13. data/app/services/rails_base/authentication/mfa_set_encrypt_token.rb +1 -1
  14. data/app/services/rails_base/authentication/send_login_mfa_to_user.rb +1 -1
  15. data/app/services/rails_base/authentication/send_verification_email.rb +1 -1
  16. data/app/services/rails_base/authentication/single_sign_on_create.rb +1 -1
  17. data/app/services/rails_base/authentication/single_sign_on_send.rb +1 -1
  18. data/app/services/rails_base/authentication/single_sign_on_verify.rb +1 -1
  19. data/app/services/rails_base/encryption.rb +2 -2
  20. data/app/views/layouts/rails_base/application.html.erb +4 -8
  21. data/app/views/rails_base/shared/_appearance_mode_selector.html.erb +4 -4
  22. data/db/seeds.rb +7 -4
  23. data/lib/rails_base/admin/action_helper.rb +7 -4
  24. data/lib/rails_base/configuration/active_job.rb +1 -0
  25. data/lib/rails_base/configuration/admin.rb +4 -3
  26. data/lib/rails_base/configuration/app.rb +10 -5
  27. data/lib/rails_base/engine.rb +17 -6
  28. data/lib/rails_base/switch_user_helper.rb +36 -0
  29. data/lib/rails_base/version.rb +1 -1
  30. data/lib/rails_base.rb +7 -1
  31. metadata +9 -9
  32. data/app/controllers/rails_base/application_controller.rb +0 -153
  33. data/config/initializers/switch_user_helper.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f94ae56f9f525b93289e14773189cf437328e50ef8b2e4c7f374bc157730ddcc
4
- data.tar.gz: 8bd40fe32d2bbb0e700e283cd0769121d385844bca3dd02dfd7e426bc32db057
3
+ metadata.gz: b65060d8d2fc37e4df2c2cb83deda894be73dc4504570573580f2cf3b1c02919
4
+ data.tar.gz: 2bb0dc7ab74728e1cde281efa69362f21234dadaf4cd5edec1bec8f3c9a2bba0
5
5
  SHA512:
6
- metadata.gz: 168ac878736a648e77e471b420a3efa0fac9244fd3c0ae594d09737db68e8ebfb99fa8077e48b63813ddde04f7ad59ca0fd52556da1db192f0fc0b6217c6f90c
7
- data.tar.gz: '091ca1be6b369f1d5a03677a6b115e69e1dd5d9cdd07032b648e9650a358999b07bf2a2d0c25a531b92048dc6e2d304ae265fd7459e8b9cb7cc8d3e7554994f5'
6
+ metadata.gz: b4b519cd757c9513509e3141bdb429bb1be7eba89c91a67f7d7c23973d4d1869870651fd7d3aae95fea5ac625bc883c58ef630744687d1bad942b3eac4a39780
7
+ data.tar.gz: ba271fdbbab552800f0aa31052a1bd9e69342a365bbebfa7ec02bbbcc09d45b07f6c65055b2d321dccdca2ee21f115b92e8c91746c15463bdc07ba5c8c1d9fa8
@@ -1,9 +1,9 @@
1
1
  module RailsBase
2
- class AdminController < ApplicationController
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 ErrorsController < ApplicationController
2
+ class ErrorsController < RailsBaseApplicationController
3
3
  before_action :set_variable
4
4
 
5
5
  def not_found
@@ -1,5 +1,5 @@
1
1
  module RailsBase
2
- class MfaAuthController < ApplicationController
2
+ class MfaAuthController < RailsBaseApplicationController
3
3
  before_action :validate_token, only: [:mfa_code, :mfa_code_verify, :resend_mfa]
4
4
 
5
5
  # GET /mfa_verify
@@ -1,5 +1,5 @@
1
1
  module RailsBase
2
- class SecondaryAuthenticationController < ApplicationController
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]
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module RailsBase
3
4
  class SwitchUserController < ::SwitchUserController
4
5
  before_action :admin_user?
@@ -1,5 +1,5 @@
1
1
  module RailsBase
2
- class UserSettingsController < ApplicationController
2
+ class UserSettingsController < RailsBaseApplicationController
3
3
  before_action :authenticate_user!
4
4
  before_action :confirm_password_flow, only: :confirm_password
5
5
 
@@ -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
@@ -17,6 +17,6 @@ module RailsBase::UserSettingsHelper
17
17
  ttl: DATUM_TTL,
18
18
  length: DATUM_LENGTH,
19
19
  }
20
- ShortLivedData.create_data_key(params)
20
+ ShortLivedData.create_data_key(**params)
21
21
  end
22
22
  end
@@ -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[RailsBase::ApplicationController::TIMEZONE_THREAD_NAME]
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
 
@@ -49,7 +49,7 @@ module RailsBase
49
49
  expires_at: EXPIRES_AT.from_now,
50
50
  length: Authentication::Constants::MFA_LENGTH,
51
51
  }
52
- ShortLivedData.create_data_key(params)
52
+ ShortLivedData.create_data_key(**params)
53
53
  end
54
54
 
55
55
  def velocity_max_in_frame
@@ -11,7 +11,7 @@ module RailsBase::Authentication
11
11
  expires_at: expires_at
12
12
  }
13
13
 
14
- context.encrypted_val = RailsBase::Encryption.encode(params)
14
+ context.encrypted_val = RailsBase::Encryption.encode(**params)
15
15
  end
16
16
 
17
17
  def value
@@ -46,7 +46,7 @@ module RailsBase::Authentication
46
46
  expires_at: expires_at,
47
47
  length: Constants::MFA_LENGTH,
48
48
  }
49
- ShortLivedData.create_data_key(params)
49
+ ShortLivedData.create_data_key(**params)
50
50
  end
51
51
 
52
52
  def velocity_max_in_frame
@@ -74,7 +74,7 @@ module RailsBase::Authentication
74
74
  ttl: Constants::SVE_TTL,
75
75
  length: Constants::EMAIL_LENGTH,
76
76
  }
77
- ShortLivedData.create_data_key(params)
77
+ ShortLivedData.create_data_key(**params)
78
78
  end
79
79
 
80
80
  def velocity_max_in_frame
@@ -25,7 +25,7 @@ module RailsBase::Authentication
25
25
  length: token_length,
26
26
  extra: url_redirect,
27
27
  }.compact
28
- ShortLivedData.create_data_key(params)
28
+ ShortLivedData.create_data_key(**params)
29
29
  end
30
30
 
31
31
  def data_type
@@ -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)
@@ -31,7 +31,7 @@ module RailsBase::Authentication
31
31
  reason: reason,
32
32
  access_count: !(bypass || false)
33
33
  }
34
- ShortLivedData.find_datum(params)
34
+ ShortLivedData.find_datum(**params)
35
35
  end
36
36
 
37
37
  def validate!
@@ -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
- <% RailsBase::ApplicationController::VIEWPORT_SIZES.each do |name, max_width| %>
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 = RailsBase::ApplicationController::VIEWPORT_MOBILE_MAX
66
- size = RailsBase::ApplicationController::VIEWPORT_SIZES[k] || 99_999
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 %>
@@ -212,7 +208,7 @@
212
208
  $('.tableFixHead').stickyTableHeaders();
213
209
 
214
210
  // Attempt to set timezone on every request
215
- set_cookie('<%= RailsBase::ApplicationController::TIMEZONE_OFFSET_COOKIE %>', new Date().getTimezoneOffset())
211
+ set_cookie('<%= RailsBaseApplicationController::TIMEZONE_OFFSET_COOKIE %>', new Date().getTimezoneOffset())
216
212
  });
217
213
  <% end %>
218
214
  <% if Rails.env == 'production' %>
@@ -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 = `<%= RailsBase::ApplicationController::APPEARANCE_MODE_COOKIE %>`;
57
- var cookie_actual_name = `<%= RailsBase::ApplicationController::APPEARANCE_MODE_ACTUAL_COOKIE %>`;
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[RailsBase::ApplicationController::APPEARANCE_MODE_COOKIE] || RailsBase.appearance.default_mode %>`)
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[RailsBase::ApplicationController::APPEARANCE_MODE_COOKIE] || RailsBase.appearance.default_mode %>`)
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
  });
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: '6508675309',
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, RailsBase::ApplicationController, ::SwitchUserController]
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 RailsBase::ApplicationController
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: ->(_request, _params) { RailsBase.url_routes.authenticated_root_path },
196
- description: 'Redirection to impersonation -- Landing page when having an identity cris',
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: ->(_request, _params) { RailsBase.url_routes.admin_base_path },
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: ->(user) { RailsBase.app_name },
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: {
@@ -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 'instantiate RailsBase configs' do |_app|
18
+ initializer 'rails_base.config.intantiate' do |_app|
15
19
  RailsBase.config if RailsBase.___execute_initializer___?
16
20
  end
17
21
 
18
- initializer 'remove write access to RailsBase config', after: 'after_initialize' do |app|
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 'define magic convenionce methods for converting team', after: 'active_record.initialize_database' do |app|
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 'remove switch_user routes', after: 'add_routing_paths' do |app|
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 'append RailsBase engine migrations' do |app|
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
@@ -1,6 +1,6 @@
1
1
  module RailsBase
2
2
  MAJOR = '0'
3
- MINOR = '61'
3
+ MINOR = '70'
4
4
  PATCH = '0'
5
5
  VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
6
6
 
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.61.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: 2021-10-05 00:00:00.000000000 Z
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: '5'
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: '5'
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
@@ -546,7 +546,6 @@ files:
546
546
  - config/initializers/devise.rb
547
547
  - config/initializers/encryption.rb
548
548
  - config/initializers/switch_user.rb
549
- - config/initializers/switch_user_helper.rb
550
549
  - config/locales/devise.en.yml
551
550
  - config/locales/en.yml
552
551
  - config/routes.rb
@@ -594,6 +593,7 @@ files:
594
593
  - lib/rails_base/configuration/templates.rb
595
594
  - lib/rails_base/configuration/user.rb
596
595
  - lib/rails_base/engine.rb
596
+ - lib/rails_base/switch_user_helper.rb
597
597
  - lib/rails_base/version.rb
598
598
  - lib/tasks/rails_base_tasks.rake
599
599
  - lib/twilio_helper.rb
@@ -617,7 +617,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
617
617
  - !ruby/object:Gem::Version
618
618
  version: '0'
619
619
  requirements: []
620
- rubygems_version: 3.2.22
620
+ rubygems_version: 3.2.32
621
621
  signing_key:
622
622
  specification_version: 4
623
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