lesli_shield 1.0.3 → 1.0.4

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/lesli_shield/confirmations.css +18732 -0
  3. data/app/assets/stylesheets/lesli_shield/passwords.css +2 -238
  4. data/app/assets/stylesheets/lesli_shield/registrations.css +2 -238
  5. data/app/assets/stylesheets/lesli_shield/sessions.css +2 -238
  6. data/app/controllers/lesli_shield/dashboards_controller.rb +1 -8
  7. data/app/controllers/lesli_shield/invites_controller.rb +80 -0
  8. data/app/controllers/lesli_shield/role/actions_controller.rb +32 -20
  9. data/app/controllers/lesli_shield/roles_controller.rb +16 -8
  10. data/app/controllers/lesli_shield/sessions_controller.rb +5 -8
  11. data/app/controllers/lesli_shield/user/roles_controller.rb +62 -0
  12. data/app/controllers/lesli_shield/users_controller.rb +57 -20
  13. data/app/controllers/users/confirmations_controller.rb +42 -8
  14. data/app/controllers/users/passwords_controller.rb +52 -37
  15. data/app/controllers/users/registrations_controller.rb +2 -8
  16. data/app/controllers/users/sessions_controller.rb +57 -50
  17. data/app/helpers/lesli_shield/invites_helper.rb +4 -0
  18. data/app/helpers/lesli_shield/user/roles_helper.rb +4 -0
  19. data/app/interfaces/lesli_shield/authorization_interface.rb +8 -2
  20. data/app/mailers/lesli_shield/devise_mailer.rb +98 -0
  21. data/app/mailers/lesli_shield/invitation.html.erb +23 -0
  22. data/app/models/concerns/lesli_shield/user_security.rb +222 -0
  23. data/app/models/lesli_shield/account.rb +1 -1
  24. data/app/models/lesli_shield/dashboard.rb +1 -4
  25. data/app/models/lesli_shield/invite.rb +24 -0
  26. data/{lib/vue/confirmations.js → app/models/lesli_shield/role/action.rb} +17 -10
  27. data/{db/migrate/v1/0801003010_create_lesli_shield_dashboards.rb → app/models/lesli_shield/role/privilege.rb} +5 -4
  28. data/app/models/lesli_shield/user/role.rb +8 -0
  29. data/app/models/lesli_shield/user/session.rb +80 -0
  30. data/app/services/lesli_shield/invite_service.rb +43 -0
  31. data/app/services/lesli_shield/role_action_service.rb +118 -0
  32. data/app/services/lesli_shield/role_privilege_service.rb +112 -0
  33. data/app/{operators/lesli_shield/user_registration_operator.rb → services/lesli_shield/user_registration_service.rb} +26 -29
  34. data/app/services/lesli_shield/user_session_service.rb +78 -0
  35. data/app/services/lesli_shield/user_validator_service.rb +221 -0
  36. data/app/views/devise/confirmations/show.html.erb +4 -6
  37. data/app/views/devise/passwords/edit.html.erb +1 -2
  38. data/app/views/devise/passwords/new.html.erb +1 -1
  39. data/app/views/devise/registrations/new.html.erb +5 -4
  40. data/app/views/devise/sessions/new.html.erb +3 -2
  41. data/app/views/devise/shared/_application-devise-simple.erb +59 -0
  42. data/app/views/devise/shared/_application-devise.html.erb +76 -0
  43. data/app/views/lesli_shield/dashboards/_component-calendar.html.erb +1 -0
  44. data/app/views/lesli_shield/dashboards/_component-chart-bar.html.erb +6 -0
  45. data/app/views/lesli_shield/dashboards/_component-chart-line.html.erb +8 -0
  46. data/app/views/lesli_shield/dashboards/_component-count.html.erb +1 -0
  47. data/app/views/lesli_shield/dashboards/_component-date.html.erb +1 -0
  48. data/app/views/lesli_shield/dashboards/_component-weather.html.erb +1 -0
  49. data/app/views/lesli_shield/invites/_form.html.erb +10 -0
  50. data/app/views/lesli_shield/invites/_invite.html.erb +2 -0
  51. data/app/views/lesli_shield/invites/edit.html.erb +12 -0
  52. data/app/views/lesli_shield/invites/index.html.erb +66 -0
  53. data/{db/migrate/v1/0801001710_create_lesli_shield_settings.rb → app/views/lesli_shield/invites/new.html.erb} +9 -10
  54. data/{lib/vue/apps/dashboards/components/engine-version.vue → app/views/lesli_shield/invites/show.html.erb} +26 -43
  55. data/app/views/lesli_shield/partials/_navigation.html.erb +2 -4
  56. data/app/views/lesli_shield/{roles/_form-privileges.html.erb → role/actions/_form.html.erb} +5 -30
  57. data/app/views/lesli_shield/role/actions/index.html.erb +14 -0
  58. data/app/views/lesli_shield/roles/index.html.erb +2 -6
  59. data/app/views/lesli_shield/roles/new.html.erb +0 -11
  60. data/app/views/lesli_shield/roles/show.html.erb +5 -8
  61. data/app/views/lesli_shield/user/roles/_form.html.erb +17 -0
  62. data/app/views/lesli_shield/user/roles/_role.html.erb +2 -0
  63. data/app/views/lesli_shield/user/roles/edit.html.erb +12 -0
  64. data/app/views/lesli_shield/user/roles/index.html.erb +16 -0
  65. data/app/views/lesli_shield/user/roles/new.html.erb +11 -0
  66. data/app/views/lesli_shield/user/roles/show.html.erb +10 -0
  67. data/app/views/lesli_shield/users/{_viewer-activities.html.erb → _activities-viewer.html.erb} +2 -4
  68. data/app/views/lesli_shield/users/_information-card.html.erb +3 -3
  69. data/app/views/lesli_shield/users/_management-privileges.html.erb +74 -0
  70. data/app/views/lesli_shield/users/_management-security.html.erb +5 -0
  71. data/app/views/lesli_shield/users/index.html.erb +3 -7
  72. data/app/views/lesli_shield/users/new.html.erb +5 -11
  73. data/app/views/lesli_shield/users/show.html.erb +7 -5
  74. data/config/initializers/devise.rb +305 -304
  75. data/config/locales/translations.en.yml +4 -1
  76. data/config/locales/translations.es.yml +4 -1
  77. data/config/locales/translations.it.yml +4 -1
  78. data/config/routes.rb +7 -8
  79. data/db/migrate/v1/0801100210_create_lesli_shield_role_actions.rb +48 -0
  80. data/db/migrate/v1/0801100410_create_lesli_shield_role_privileges.rb +45 -0
  81. data/db/migrate/v1/0801110110_create_lesli_shield_user_roles.rb +43 -0
  82. data/db/migrate/v1/0801111210_create_lesli_shield_user_sessions.rb +56 -0
  83. data/db/migrate/v1/0801120110_create_lesli_shield_invites.rb +49 -0
  84. data/lib/lesli_shield/router.rb +21 -0
  85. data/lib/lesli_shield/version.rb +2 -2
  86. data/lib/lesli_shield.rb +1 -1
  87. data/lib/scss/confirmations.scss +24 -24
  88. data/lib/tasks/lesli_shield_tasks.rake +1 -1
  89. data/readme.md +59 -20
  90. metadata +57 -33
  91. data/app/controllers/lesli_shield/dashboard/components_controller.rb +0 -60
  92. data/app/models/lesli_shield/dashboard/component.rb +0 -18
  93. data/app/views/lesli_shield/dashboards/edit.html.erb +0 -1
  94. data/app/views/lesli_shield/dashboards/index.html.erb +0 -9
  95. data/app/views/lesli_shield/dashboards/new.html.erb +0 -1
  96. data/app/views/lesli_shield/dashboards/show.html.erb +0 -1
  97. data/app/views/lesli_shield/roles/_session.html.erb +0 -2
  98. data/app/views/lesli_shield/roles/edit.html.erb +0 -12
  99. data/app/views/lesli_shield/roles/update.turbo_stream.erb +0 -3
  100. data/app/views/lesli_shield/users/update.turbo_stream.erb +0 -3
  101. data/lib/lesli_shield/routing.rb +0 -23
  102. data/lib/vue/application.js +0 -83
  103. data/lib/vue/apps/sessions/index.vue +0 -50
  104. data/lib/vue/passwords.js +0 -137
  105. data/lib/vue/registrations.js +0 -144
  106. data/lib/vue/sessions.js +0 -148
  107. data/lib/vue/stores/sessions.js +0 -43
  108. data/lib/vue/stores/translations.json +0 -162
  109. /data/app/views/lesli_shield/roles/{_form-information.html.erb → _form.html.erb} +0 -0
  110. /data/db/migrate/v1/{0801120310_create_lesli_shield_user_shortcuts.rb → 0801111010_create_lesli_shield_user_shortcuts.rb} +0 -0
  111. /data/db/migrate/v1/{0801120410_create_lesli_shield_user_tokens.rb → 0801111110_create_lesli_shield_user_tokens.rb} +0 -0
