lesli_shield 1.0.2 → 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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/lesli_shield/confirmations.css +18763 -0
  3. data/app/assets/stylesheets/lesli_shield/devise/oauth.css +32 -0
  4. data/app/assets/stylesheets/lesli_shield/passwords.css +18717 -1
  5. data/app/assets/stylesheets/lesli_shield/registrations.css +18804 -1
  6. data/app/assets/stylesheets/lesli_shield/sessions.css +18804 -1
  7. data/app/assets/stylesheets/lesli_shield/users.css +30 -0
  8. data/app/controllers/lesli_shield/dashboards_controller.rb +1 -8
  9. data/app/controllers/lesli_shield/invites_controller.rb +80 -0
  10. data/app/controllers/lesli_shield/role/actions_controller.rb +32 -20
  11. data/app/controllers/lesli_shield/roles_controller.rb +16 -8
  12. data/app/controllers/lesli_shield/sessions_controller.rb +5 -8
  13. data/app/controllers/lesli_shield/user/roles_controller.rb +62 -0
  14. data/app/controllers/lesli_shield/users_controller.rb +57 -20
  15. data/app/controllers/users/confirmations_controller.rb +42 -8
  16. data/app/controllers/users/passwords_controller.rb +52 -37
  17. data/app/controllers/users/registrations_controller.rb +2 -8
  18. data/app/controllers/users/sessions_controller.rb +57 -50
  19. data/app/helpers/lesli_shield/invites_helper.rb +4 -0
  20. data/app/helpers/lesli_shield/user/roles_helper.rb +4 -0
  21. data/app/interfaces/lesli_shield/authorization_interface.rb +8 -2
  22. data/app/mailers/lesli_shield/devise_mailer.rb +98 -0
  23. data/app/mailers/lesli_shield/invitation.html.erb +23 -0
  24. data/app/models/concerns/lesli_shield/user_security.rb +222 -0
  25. data/app/models/lesli_shield/account.rb +1 -1
  26. data/app/models/lesli_shield/dashboard.rb +1 -4
  27. data/app/models/lesli_shield/invite.rb +24 -0
  28. data/{lib/vue/confirmations.js → app/models/lesli_shield/role/action.rb} +17 -10
  29. data/{db/migrate/v1/0801003010_create_lesli_shield_dashboards.rb → app/models/lesli_shield/role/privilege.rb} +5 -4
  30. data/app/models/lesli_shield/user/role.rb +8 -0
  31. data/app/models/lesli_shield/user/session.rb +80 -0
  32. data/app/services/lesli_shield/invite_service.rb +43 -0
  33. data/app/services/lesli_shield/role_action_service.rb +118 -0
  34. data/app/services/lesli_shield/role_privilege_service.rb +112 -0
  35. data/app/{operators/lesli_shield/user_registration_operator.rb → services/lesli_shield/user_registration_service.rb} +26 -29
  36. data/app/services/lesli_shield/user_session_service.rb +78 -0
  37. data/app/services/lesli_shield/user_validator_service.rb +221 -0
  38. data/app/views/devise/confirmations/show.html.erb +4 -6
  39. data/app/views/devise/passwords/edit.html.erb +1 -2
  40. data/app/views/devise/passwords/new.html.erb +1 -1
  41. data/app/views/devise/registrations/new.html.erb +5 -4
  42. data/app/views/devise/sessions/new.html.erb +3 -2
  43. data/app/views/devise/shared/_application-devise-simple.erb +59 -0
  44. data/app/views/devise/shared/_application-devise.html.erb +76 -0
  45. data/app/views/lesli_shield/dashboards/_component-calendar.html.erb +1 -0
  46. data/app/views/lesli_shield/dashboards/_component-chart-bar.html.erb +6 -0
  47. data/app/views/lesli_shield/dashboards/_component-chart-line.html.erb +8 -0
  48. data/app/views/lesli_shield/dashboards/_component-count.html.erb +1 -0
  49. data/app/views/lesli_shield/dashboards/_component-date.html.erb +1 -0
  50. data/app/views/lesli_shield/dashboards/_component-weather.html.erb +1 -0
  51. data/app/views/lesli_shield/invites/_form.html.erb +10 -0
  52. data/app/views/lesli_shield/invites/_invite.html.erb +2 -0
  53. data/app/views/lesli_shield/invites/edit.html.erb +12 -0
  54. data/app/views/lesli_shield/invites/index.html.erb +66 -0
  55. data/{db/migrate/v1/0801001710_create_lesli_shield_settings.rb → app/views/lesli_shield/invites/new.html.erb} +9 -10
  56. data/{lib/vue/apps/dashboards/components/engine-version.vue → app/views/lesli_shield/invites/show.html.erb} +26 -43
  57. data/app/views/lesli_shield/partials/_navigation.html.erb +2 -4
  58. data/app/views/lesli_shield/{roles/_form-privileges.html.erb → role/actions/_form.html.erb} +5 -30
  59. data/app/views/lesli_shield/role/actions/index.html.erb +14 -0
  60. data/app/views/lesli_shield/roles/index.html.erb +2 -6
  61. data/app/views/lesli_shield/roles/new.html.erb +0 -11
  62. data/app/views/lesli_shield/roles/show.html.erb +5 -8
  63. data/app/views/lesli_shield/user/roles/_form.html.erb +17 -0
  64. data/app/views/lesli_shield/user/roles/_role.html.erb +2 -0
  65. data/app/views/lesli_shield/user/roles/edit.html.erb +12 -0
  66. data/app/views/lesli_shield/user/roles/index.html.erb +16 -0
  67. data/app/views/lesli_shield/user/roles/new.html.erb +11 -0
  68. data/app/views/lesli_shield/user/roles/show.html.erb +10 -0
  69. data/app/views/lesli_shield/users/{_viewer-activities.html.erb → _activities-viewer.html.erb} +2 -4
  70. data/app/views/lesli_shield/users/_information-card.html.erb +3 -3
  71. data/app/views/lesli_shield/users/_management-privileges.html.erb +74 -0
  72. data/app/views/lesli_shield/users/_management-security.html.erb +5 -0
  73. data/app/views/lesli_shield/users/index.html.erb +3 -7
  74. data/app/views/lesli_shield/users/new.html.erb +5 -11
  75. data/app/views/lesli_shield/users/show.html.erb +7 -5
  76. data/config/initializers/devise.rb +305 -304
  77. data/config/locales/translations.en.yml +4 -1
  78. data/config/locales/translations.es.yml +4 -1
  79. data/config/locales/translations.it.yml +4 -1
  80. data/config/routes.rb +7 -8
  81. data/db/migrate/v1/0801100210_create_lesli_shield_role_actions.rb +48 -0
  82. data/db/migrate/v1/0801100410_create_lesli_shield_role_privileges.rb +45 -0
  83. data/db/migrate/v1/0801110110_create_lesli_shield_user_roles.rb +43 -0
  84. data/db/migrate/v1/0801111210_create_lesli_shield_user_sessions.rb +56 -0
  85. data/db/migrate/v1/0801120110_create_lesli_shield_invites.rb +49 -0
  86. data/lib/lesli_shield/engine.rb +3 -3
  87. data/lib/lesli_shield/router.rb +21 -0
  88. data/lib/lesli_shield/version.rb +2 -2
  89. data/lib/lesli_shield.rb +1 -1
  90. data/lib/scss/_devise.scss +10 -0
  91. data/lib/scss/confirmations.scss +24 -24
  92. data/lib/tasks/lesli_shield_tasks.rake +1 -1
  93. data/readme.md +59 -20
  94. metadata +69 -44
  95. data/app/controllers/lesli_shield/dashboard/components_controller.rb +0 -60
  96. data/app/models/lesli_shield/dashboard/component.rb +0 -18
  97. data/app/views/lesli_shield/dashboards/edit.html.erb +0 -1
  98. data/app/views/lesli_shield/dashboards/index.html.erb +0 -9
  99. data/app/views/lesli_shield/dashboards/new.html.erb +0 -1
  100. data/app/views/lesli_shield/dashboards/show.html.erb +0 -1
  101. data/app/views/lesli_shield/roles/_session.html.erb +0 -2
  102. data/app/views/lesli_shield/roles/edit.html.erb +0 -12
  103. data/app/views/lesli_shield/roles/update.turbo_stream.erb +0 -3
  104. data/app/views/lesli_shield/users/update.turbo_stream.erb +0 -3
  105. data/lib/lesli_shield/routing.rb +0 -23
  106. data/lib/vue/application.js +0 -83
  107. data/lib/vue/apps/sessions/index.vue +0 -50
  108. data/lib/vue/passwords.js +0 -137
  109. data/lib/vue/registrations.js +0 -144
  110. data/lib/vue/sessions.js +0 -148
  111. data/lib/vue/stores/sessions.js +0 -43
  112. data/lib/vue/stores/translations.json +0 -162
  113. /data/app/views/lesli_shield/roles/{_form-information.html.erb → _form.html.erb} +0 -0
  114. /data/db/migrate/v1/{0801120310_create_lesli_shield_user_shortcuts.rb → 0801111010_create_lesli_shield_user_shortcuts.rb} +0 -0
  115. /data/db/migrate/v1/{0801120410_create_lesli_shield_user_tokens.rb → 0801111110_create_lesli_shield_user_tokens.rb} +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2025, 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
