rails_base 0.51.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +32 -0
- data/Rakefile +32 -0
- data/app/assets/config/rails_base/manifest.js +3 -0
- data/app/assets/images/rails_base/favicon.ico +0 -0
- data/app/assets/javascripts/rails_base/admin.js +2 -0
- data/app/assets/javascripts/rails_base/application.js +22 -0
- data/app/assets/javascripts/rails_base/cable.js +13 -0
- data/app/assets/javascripts/rails_base/mfa_auth.coffee +3 -0
- data/app/assets/javascripts/rails_base/secondary_authentication.coffee +3 -0
- data/app/assets/javascripts/rails_base/sessions.js +152 -0
- data/app/assets/javascripts/rails_base/user_settings.coffee +3 -0
- data/app/assets/stylesheets/rails_base/admin.css +4 -0
- data/app/assets/stylesheets/rails_base/application.scss +15 -0
- data/app/assets/stylesheets/rails_base/mfa_auth.scss +3 -0
- data/app/assets/stylesheets/rails_base/scaffolds.scss +84 -0
- data/app/assets/stylesheets/rails_base/secondary_authentication.scss +3 -0
- data/app/assets/stylesheets/rails_base/user_settings.scss +3 -0
- data/app/controllers/rails_base/admin_controller.rb +315 -0
- data/app/controllers/rails_base/application_controller.rb +153 -0
- data/app/controllers/rails_base/errors_controller.rb +29 -0
- data/app/controllers/rails_base/mfa_auth_controller.rb +50 -0
- data/app/controllers/rails_base/secondary_authentication_controller.rb +224 -0
- data/app/controllers/rails_base/switch_user_controller.rb +29 -0
- data/app/controllers/rails_base/user_settings_controller.rb +81 -0
- data/app/controllers/rails_base/users/passwords_controller.rb +19 -0
- data/app/controllers/rails_base/users/registrations_controller.rb +80 -0
- data/app/controllers/rails_base/users/sessions_controller.rb +108 -0
- data/app/helpers/rails_base/admin_helper.rb +107 -0
- data/app/helpers/rails_base/appearance_helper.rb +58 -0
- data/app/helpers/rails_base/application_helper.rb +26 -0
- data/app/helpers/rails_base/capture_reference_helper.rb +57 -0
- data/app/helpers/rails_base/mfa_auth_helper.rb +2 -0
- data/app/helpers/rails_base/secondary_authentication_helper.rb +2 -0
- data/app/helpers/rails_base/user_field_validators.rb +108 -0
- data/app/helpers/rails_base/user_settings_helper.rb +22 -0
- data/app/jobs/rails_base/application_job.rb +10 -0
- data/app/jobs/twilio_job.rb +9 -0
- data/app/mailers/rails_base/application_mailer.rb +9 -0
- data/app/mailers/rails_base/email_verification_mailer.rb +22 -0
- data/app/mailers/rails_base/event_mailer.rb +16 -0
- data/app/models/admin_action.rb +119 -0
- data/app/models/rails_base/application_record.rb +22 -0
- data/app/models/rails_base/user_constants.rb +28 -0
- data/app/models/secret.rb +37 -0
- data/app/models/short_lived_data.rb +132 -0
- data/app/models/user.rb +143 -0
- data/app/services/rails_base/admin_risky_mfa_send.rb +80 -0
- data/app/services/rails_base/admin_update_attribute.rb +100 -0
- data/app/services/rails_base/authentication/authenticate_user.rb +28 -0
- data/app/services/rails_base/authentication/constants.rb +60 -0
- data/app/services/rails_base/authentication/decision_twofa_type.rb +76 -0
- data/app/services/rails_base/authentication/destroy_user.rb +45 -0
- data/app/services/rails_base/authentication/mfa_set_encrypt_token.rb +32 -0
- data/app/services/rails_base/authentication/mfa_validator.rb +88 -0
- data/app/services/rails_base/authentication/modify_password.rb +67 -0
- data/app/services/rails_base/authentication/send_forgot_password.rb +26 -0
- data/app/services/rails_base/authentication/send_login_mfa_to_user.rb +77 -0
- data/app/services/rails_base/authentication/send_verification_email.rb +103 -0
- data/app/services/rails_base/authentication/session_token_verifier.rb +31 -0
- data/app/services/rails_base/authentication/single_sign_on_create.rb +44 -0
- data/app/services/rails_base/authentication/single_sign_on_send.rb +101 -0
- data/app/services/rails_base/authentication/single_sign_on_verify.rb +42 -0
- data/app/services/rails_base/authentication/sso_verify_email.rb +43 -0
- data/app/services/rails_base/authentication/update_phone_send_verification.rb +46 -0
- data/app/services/rails_base/authentication/verify_forgot_password.rb +46 -0
- data/app/services/rails_base/email_change.rb +20 -0
- data/app/services/rails_base/encryption.rb +87 -0
- data/app/services/rails_base/name_change.rb +71 -0
- data/app/services/rails_base/service_base.rb +65 -0
- data/app/services/rails_base/service_logging.rb +23 -0
- data/app/views/layouts/rails_base/application.html.erb +185 -0
- data/app/views/layouts/rails_base/mailer.html.erb +13 -0
- data/app/views/layouts/rails_base/mailer.text.erb +1 -0
- data/app/views/new.html.erb +4 -0
- data/app/views/rails_base/admin/history.html.erb +26 -0
- data/app/views/rails_base/admin/index.html.erb +149 -0
- data/app/views/rails_base/admin/show_config.html.erb +18 -0
- data/app/views/rails_base/devise/confirmations/new.html.erb +16 -0
- data/app/views/rails_base/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/rails_base/devise/mailer/email_changed.html.erb +7 -0
- data/app/views/rails_base/devise/mailer/password_change.html.erb +3 -0
- data/app/views/rails_base/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/rails_base/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/rails_base/devise/passwords/edit.html.erb +25 -0
- data/app/views/rails_base/devise/passwords/new.html.erb +27 -0
- data/app/views/rails_base/devise/registrations/edit.html.erb +43 -0
- data/app/views/rails_base/devise/registrations/new.html.erb +123 -0
- data/app/views/rails_base/devise/sessions/new.html.erb +4 -0
- data/app/views/rails_base/devise/shared/_error_messages.html.erb +15 -0
- data/app/views/rails_base/devise/shared/_links.html.erb +25 -0
- data/app/views/rails_base/devise/unlocks/new.html.erb +16 -0
- data/app/views/rails_base/email_verification_mailer/email_verification.html.erb +25 -0
- data/app/views/rails_base/email_verification_mailer/event.html.erb +20 -0
- data/app/views/rails_base/email_verification_mailer/forgot_password.html.erb +22 -0
- data/app/views/rails_base/errors/internal_error.html.erb +1 -0
- data/app/views/rails_base/errors/not_found.html.erb +1 -0
- data/app/views/rails_base/errors/unacceptable.html.erb +1 -0
- data/app/views/rails_base/event_mailer/event.html.erb +10 -0
- data/app/views/rails_base/mfa_auth/mfa_code.html.erb +10 -0
- data/app/views/rails_base/secondary_authentication/after_email_login_session_new.html.erb +3 -0
- data/app/views/rails_base/secondary_authentication/forgot_password.html.erb +9 -0
- data/app/views/rails_base/secondary_authentication/remove_me.html.erb +1 -0
- data/app/views/rails_base/secondary_authentication/static.html.erb +5 -0
- data/app/views/rails_base/shared/_admin_actions_modal.html.erb +65 -0
- data/app/views/rails_base/shared/_admin_config_class.html.erb +52 -0
- data/app/views/rails_base/shared/_admin_history.html.erb +86 -0
- data/app/views/rails_base/shared/_admin_modify_email.html.erb +78 -0
- data/app/views/rails_base/shared/_admin_modify_name.html.erb +107 -0
- data/app/views/rails_base/shared/_admin_modify_phone.html.erb +87 -0
- data/app/views/rails_base/shared/_admin_modify_text.html.erb +35 -0
- data/app/views/rails_base/shared/_admin_risky_change.html.erb +57 -0
- data/app/views/rails_base/shared/_admin_risky_mfa.html.erb +74 -0
- data/app/views/rails_base/shared/_admin_selector_dropdown.html.erb +70 -0
- data/app/views/rails_base/shared/_admin_toggle_button.html.erb +72 -0
- data/app/views/rails_base/shared/_admin_warning_alert.html.erb +7 -0
- data/app/views/rails_base/shared/_appearance_mode_selector.html.erb +183 -0
- data/app/views/rails_base/shared/_custom_form_validation_javascript.html.erb +129 -0
- data/app/views/rails_base/shared/_enable_mfa_auth_modal.html.erb +105 -0
- data/app/views/rails_base/shared/_error_pages.html.erb +123 -0
- data/app/views/rails_base/shared/_logged_in_header.html.erb +123 -0
- data/app/views/rails_base/shared/_logged_out_header.html.erb +14 -0
- data/app/views/rails_base/shared/_mfa_input_layout.html.erb +5 -0
- data/app/views/rails_base/shared/_mfa_input_layout_default.html.erb +97 -0
- data/app/views/rails_base/shared/_mfa_input_layout_fallback.html.erb +55 -0
- data/app/views/rails_base/shared/_modify_mfa_auth_modal.html.erb +20 -0
- data/app/views/rails_base/shared/_password_confirm_javascript.html.erb +71 -0
- data/app/views/rails_base/shared/_reset_password_form.html.erb +111 -0
- data/app/views/rails_base/shared/_session_create_form.html.erb +32 -0
- data/app/views/rails_base/shared/_session_timeout_modal.html.erb +76 -0
- data/app/views/rails_base/switch_user/_widget.html.erb +5 -0
- data/app/views/rails_base/user_settings/_confirm_destroy_user.html.erb +42 -0
- data/app/views/rails_base/user_settings/_destroy_user.html.erb +106 -0
- data/app/views/rails_base/user_settings/_modify_name.html.erb +71 -0
- data/app/views/rails_base/user_settings/_modify_password.html.erb +101 -0
- data/app/views/rails_base/user_settings/_modify_password_update_password.html.erb +2 -0
- data/app/views/rails_base/user_settings/index.html.erb +54 -0
- data/config/initializers/01_rails_config.rb +19 -0
- data/config/initializers/admin_action_helper.rb +88 -0
- data/config/initializers/browser.rb +4 -0
- data/config/initializers/default_logged_in_headers.rb +23 -0
- data/config/initializers/devise.rb +314 -0
- data/config/initializers/encryption.rb +2 -0
- data/config/initializers/switch_user.rb +58 -0
- data/config/initializers/switch_user_helper.rb +29 -0
- data/config/locales/devise.en.yml +65 -0
- data/config/locales/en.yml +58 -0
- data/config/routes.rb +114 -0
- data/db/migrate/20210212175453_devise_create_rails_base_users.rb +56 -0
- data/db/migrate/20210212190537_create_rails_base_short_lived_data.rb +19 -0
- data/db/migrate/20210212192645_create_rails_base_secrets.rb +11 -0
- data/db/migrate/20210406015744_create_rails_base_admin_actions.rb +17 -0
- data/db/seeds.rb +23 -0
- data/lib/link_decision_helper.rb +71 -0
- data/lib/rails_base.rb +50 -0
- data/lib/rails_base/admin/action_cache.rb +99 -0
- data/lib/rails_base/admin/action_helper.rb +134 -0
- data/lib/rails_base/admin/default_index_tile.rb +176 -0
- data/lib/rails_base/admin/index_tile.rb +186 -0
- data/lib/rails_base/config.rb +52 -0
- data/lib/rails_base/configuration/active_job.rb +38 -0
- data/lib/rails_base/configuration/admin.rb +231 -0
- data/lib/rails_base/configuration/app.rb +52 -0
- data/lib/rails_base/configuration/appearance.rb +131 -0
- data/lib/rails_base/configuration/authentication.rb +37 -0
- data/lib/rails_base/configuration/base.rb +209 -0
- data/lib/rails_base/configuration/display/background_color.rb +25 -0
- data/lib/rails_base/configuration/display/btn_danger.rb +25 -0
- data/lib/rails_base/configuration/display/btn_dark.rb +25 -0
- data/lib/rails_base/configuration/display/btn_info.rb +25 -0
- data/lib/rails_base/configuration/display/btn_light.rb +25 -0
- data/lib/rails_base/configuration/display/btn_primary.rb +25 -0
- data/lib/rails_base/configuration/display/btn_secondary.rb +25 -0
- data/lib/rails_base/configuration/display/btn_success.rb +25 -0
- data/lib/rails_base/configuration/display/btn_warning.rb +25 -0
- data/lib/rails_base/configuration/display/footer.rb +54 -0
- data/lib/rails_base/configuration/display/navbar.rb +25 -0
- data/lib/rails_base/configuration/display/table_body.rb +25 -0
- data/lib/rails_base/configuration/display/table_header.rb +25 -0
- data/lib/rails_base/configuration/display/text.rb +26 -0
- data/lib/rails_base/configuration/exceptions_app.rb +25 -0
- data/lib/rails_base/configuration/login_behavior.rb +17 -0
- data/lib/rails_base/configuration/mailer.rb +116 -0
- data/lib/rails_base/configuration/mfa.rb +84 -0
- data/lib/rails_base/configuration/owner.rb +17 -0
- data/lib/rails_base/configuration/redis.rb +29 -0
- data/lib/rails_base/configuration/user.rb +43 -0
- data/lib/rails_base/engine.rb +51 -0
- data/lib/rails_base/version.rb +10 -0
- data/lib/tasks/rails_base_tasks.rake +4 -0
- data/lib/twilio_helper.rb +26 -0
- data/lib/velocity_limiter.rb +91 -0
- metadata +619 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rails_base/configuration/base'
|
2
|
+
|
3
|
+
module RailsBase
|
4
|
+
module Configuration
|
5
|
+
class App < Base
|
6
|
+
DEFAULT_VALUES = {
|
7
|
+
base_url: {
|
8
|
+
type: :string,
|
9
|
+
default: ENV.fetch('BASE_URL', 'http://localhost'),
|
10
|
+
description: 'Base url. Used for things like SSO.'
|
11
|
+
},
|
12
|
+
base_port: {
|
13
|
+
type: :string_nil,
|
14
|
+
default: ENV.fetch('BASE_URL_PORT', nil),
|
15
|
+
description: 'Base port. Used for things like SSO.'
|
16
|
+
},
|
17
|
+
web_name_logged_in: {
|
18
|
+
type: :string_proc,
|
19
|
+
default: ->(user) { Rails.application.class.parent_name },
|
20
|
+
description: 'Name of the application when authenticated user is present. Name in the tab of the browser. Allows for dynamic tab names'
|
21
|
+
},
|
22
|
+
web_name_logged_out: {
|
23
|
+
type: :string_proc,
|
24
|
+
default: ->(*) { Rails.application.class.parent_name },
|
25
|
+
description: 'Name of the application when no authenticated user. Name in the tab of the browser. Allows for dynamic tab names'
|
26
|
+
},
|
27
|
+
web_title_logged_in: {
|
28
|
+
type: :string_proc,
|
29
|
+
default: ->(user) { Rails.application.class.parent_name },
|
30
|
+
description: 'Title in nav for the web when logged in. String or proc accepted. When proc, current user will be passed in.'
|
31
|
+
},
|
32
|
+
web_title_logged_out: {
|
33
|
+
type: :string_proc,
|
34
|
+
default: ->(*) { Rails.application.class.parent_name },
|
35
|
+
description: 'Title in nav for the web when logged in. String or proc accepted. When proc, current user will be passed in.'
|
36
|
+
},
|
37
|
+
communication_name: {
|
38
|
+
type: :string_proc,
|
39
|
+
default: ->(*) { Rails.application.class.parent_name },
|
40
|
+
description: 'Name used when communicating with users.'
|
41
|
+
},
|
42
|
+
favicon_path: {
|
43
|
+
type: :string_nil,
|
44
|
+
default: 'rails_base/favicon.ico',
|
45
|
+
description: 'Favicon path'
|
46
|
+
},
|
47
|
+
}
|
48
|
+
|
49
|
+
attr_accessor *DEFAULT_VALUES.keys
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rails_base/configuration/base'
|
2
|
+
require 'rails_base/configuration/display/table_header'
|
3
|
+
require 'rails_base/configuration/display/table_body'
|
4
|
+
require 'rails_base/configuration/display/background_color'
|
5
|
+
require 'rails_base/configuration/display/navbar'
|
6
|
+
require 'rails_base/configuration/display/text'
|
7
|
+
require 'rails_base/configuration/display/footer'
|
8
|
+
require 'rails_base/configuration/display/btn_primary'
|
9
|
+
require 'rails_base/configuration/display/btn_secondary'
|
10
|
+
require 'rails_base/configuration/display/btn_success'
|
11
|
+
require 'rails_base/configuration/display/btn_danger'
|
12
|
+
require 'rails_base/configuration/display/btn_warning'
|
13
|
+
require 'rails_base/configuration/display/btn_info'
|
14
|
+
require 'rails_base/configuration/display/btn_light'
|
15
|
+
require 'rails_base/configuration/display/btn_dark'
|
16
|
+
|
17
|
+
module RailsBase
|
18
|
+
module Configuration
|
19
|
+
class Appearance < Base
|
20
|
+
BUTTONS = [
|
21
|
+
:btn_primary,
|
22
|
+
:btn_secondary,
|
23
|
+
:btn_success,
|
24
|
+
:btn_danger,
|
25
|
+
:btn_warning,
|
26
|
+
:btn_info,
|
27
|
+
:btn_light,
|
28
|
+
:btn_dark,
|
29
|
+
]
|
30
|
+
|
31
|
+
DOWNSTREAM_CLASSES = [
|
32
|
+
:t_header,
|
33
|
+
:t_body,
|
34
|
+
:bg_color,
|
35
|
+
:navbar,
|
36
|
+
:text,
|
37
|
+
:footer,
|
38
|
+
|
39
|
+
] + BUTTONS
|
40
|
+
|
41
|
+
SKIP_DOWNSTREAM_CLASSES = [:footer]
|
42
|
+
DARK_MODE = :dark
|
43
|
+
LIGHT_MODE = :light
|
44
|
+
MATCH_OS = :match_os
|
45
|
+
|
46
|
+
ALLOWABLE_TYPES = {
|
47
|
+
DARK_MODE => 'Dark Mode',
|
48
|
+
LIGHT_MODE => 'Light Mode',
|
49
|
+
}
|
50
|
+
|
51
|
+
APPEARANCE_TYPES = ALLOWABLE_TYPES.merge(MATCH_OS => 'Match System')
|
52
|
+
|
53
|
+
DEFAULT_VALUES = {
|
54
|
+
enabled: {
|
55
|
+
type: :boolean,
|
56
|
+
default: true,
|
57
|
+
description: 'When disabled, the user will be forced into default_mode when appropriate'
|
58
|
+
},
|
59
|
+
default_mode: {
|
60
|
+
type: :values,
|
61
|
+
expect_values: APPEARANCE_TYPES.keys,
|
62
|
+
default: LIGHT_MODE,
|
63
|
+
description: 'Default mode to set when mode not found in cookies/session',
|
64
|
+
},
|
65
|
+
|
66
|
+
math_os_dark: {
|
67
|
+
type: :values,
|
68
|
+
expect_values: ALLOWABLE_TYPES.keys,
|
69
|
+
default: DARK_MODE,
|
70
|
+
description: 'Mode to set when OS returns dark mode (useful when more than light/dark mode',
|
71
|
+
},
|
72
|
+
}
|
73
|
+
|
74
|
+
attr_accessor *DEFAULT_VALUES.keys
|
75
|
+
attr_reader *DOWNSTREAM_CLASSES
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
#####
|
79
|
+
# all display classes are required to have ALLOWABLE_TYPES as default values
|
80
|
+
#####
|
81
|
+
@t_header = Configuration::Display::TableHeader.new
|
82
|
+
@t_body = Configuration::Display::TableBody.new
|
83
|
+
@bg_color = Configuration::Display::BackgroundColor.new
|
84
|
+
@navbar = Configuration::Display::Navbar.new
|
85
|
+
@text = Configuration::Display::Text.new
|
86
|
+
@footer = Configuration::Display::Footer.new
|
87
|
+
|
88
|
+
@btn_primary = Configuration::Display::BtnPrimary.new
|
89
|
+
@btn_secondary = Configuration::Display::BtnSecondary.new
|
90
|
+
@btn_success = Configuration::Display::BtnSuccess.new
|
91
|
+
@btn_danger = Configuration::Display::BtnDanger.new
|
92
|
+
@btn_warning = Configuration::Display::BtnWarning.new
|
93
|
+
@btn_info = Configuration::Display::BtnInfo.new
|
94
|
+
@btn_light = Configuration::Display::BtnLight.new
|
95
|
+
@btn_dark = Configuration::Display::BtnDark.new
|
96
|
+
|
97
|
+
_validate_values
|
98
|
+
super()
|
99
|
+
end
|
100
|
+
|
101
|
+
def validate!
|
102
|
+
super()
|
103
|
+
DOWNSTREAM_CLASSES.each do |variable|
|
104
|
+
instance_variable_get("@#{variable}").validate!
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def assign_default_values!
|
109
|
+
super()
|
110
|
+
DOWNSTREAM_CLASSES.each do |variable|
|
111
|
+
instance_variable_get("@#{variable}").assign_default_values!
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def _validate_values
|
117
|
+
DOWNSTREAM_CLASSES.each do |var|
|
118
|
+
next if SKIP_DOWNSTREAM_CLASSES.include?(var)
|
119
|
+
|
120
|
+
ALLOWABLE_TYPES.each do |k, v|
|
121
|
+
next if public_send(var).respond_to?("#{k}_mode")
|
122
|
+
|
123
|
+
raise ArgumentError, "#{var} does not respond to #{k}_mode"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rails_base/configuration/base'
|
2
|
+
|
3
|
+
module RailsBase
|
4
|
+
module Configuration
|
5
|
+
class Authentication < Base
|
6
|
+
DEFAULT_SESSION = 60.days
|
7
|
+
MIN_SESSION = 5.minutes
|
8
|
+
|
9
|
+
DEFAULT_MFA_TIME = 7.day
|
10
|
+
MIN_MFA_TIME = 1.day
|
11
|
+
|
12
|
+
DEFAULT_VALUES = {
|
13
|
+
session_timeout: {
|
14
|
+
type: :duration,
|
15
|
+
default: ENV.fetch('SESSION_TIMEOUT_IN_SECONDS', DEFAULT_SESSION).to_i.seconds,
|
16
|
+
custom: ->(val) { val.to_i >= MIN_SESSION },
|
17
|
+
msg: "session_timeout must be a duration. Greater than #{MIN_SESSION}",
|
18
|
+
on_assignment: ->(val, _instance) { Devise.timeout_in = val },
|
19
|
+
description: 'Debug purposes. How long to keep admin_velocity_max attempts',
|
20
|
+
},
|
21
|
+
session_timeout_warning: {
|
22
|
+
type: :boolean,
|
23
|
+
default: true,
|
24
|
+
description: 'Display a timeout warning. When disabled, user will be logged out without warning',
|
25
|
+
},
|
26
|
+
mfa_time_duration: {
|
27
|
+
type: :duration,
|
28
|
+
default: DEFAULT_MFA_TIME,
|
29
|
+
custom: ->(val) { val.to_i > MIN_MFA_TIME },
|
30
|
+
msg: "mfa_time_duration must be a duration. Greater than #{MIN_MFA_TIME}",
|
31
|
+
description: 'Max time between when MFA will be required',
|
32
|
+
}
|
33
|
+
}
|
34
|
+
attr_accessor *DEFAULT_VALUES.keys
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module RailsBase
|
2
|
+
module Configuration
|
3
|
+
class Base
|
4
|
+
class InvalidConfiguration < StandardError; end;
|
5
|
+
class InvalidCustomConfiguration < StandardError; end;
|
6
|
+
class ConfigurationAlreadyEstablished < StandardError; end;
|
7
|
+
|
8
|
+
def self._allow_write_block?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def self._unset_allow_write!
|
13
|
+
define_singleton_method('_allow_write_block?') do
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
ALLOWED_TYPES = {
|
19
|
+
boolean: -> (val) { [TrueClass, FalseClass].include?(val.class) },
|
20
|
+
proc: -> (val) { [Proc].include?(val.class) },
|
21
|
+
integer: -> (val) { [Integer].include?(val.class) },
|
22
|
+
string: -> (val) { [String].include?(val.class) },
|
23
|
+
symbol: -> (val) { [Symbol].include?(val.class) },
|
24
|
+
symbol_class: -> (val) { [Symbol].include?(val.class) || val.superclass === ActiveJob::QueueAdapters },
|
25
|
+
duration: -> (val) { [ActiveSupport::Duration].include?(val.class) },
|
26
|
+
string_nil: -> (val) { [String, NilClass].include?(val.class) },
|
27
|
+
string_proc: -> (val) { [String, Proc].include?(val.class) },
|
28
|
+
array: -> (val) { [Array].include?(val.class) },
|
29
|
+
hash: -> (val) { [Hash].include?(val.class) },
|
30
|
+
path: -> (val) { [Pathname].include?(val.class) },
|
31
|
+
klass: -> (_val) { true },
|
32
|
+
values: -> (_val) { true },
|
33
|
+
}
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
override_methods!
|
37
|
+
assign_default_values!
|
38
|
+
def_convenience_methods
|
39
|
+
end
|
40
|
+
|
41
|
+
# on any object you Base inherited object yoyu can call
|
42
|
+
# `.dig(:chain1, :chain2, :chain3)
|
43
|
+
def dig(*args, default: nil, &block)
|
44
|
+
current = self.public_send(args[0])
|
45
|
+
|
46
|
+
args[1..-1].each do |key|
|
47
|
+
return current || default if current.nil?
|
48
|
+
|
49
|
+
current = current.public_send(key)
|
50
|
+
end
|
51
|
+
current
|
52
|
+
rescue StandardError
|
53
|
+
if block_given?
|
54
|
+
yield block
|
55
|
+
else
|
56
|
+
default
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def assign_default_values!
|
61
|
+
self.class::DEFAULT_VALUES.each do |key, object|
|
62
|
+
val = object[:default_assign_on_boot] ? object[:default_assign_on_boot].call : object[:default]
|
63
|
+
public_send(:"#{key}=", val)
|
64
|
+
end
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def override_methods!
|
69
|
+
self.class::DEFAULT_VALUES.each do |key, object|
|
70
|
+
self.class.define_method(:"#{key}=") do |value|
|
71
|
+
raise ConfigurationAlreadyEstablished, "Unable to assign [#{_name}.#{key}]. Assignment must happen on boot" unless self.class._allow_write_block?
|
72
|
+
|
73
|
+
instance_variable_set(:"@#{key}", value)
|
74
|
+
end
|
75
|
+
if object[:type] == :array
|
76
|
+
self.class.define_method(:"#{key}<<") do |value|
|
77
|
+
raise ConfigurationAlreadyEstablished, "Unable to assign [#{_name}.#{key}]. Assignment must happen on boot" unless self.class._allow_write_block?
|
78
|
+
|
79
|
+
curr = instance_variable_get(:"@#{key}")
|
80
|
+
curr << value
|
81
|
+
instance_variable_set(:"@#{key}", curr)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
if object[:type] == :hash
|
85
|
+
self.class.define_method(:"#{key}.merge") do |value|
|
86
|
+
raise ConfigurationAlreadyEstablished, "Unable to assign [#{_name}.#{key}]. Assignment must happen on boot" unless self.class._allow_write_block?
|
87
|
+
|
88
|
+
curr = instance_variable_get(:"@#{key}")
|
89
|
+
curr.merge(value)
|
90
|
+
instance_variable_set(:"@#{key}", curr)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def validate!
|
97
|
+
custom_validations
|
98
|
+
self.class::DEFAULT_VALUES.each do |key, object|
|
99
|
+
value = instance_variable_get("@#{key}".to_sym)
|
100
|
+
validate_var!(key: key, var: value, type: object[:type])
|
101
|
+
validate_custom_rule!(var: value, custom: object[:custom], key: key, msg: object[:msg])
|
102
|
+
validate_klass_type!(key: key, var: value, type: object[:type], klass_type: object[:klass_type])
|
103
|
+
validate_values_included!(key: key, var: value, type: object[:type], expect_values: object[:expect_values])
|
104
|
+
if object[:on_assignment]
|
105
|
+
if object[:on_assignment].is_a? Array
|
106
|
+
object[:on_assignment].each do |elem|
|
107
|
+
elem.call(value, self)
|
108
|
+
end
|
109
|
+
else
|
110
|
+
object[:on_assignment].call(value, self)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def custom_validations
|
120
|
+
end
|
121
|
+
|
122
|
+
def def_convenience_methods
|
123
|
+
self.class::DEFAULT_VALUES.each do |key, object|
|
124
|
+
if object[:type] == :boolean
|
125
|
+
self.class.define_method("#{key}?") do
|
126
|
+
return false unless dependents_true?(key)
|
127
|
+
|
128
|
+
public_send(key)
|
129
|
+
end
|
130
|
+
elsif object[:type] == :proc
|
131
|
+
self.class.define_method("#{key}?") do |current_user|
|
132
|
+
return false unless dependents_true?(key)
|
133
|
+
|
134
|
+
public_send(key).call(current_user)
|
135
|
+
end
|
136
|
+
elsif object[:type] == :string_proc
|
137
|
+
self.class.define_method("#{key}") do |*args|
|
138
|
+
return false unless dependents_true?(key)
|
139
|
+
|
140
|
+
if instance_variable_get("@#{key}".to_sym).is_a? Proc
|
141
|
+
instance_variable_get("@#{key}".to_sym).call(args[0])
|
142
|
+
else
|
143
|
+
instance_variable_get("@#{key}".to_sym)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
else
|
147
|
+
self.class.define_method("#{key}") do
|
148
|
+
return false unless dependents_true?(key)
|
149
|
+
|
150
|
+
instance_variable_get("@#{key}".to_sym)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def dependents_true?(key)
|
157
|
+
dependents = self.class::DEFAULT_VALUES[key][:dependents] || []
|
158
|
+
|
159
|
+
dependents.all? { |s| s.call(self) }
|
160
|
+
end
|
161
|
+
|
162
|
+
def validate_var!(var:, type:, key:)
|
163
|
+
proc = ALLOWED_TYPES.fetch(type)
|
164
|
+
return if proc.call(var)
|
165
|
+
|
166
|
+
raise InvalidConfiguration, "#{_name}.#{key} expects a #{type}."
|
167
|
+
end
|
168
|
+
|
169
|
+
def validate_klass_type!(var:, type:, key:, klass_type:)
|
170
|
+
return if klass_type.nil?
|
171
|
+
|
172
|
+
boolean =
|
173
|
+
if var.is_a? Array
|
174
|
+
var.all? { |s| klass_type.include?(s.class) }
|
175
|
+
else
|
176
|
+
klass_type.include?(var.class)
|
177
|
+
end
|
178
|
+
return if boolean
|
179
|
+
|
180
|
+
raise InvalidConfiguration, "#{_name}.#{key} expects all members to be a #{klass_type}. Received: [#{var.class}]"
|
181
|
+
end
|
182
|
+
|
183
|
+
def validate_values_included!(key:, var:, type:, expect_values:)
|
184
|
+
return if expect_values.nil?
|
185
|
+
values =
|
186
|
+
if expect_values.is_a? Proc
|
187
|
+
expect_values.call(self)
|
188
|
+
else
|
189
|
+
expect_values
|
190
|
+
end
|
191
|
+
|
192
|
+
return if values.include?(var)
|
193
|
+
|
194
|
+
raise InvalidConfiguration, "#{_name}.#{key} expects value to be included in [#{values}]. Received: [#{var}]"
|
195
|
+
end
|
196
|
+
|
197
|
+
def _name
|
198
|
+
self.class.name.demodulize
|
199
|
+
end
|
200
|
+
|
201
|
+
def validate_custom_rule!(var:, custom:, key:, msg:)
|
202
|
+
return if custom.nil?
|
203
|
+
return if custom.call(var)
|
204
|
+
|
205
|
+
raise InvalidCustomConfiguration, msg
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails_base/configuration/base'
|
2
|
+
|
3
|
+
module RailsBase
|
4
|
+
module Configuration
|
5
|
+
module Display
|
6
|
+
class BackgroundColor < Base
|
7
|
+
|
8
|
+
DEFAULT_VALUES = {
|
9
|
+
dark_mode: {
|
10
|
+
type: :string_nil,
|
11
|
+
default: 'bg-secondary',
|
12
|
+
description: 'Background to use in Dark mode'
|
13
|
+
},
|
14
|
+
light_mode: {
|
15
|
+
type: :string_nil,
|
16
|
+
default: '',
|
17
|
+
description: 'Background to use in light mode'
|
18
|
+
},
|
19
|
+
}
|
20
|
+
|
21
|
+
attr_accessor *DEFAULT_VALUES.keys
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|