@@ -0,0 +1,112 @@
1
+ =begin
2
+
3
+ Lesli
4
+
5
+ Copyright (c) 2026, Lesli Technologies, S. A.
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see http://www.gnu.org/licenses/.
19
+
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
+
22
+ Made with ♥ by LesliTech
23
+ Building a better future, one line of code at a time.
24
+
25
+ @contact hello@lesli.tech
26
+ @website https://www.lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+ =end
32
+
33
+ module LesliShield
34
+ class RolePrivilegeService < Lesli::ApplicationLesliService
35
+
36
+ # Syncronize the descriptor privileges with the role privilege cache table
37
+ def synchronize role
38
+
39
+ # bulk all the descriptor privileges
40
+ # this script was built manually for performance, maintenance
41
+ # and to make it easy to read for future changes, basically what it does
42
+ # is get the controllers and actions assigned to a descriptor through the
43
+ # system_descriptor_privileges table and create an array of hashes with
44
+ # all the raw privileges (this includes duplicated privileges)
45
+ # IMPORTANT: A descriptor privilege is evaluated as active if:
46
+ # - the role has assigned the descriptor through the power association
47
+ # - the descriptor has assigned the privilege through the controller actions table
48
+ # - the power has active that group of actions, this means that, if the power has
49
+ # not marked as active the pshow, pindex, etc column the power is not active
50
+ # even if it is assigned and active to a descriptor
51
+
52
+ records = Lesli::Role.joins(%(
53
+ INNER JOIN "lesli_shield_role_actions"
54
+ ON "lesli_shield_role_actions"."role_id" = "lesli_roles"."id"
55
+ )).joins(%(
56
+ INNER JOIN lesli_resources as resource_actions
57
+ ON resource_actions.id = lesli_shield_role_actions.action_id
58
+ )).joins(%(
59
+ INNER JOIN lesli_resources as resource_controllers
60
+ ON resource_controllers.id = resource_actions.parent_id
61
+ )).select(%(
62
+ lesli_shield_role_actions.role_id as role_id,
63
+ resource_controllers.route as controller,
64
+ resource_actions.action as action,
65
+ lesli_shield_role_actions.deleted_at IS NULL as active
66
+ )).with_deleted
67
+
68
+ # get privileges only for the given role, this is needed to sync only modified roles
69
+ records = records.where("lesli_shield_role_actions.role_id" => role.id)
70
+
71
+ # get privileges only for the given role action, this is needed to sync only modified actions
72
+ records = records.where("lesli_shield_role_actions.id" => @action.id) if @action
73
+
74
+
75
+ # we use the deleted_at column to know if a privilege is enable or disable, NULL values
76
+ # at the deleted_at column means privilege is active, so if we sort by deleted_at column
77
+ # all the active privileges will be at the top, then the uniq method is going to take
78
+ # always the active values, to completely disable a privilege for a specific controller/action
79
+ # we have to disable in all the roles
80
+ records = records.order("lesli_shield_role_actions.deleted_at DESC")
81
+
82
+
83
+ # convert the results to json so it is easy to insert/update
84
+ records = records.as_json(only: [:controller, :action, :role_id, :active])
85
+
86
+
87
+ # IMPORTANT: We must save only uniq privileges in the role_privilege table
88
+ # this means that it does not matters how many times we defined a privilege dependency
89
+ # we insert the privilege only once.
90
+ # Example: If we defined that we need access to UsersController#index in 20 descriptors,
91
+ # in the role_privileges will be only one record for that specific controller and action
92
+ records = records.uniq do |privilege|
93
+
94
+ # NOTE: If can disable a privilege that belongs to a descriptor,
95
+ # however, if the same privilege is define in another active descriptor,
96
+ # the role that has both descriptor will be able to access the resources
97
+ # of that privilege, that is a normal and desire behavior.
98
+ [privilege["controller"], privilege["action"], privilege["role_id"]]
99
+ end
100
+
101
+
102
+ # small check to ensure I have records to update/insert
103
+ return if records.blank?
104
+
105
+ # bulk update/insert into role privilege cache table
106
+ # IMPORTANT: Due to the importance and how delicate this process is, it is better
107
+ # to copy the controller name and actions from the system, instead of
108
+ # just have a reference to the system_controller_actions table
109
+ Role::Privilege.with_deleted.upsert_all(records, unique_by: [:controller, :action, :role_id])
110
+ end
111
+ end
112
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2023, Lesli Technologies, S. A.
5
+ Copyright (c) 2026, Lesli Technologies, S. A.
6
6
 