@@ -30,8 +30,9 @@ Building a better future, one line of code at a time.
30
30
  // ·
31
31
  =end
32
32
 
33
- class CreateLesliShieldDashboards < ActiveRecord::Migration[6.1]
34
- def change
35
- create_table_lesli_shared_dashboards_10(:lesli_shield)
33
+ module LesliShield
34
+ class Role::Privilege < Lesli::ApplicationLesliRecord
35
+ self.table_name = "lesli_shield_role_privileges"
36
+ belongs_to :role, class_name: "Lesli::Role"
36
37
  end
37
38
  end
@@ -0,0 +1,8 @@
1
+ module LesliShield
2
+ class User::Role < ApplicationRecord
3
+ self.table_name = 'lesli_shield_user_roles'
4
+ belongs_to :user
5
+ belongs_to :role, class_name: "Lesli::Role"
6
+ has_many :roles
7
+ end
8
+ end
@@ -0,0 +1,80 @@
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 User::Session < Lesli::ApplicationLesliRecord
35
+ self.table_name = 'lesli_shield_user_sessions'
36
+ belongs_to :user, class_name: 'Lesli::User'
37
+
38
+ after_create :set_session_token
39
+
40
+ enum :session_source, {
41
+ :dispatcher_standard_session => "dispatcher_standard_session",
42
+ :devise_standard_session => "devise_standard_session"
43
+ }
44
+
45
+ def set_session_token
46
+
47
+ return if self.session_source == "devise_standard_session"
48
+
49
+ return unless self.session_token.blank?
50
+
51
+ rebuild_token = true
52
+
53
+ while rebuild_token do
54
+
55
+ session_token = SecureRandom.alphanumeric(20)
56
+
57
+ # assign token to user if token is unique
58
+ unless User::Session.find_by(:session_token => session_token)
59
+ self.session_token = session_token
60
+ self.save!
61
+ rebuild_token = false
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ def active?
69
+ if self.deleted_at.present?
70
+ return false
71
+ end
72
+
73
+ if self.expiration_at != nil && self.expiration_at < Time.now.utc
74
+ return false
75
+ end
76
+
77
+ return true
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,43 @@
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 InviteService < Lesli::ApplicationLesliService
35
+
36
+ def index params
37
+ Invite.all
38
+ .page(query[:pagination][:page])
39
+ .per(query[:pagination][:perPage])
40
+ .order(updated_at: :desc)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,118 @@
1
+ module LesliShield
2
+ class RoleActionService < Lesli::ApplicationLesliService
3
+
4
+ def find id
5
+ super(Role::Action.with_deleted.find(id))
6
+ end
7
+
8
+ def index role_id
9
+
10
+ def clean action
11
+ {
12
+ :id => action.id,
13
+ :role_id => action.role_id,
14
+ :action_id => action.action_id,
15
+ :deleted_at => action.deleted_at,
16
+ :active => action.active
17
+ }
18
+ end
19
+
20
+ role_actions = {}
21
+
22
+ Role::Action.with_deleted.joins(action: :parent)
23
+ .where(:role_id => role_id)
24
+ .select(
25
+ :id,
26
+ :role_id,
27
+ :deleted_at,
28
+ "parents_lesli_resources.id as controller_id",
29
+ "parents_lesli_resources.label as controller_name",
30
+ "lesli_resources.action as action_name",
31
+ "lesli_resources.id as action_id",
32
+ "case when lesli_shield_role_actions.deleted_at is null then TRUE else FALSE end active"
33
+ ).each do |action|
34
+
35
+ unless role_actions.has_key?(action[:controller_name])
36
+ role_actions[action[:controller_name]] = {
37
+ list:nil,
38
+ index: nil,
39
+ show:nil,
40
+ create:nil,
41
+ update:nil,
42
+ destroy:nil
43
+ }
44
+ end
45
+
46
+ if action[:action_name] == "list"
47
+ role_actions[action[:controller_name]][:list] = clean(action)
48
+ end
49
+
50
+ if action[:action_name] == "index"
51
+ role_actions[action[:controller_name]][:index] = clean(action)
52
+ end
53
+
54
+ if action[:action_name] == "show"
55
+ role_actions[action[:controller_name]][:show] = clean(action)
56
+ end
57
+
58
+ if action[:action_name] == "create"
59
+ role_actions[action[:controller_name]][:create] = clean(action)
60
+ end
61
+
62
+ if action[:action_name] == "update"
63
+ role_actions[action[:controller_name]][:update] = clean(action)
64
+ end
65
+
66
+ if action[:action_name] == "destroy"
67
+ role_actions[action[:controller_name]][:destroy] = clean(action)
68
+ end
69
+ end
70
+
71
+ role_actions
72
+ end
73
+
74
+ def add_guest_actions role
75
+
76
+ # Adding default system actions for profile descriptor
77
+ [
78
+ { controller: "lesli/users", actions: ["update"] }, # enable user edition
79
+ { controller: "lesli/abouts", actions: ["show"] }, # system status
80
+ { controller: "lesli/user/sessions", actions: ["index"] }, # session management
81
+ { controller: "lesli_admin/profiles", actions: ["show"] } # enable profile view
82
+ ].each do |controller_action|
83
+
84
+ controller_action[:actions].each do |action_name|
85
+
86
+ system_controller_action = Lesli::Resource.actions.joins(:parent)
87
+ .where("parents_lesli_resources.route = ?", controller_action[:controller])
88
+ .where("lesli_resources.action = ?", action_name)
89
+
90
+ role.actions.find_or_create_by(
91
+ action: system_controller_action.first
92
+ )
93
+ end
94
+ end
95
+ end
96
+
97
+ def add_owner_actions role
98
+
99
+ now = Time.current
100
+
101
+ # Adding default system actions for profile descriptor
102
+ actions = Lesli::Resource.actions
103
+
104
+ records = actions.map do |action|
105
+ {
106
+ role_id: role.id,
107
+ action_id: action.id,
108
+ created_at: now,
109
+ updated_at: now
110
+ }
111
+ end
112
+
113
+ role.actions.upsert_all(records,
114
+ unique_by: :index_role_actions_on_role_and_action
115
+ )
116
+ end
117
+ end
118
+ end
@@ -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