7
7
  This program is free software: you can redistribute it and/or modify
8
8
  it under the terms of the GNU General Public License as published by
@@ -17,9 +17,9 @@ GNU General Public License for more details.
17
17
  You should have received a copy of the GNU General Public License
18
18
  along with this program. If not, see http://www.gnu.org/licenses/.
19
19
 
20
- Lesli · Ruby on Rails Development Platform.
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
21
 
22
- Made with ♥ by https://www.lesli.tech
22
+ Made with ♥ by LesliTech
23
23
  Building a better future, one line of code at a time.
24
24
 
25
25
  @contact hello@lesli.tech
@@ -28,11 +28,10 @@ Building a better future, one line of code at a time.
28
28
 
29
29
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
30
  // ·
31
-
32
31
  =end
33
32
 
34
33
  module LesliShield
35
- class UserRegistrationOperator < Lesli::ApplicationLesliService
34
+ class UserRegistrationService < Lesli::ApplicationLesliService
36
35
 
37
36
  def initialize(current_user)
38
37
  @resource = current_user
@@ -41,37 +40,22 @@ module LesliShield
41
40
 
42
41
  def confirm
43
42
 
44
- if current_user.blank?
45
- failures.push(I18n.t("core.shared.messages_warning_user_not_found"))
46
- return self
47
- end
48
-
49
43
  # confirm the user
50
44
  current_user.confirm
51
45
 
52
- # force token deletion so we are sure nobody will be able to use the token again
53
- resource.update(confirmation_token: nil)
54
46
 
55
- # send a welcome email to user as is confirmed
56
- Lesli::DeviseMailer.with(user: resource).welcome.deliver_later
47
+ # force token deletion so we are sure nobody
48
+ # will be able to use the token again
49
+ current_user.update(confirmation_token: nil)
57
50
 
58
- # initialize user dependencies
59
- current_user.after_confirmation
51
+ # Minimum security settings required
52
+ #self.settings.create_with(:value => false).find_or_create_by(:name => "mfa_enabled")
53
+ #self.settings.create_with(:value => :email).find_or_create_by(:name => "mfa_method")
60
54
 
61
55
  end
62
56
 
63
57
  def create_account
64
58
 
65
- if resource.blank?
66
- failures.push(I18n.t("core.shared.messages_warning_user_not_found"))
67
- return self
68
- end
69
-
70
- if resource.account
71
- failures.push(I18n.t("core.users.messages_info_user_already_belongs_to_account"))
72
- return self
73
- end
74
-
75
59
  # check if instance is for multi-account
76
60
  allow_multiaccount = Lesli.config.security.dig(:allow_multiaccount)
77
61
 
@@ -95,7 +79,7 @@ module LesliShield
95
79
 
96
80
  # add owner role to user only if multi-account is allowed
97
81
  if allow_multiaccount == true
98
- resource.roles.create({ role: account.roles.find_by(name: "owner") })
82
+ resource.user_roles.create({ role: account.roles.find_by(name: "owner") })
99
83
  end
100
84
 
101
85
  # add profile role to user only if multi-account is allowed
@@ -112,11 +96,24 @@ module LesliShield
112
96
  end
113
97
  end
114
98
 
99
+ # Synchronize roles for the very first time
100
+ resource.roles.each do |role|
101
+ LesliShield::RolePrivilegeService.new(nil).synchronize(role)
102
+ end
103
+
115
104
  # update user :)
116
105
  resource.save
117
106
 
118
- # initialize user dependencies
119
- resource.after_account_assignation
107
+ # # initialize user dependencies
108
+ # def after_account_assignation
109
+ # return unless self.account
110
+
111
+ # #Courier::One::Firebase::User.sync_user(self)
112
+ # # Lesli::Courier.new(:lesli_calendar).from(:calendar_service, self).create({
113
+ # # name: "Personal Calendar",
114
+ # # default: true
115
+ # # })
116
+ # end
120
117
 
121
118
  end
122
119
  end
@@ -0,0 +1,78 @@
1
+ =begin
2
+
3
+ Lesli
4
+
5
+ Copyright (c) 2025, Lesli Technologies, S. A.
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see http://www.gnu.org/licenses/.
19
+
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
+
22
+ Made with ♥ by LesliTech
23
+ Building a better future, one line of code at a time.
24
+
25
+ @contact hello@lesli.tech
26
+ @website https://www.lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+ =end
32
+
33
+ module LesliShield
34
+ class UserSessionService < Lesli::ApplicationLesliService
35
+
36
+ def index
37
+ LesliShield::User::Session
38
+ .joins(:user)
39
+ .select(
40
+ :id,
41
+ :user_id,
42
+ :first_name,
43
+ :session_source,
44
+ Date2.new.date_time.db_column("created_at", "lesli_shield_user_sessions"),
45
+ Date2.new.date_time.db_column("last_used_at"),
46
+ Date2.new.date_time.db_column("expiration_at"),
47
+ "CONCAT_WS(' ', agent_platform, agent_os, '/', agent_browser, agent_version) as device"
48
+ )
49
+ .page(query[:pagination][:page])
50
+ .per(query[:pagination][:perPage])
51
+ .order(updated_at: :desc)
52
+ end
53
+
54
+ # create a new session
55
+ def create(remote_ip, user_agent=nil, session_source="devise_standard_session")
56
+
57
+ # register a new unique session
58
+ current_session = current_user.sessions.create({
59
+ :remote => remote_ip,
60
+
61
+ :agent_os => user_agent&.dig(:os) || "unknown",
62
+ :agent_platform => user_agent&.dig(:platform) || "unknown",
63
+ :agent_browser => user_agent&.dig(:browser) || "unknown",
64
+ :agent_version => user_agent&.dig(:version) || "unknown",
65
+
66
+ :session_source => session_source,
67
+ :last_used_at => Date2.new.get,
68
+
69
+ :usage_count => 1
70
+ })
71
+
72
+ # register or sync the current_user with the user representation on Firebase
73
+ #Courier::One::Firebase::User.sync_user(@resource) if defined? CloudOne
74
+
75
+ self.response(current_session)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,221 @@
1
+ =begin
2
+
3
+ Lesli
4
+
5
+ Copyright (c) 2023, Lesli Technologies, S. A.
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see http://www.gnu.org/licenses/.
19
+
20
+ Lesli · Ruby on Rails SaaS Development Framework.
21
+
22
+ Made with ♥ by https://www.lesli.tech
23
+ Building a better future, one line of code at a time.
24
+
25
+ @contact hello@lesli.tech
26
+ @website https://www.lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+ =end
32
+
33
+ module LesliShield
34
+ class UserValidatorService < Lesli::ApplicationLesliService
35
+
36
+ def validate
37
+ active?()
38
+ confirmed?()
39
+ roles_empty?()
40
+ active_roles?()
41
+ end
42
+
43
+
44
+ # validates if password meet with the minimum password requirements
45
+ # this settings are stored in the account_settings table
46
+ def password_complexity(password)
47
+
48
+ if password.blank?
49
+ failures.push('error_password_cannot_be_blank')
50
+ return self
51
+ end
52
+
53
+ # remove all the special characters for easy validations of some rules
54
+ password_string_no_special = password.gsub(/[^0-9A-Za-z]/, '')
55
+
56
+ # database keys with the parameters to validate
57
+ password_values = [
58
+ 'password_expiration_time_days',
59
+ 'password_enforce_complexity',
60
+ 'password_special_char_count',
61
+ 'password_lowercase_count',
62
+ 'password_uppercase_count',
63
+ 'password_minimum_length',
64
+ 'password_digit_count'
65
+ ].map do |setting_name|
66
+ "name = '#{setting_name}'"
67
+ end
68
+
69
+ password_settings = []
70
+
71
+ # get password settings from the database
72
+ if @resource.account
73
+
74
+ # if user is already registered
75
+ password_settings = @resource.account.settings.where(password_values.join(" or "))
76
+
77
+ elseif Account.first
78
+
79
+ # for new accounts just take the first account in the database
80
+ password_settings = Account.first.settings.where(password_values.join(" or "))
81
+
82
+ end
83
+
84
+ password_settings.each do |settings|
85
+
86
+ # exit validations if password complexity is not enabled
87
+ if settings[:name] == 'password_enforce_complexity' && settings[:value] != "1"
88
+ failures = []
89
+ break
90
+ end
91
+
92
+ # check if the password has te minimum number of special characters required
93
+ if settings[:name] == 'password_special_char_count'
94
+
95
+ # this regex removes all "normal" letters and numbers leaving special characters
96
+ if settings[:value].to_i > password.scan(/[^0-9A-Za-z]/).length
97
+ failures.push('error_password_special_char_count')
98
+ end
99
+
100
+ end
101
+
102
+ # check if the password has te minimum number of lowercase letters required
103
+ if settings[:name] == 'password_lowercase_count'
104
+
105
+ if settings[:value].to_i > password_string_no_special.scan(/[^0-9A-Z]/).length
106
+ failures.push('error_password_lowercase_count')
107
+ end
108
+
109
+ end
110
+
111
+ # check if the password has te minimum number of uppercase letters required
112
+ if settings[:name] == 'password_uppercase_count'
113
+
114
+ if settings[:value].to_i > password_string_no_special.scan(/[^0-9a-z]/).length
115
+ failures.push('error_password_uppercase_count')
116
+ end
117
+
118
+ end
119
+
120
+ # check if the password has te minium number of numbers required xD
121
+ if settings[:name] == 'password_digit_count'
122
+
123
+ if settings[:value].to_i > password_string_no_special.scan(/[^A-Za-z]/).length
124
+ failures.push('error_password_digit_count')
125
+ end
126
+
127
+ end
128
+
129
+ # check if the password has te minimum size required
130
+ if settings[:name] == 'password_minimum_length'
131
+
132
+ if settings[:value].to_i > password.length
133
+ failures.push('error_password_minimum_length')
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+
140
+ return self
141
+
142
+ end
143
+
144
+ def valid?
145
+ failures.empty?
146
+ end
147
+
148
+ private
149
+
150
+
151
+ # check if user is able to create a new session
152
+ def active?
153
+
154
+ unless @resource.active? && @resource.locked_until != nil
155
+
156
+ # save a locked log for the requested user
157
+ @resource.logs.create({
158
+ title: "session_creation_failed",
159
+ description: "user_locked"
160
+ })
161
+
162
+ return false
163
+
164
+ end
165
+
166
+ return true
167
+ end
168
+
169
+ def confirmed?
170
+
171
+ # check if user is already confirmed
172
+ unless @resource.confirmed?
173
+
174
+ # save a invalid credentials log for the requested user
175
+ @resource.logs.create({
176
+ title: "session_creation_failed",
177
+ description: "email_not_confirmed"
178
+ })
179
+
180
+ return false
181
+
182
+ end
183
+
184
+ return true
185
+
186
+ end
187
+
188
+ def roles_empty?
189
+
190
+ # check if user has roles assigned
191
+ if @resource.roles.empty?
192
+
193
+ @resource.logs.create({
194
+ title: "session_creation_failed",
195
+ description: "user_has_no_assigned_role"
196
+ })
197
+
198
+ return true
199
+
200
+ end
201
+
202
+ return false
203
+
204
+ end
205
+
206
+ def active_roles?
207
+
208
+ # check user has at least one active role before authorize the sign-in request
209
+ unless (@resource.roles.map {|role| role.active}.include? true)
210
+ @resource.logs.create({
211
+ title: "session_creation_failed",
212
+ description: "user_has_no_active_role"
213
+ })
214
+
215
+ return false
216
+ end
217
+
218
+ return true
219
+ end
220
+ end
221
+ end
@@ -38,7 +38,7 @@ Building a better future, one line of code at a time.
38
38
  </script>
39
39
  <% end %>
40
40
 
41
- <%= render("lesli/wrappers/application-devise-simple", title: "Account confirmation") do %>
41
+ <%= render("devise/shared/application-devise-simple", title:"Account confirmation") do %>
42
42
 
43
43
  <% if flash[:danger] %>
44
44
  <% flash.each do |type, msg| %>
@@ -50,14 +50,12 @@ Building a better future, one line of code at a time.
50
50
 
51
51
  <% if flash[:success] %>
52
52
  <div class="confirmation-message">
53
- <svg version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
54
- <path d="M256,6.998c-137.533,0-249,111.467-249,249c0,137.534,111.467,249,249,249s249-111.467,249-249 C505,118.464,393.533,6.998,256,6.998z M256,485.078c-126.309,0-229.08-102.771-229.08-229.081 c0-126.31,102.771-229.08,229.08-229.08c126.31,0,229.08,102.771,229.08,229.08C485.08,382.307,382.31,485.078,256,485.078z"/>
55
- <polygon points="384.235,158.192 216.919,325.518 127.862,236.481 113.72,250.624 216.919,353.803 398.28,172.334"/>
56
- </svg>
57
- <p>Confirmation successfully</p>
53
+ <p>Your account has been successfully verified</p>
58
54
  </div>
59
55
  <% end %>
60
56
 
57
+ <%= render("devise/shared/links", login:true) %>
58
+
61
59
  <% end %>
62
60
 
63
61
 
@@ -1,5 +1,4 @@
1
-
2
- <%= render("lesli/wrappers/application-devise-simple", title:"Cambiar contraseña") do %>
1
+ <%= render("devise/shared/application-devise-simple", title:"Password update") do %>
3
2
 
4
3
  <%= form_for(
5
4
  resource,
@@ -1,5 +1,5 @@
1
1
 
2
- <%= render("lesli/wrappers/application-devise-simple", title:"Forgot your password?") do %>
2
+ <%= render("devise/shared/application-devise-simple", title:"Forgot your password?") do %>
3
3
 
4
4
  <%= form_for(
5
5
  resource,
@@ -28,11 +28,12 @@ Building a better future, one line of code at a time.
28
28
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
29
29
  // ·
30
30
  %>
31
+ <%
32
+ resource.email = 'test2@lesli.tech'
33
+ resource.password = 'Test123!'
34
+ %>
35
+ <%= render("devise/shared/application-devise", title:"Create an account to discover Lesli") do %>
31
36
 
32
-
33
- <%= render("lesli/wrappers/application-devise", title:"Create an account to discover Lesli") do %>
34
-
35
- <%# Log in form %>
36
37
  <%= form_for(
37
38
  resource,
38
39
  as: resource_name,
@@ -39,13 +39,14 @@ if Lesli.config.demo
39
39
  end
40
40
  %>
41
41
 
42
- <%= render("lesli/wrappers/application-devise", title:"Welcome to Lesli") do %>
42
+ <%= render("devise/shared/application-devise", title:"Welcome to Lesli") do %>
43
43
 
44
44
  <%= form_for(
45
45
  resource,
46
46
  as: resource_name,
47
47
  url: user_session_path,
48
- builder: LesliView::Forms::Builder
48
+ builder: LesliView::Forms::Builder,
49
+ data: { turbo: false }
49
50
  ) do |form| %>
50
51
 
51
52
  <% if Lesli.config.demo %>
@@ -0,0 +1,59 @@
1
+ <%
2
+ =begin
3
+
4
+ Lesli
5
+
6
+ Copyright (c) 2023, Lesli Technologies, S. A.
7
+
8
+ This program is free software: you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation, either version 3 of the License, or
11
+ (at your option) any later version.
12
+
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program. If not, see http://www.gnu.org/licenses/.
20
+
21
+ Lesli · Ruby on Rails SaaS development platform.
22
+
23
+ Made with ♥ by https://www.lesli.tech
24
+ Building a better future, one line of code at a time.
25
+
26
+ @contact hello@lesli.tech
27
+ @website https://www.lesli.tech
28
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
29
+
30
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
31
+ // ·
32
+ =end
33
+ %>
34
+
35
+ <% title = defined?(title) ? title : "" %>
36
+
37
+ <main id="lesli-application">
38
+ <section class="hero is-fullheight">
39
+ <div class="hero-head has-text-centered">
40
+ <%# Logo container %>
41
+ <div class="logo mb-4">
42
+ <%= image_tag(
43
+ "#{lesli_instance_code}/brand/app-auth.svg", # dynamic path to the instance main logo
44
+ :class => "#{lesli_instance_code}-logo", # dynamic class according to the instance
45
+ :alt => "Main logo")
46
+ %>
47
+ <h1 class="title is-size-4 has-text-primary">
48
+ <%#= I18n.t("core.users/sessions.view_text_welcome") %>
49
+ <%= title %>
50
+ </h1>
51
+ </div>
52
+ </div>
53
+ <div class="hero-body">
54
+
55
+ <%= yield %>
56
+
57
+ </div>
58
+ </section>
59
+ </main>