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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/lesli_shield/confirmations.css +18763 -0
- data/app/assets/stylesheets/lesli_shield/devise/oauth.css +32 -0
- data/app/assets/stylesheets/lesli_shield/passwords.css +18717 -1
- data/app/assets/stylesheets/lesli_shield/registrations.css +18804 -1
- data/app/assets/stylesheets/lesli_shield/sessions.css +18804 -1
- data/app/assets/stylesheets/lesli_shield/users.css +30 -0
- data/app/controllers/lesli_shield/dashboards_controller.rb +1 -8
- data/app/controllers/lesli_shield/invites_controller.rb +80 -0
- data/app/controllers/lesli_shield/role/actions_controller.rb +32 -20
- data/app/controllers/lesli_shield/roles_controller.rb +16 -8
- data/app/controllers/lesli_shield/sessions_controller.rb +5 -8
- data/app/controllers/lesli_shield/user/roles_controller.rb +62 -0
- data/app/controllers/lesli_shield/users_controller.rb +57 -20
- data/app/controllers/users/confirmations_controller.rb +42 -8
- data/app/controllers/users/passwords_controller.rb +52 -37
- data/app/controllers/users/registrations_controller.rb +2 -8
- data/app/controllers/users/sessions_controller.rb +57 -50
- data/app/helpers/lesli_shield/invites_helper.rb +4 -0
- data/app/helpers/lesli_shield/user/roles_helper.rb +4 -0
- data/app/interfaces/lesli_shield/authorization_interface.rb +8 -2
- data/app/mailers/lesli_shield/devise_mailer.rb +98 -0
- data/app/mailers/lesli_shield/invitation.html.erb +23 -0
- data/app/models/concerns/lesli_shield/user_security.rb +222 -0
- data/app/models/lesli_shield/account.rb +1 -1
- data/app/models/lesli_shield/dashboard.rb +1 -4
- data/app/models/lesli_shield/invite.rb +24 -0
- data/{lib/vue/confirmations.js → app/models/lesli_shield/role/action.rb} +17 -10
- data/{db/migrate/v1/0801003010_create_lesli_shield_dashboards.rb → app/models/lesli_shield/role/privilege.rb} +5 -4
- data/app/models/lesli_shield/user/role.rb +8 -0
- data/app/models/lesli_shield/user/session.rb +80 -0
- data/app/services/lesli_shield/invite_service.rb +43 -0
- data/app/services/lesli_shield/role_action_service.rb +118 -0
- data/app/services/lesli_shield/role_privilege_service.rb +112 -0
- data/app/{operators/lesli_shield/user_registration_operator.rb → services/lesli_shield/user_registration_service.rb} +26 -29
- data/app/services/lesli_shield/user_session_service.rb +78 -0
- data/app/services/lesli_shield/user_validator_service.rb +221 -0
- data/app/views/devise/confirmations/show.html.erb +4 -6
- data/app/views/devise/passwords/edit.html.erb +1 -2
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/devise/registrations/new.html.erb +5 -4
- data/app/views/devise/sessions/new.html.erb +3 -2
- data/app/views/devise/shared/_application-devise-simple.erb +59 -0
- data/app/views/devise/shared/_application-devise.html.erb +76 -0
- data/app/views/lesli_shield/dashboards/_component-calendar.html.erb +1 -0
- data/app/views/lesli_shield/dashboards/_component-chart-bar.html.erb +6 -0
- data/app/views/lesli_shield/dashboards/_component-chart-line.html.erb +8 -0
- data/app/views/lesli_shield/dashboards/_component-count.html.erb +1 -0
- data/app/views/lesli_shield/dashboards/_component-date.html.erb +1 -0
- data/app/views/lesli_shield/dashboards/_component-weather.html.erb +1 -0
- data/app/views/lesli_shield/invites/_form.html.erb +10 -0
- data/app/views/lesli_shield/invites/_invite.html.erb +2 -0
- data/app/views/lesli_shield/invites/edit.html.erb +12 -0
- data/app/views/lesli_shield/invites/index.html.erb +66 -0
- data/{db/migrate/v1/0801001710_create_lesli_shield_settings.rb → app/views/lesli_shield/invites/new.html.erb} +9 -10
- data/{lib/vue/apps/dashboards/components/engine-version.vue → app/views/lesli_shield/invites/show.html.erb} +26 -43
- data/app/views/lesli_shield/partials/_navigation.html.erb +2 -4
- data/app/views/lesli_shield/{roles/_form-privileges.html.erb → role/actions/_form.html.erb} +5 -30
- data/app/views/lesli_shield/role/actions/index.html.erb +14 -0
- data/app/views/lesli_shield/roles/index.html.erb +2 -6
- data/app/views/lesli_shield/roles/new.html.erb +0 -11
- data/app/views/lesli_shield/roles/show.html.erb +5 -8
- data/app/views/lesli_shield/user/roles/_form.html.erb +17 -0
- data/app/views/lesli_shield/user/roles/_role.html.erb +2 -0
- data/app/views/lesli_shield/user/roles/edit.html.erb +12 -0
- data/app/views/lesli_shield/user/roles/index.html.erb +16 -0
- data/app/views/lesli_shield/user/roles/new.html.erb +11 -0
- data/app/views/lesli_shield/user/roles/show.html.erb +10 -0
- data/app/views/lesli_shield/users/{_viewer-activities.html.erb → _activities-viewer.html.erb} +2 -4
- data/app/views/lesli_shield/users/_information-card.html.erb +3 -3
- data/app/views/lesli_shield/users/_management-privileges.html.erb +74 -0
- data/app/views/lesli_shield/users/_management-security.html.erb +5 -0
- data/app/views/lesli_shield/users/index.html.erb +3 -7
- data/app/views/lesli_shield/users/new.html.erb +5 -11
- data/app/views/lesli_shield/users/show.html.erb +7 -5
- data/config/initializers/devise.rb +305 -304
- data/config/locales/translations.en.yml +4 -1
- data/config/locales/translations.es.yml +4 -1
- data/config/locales/translations.it.yml +4 -1
- data/config/routes.rb +7 -8
- data/db/migrate/v1/0801100210_create_lesli_shield_role_actions.rb +48 -0
- data/db/migrate/v1/0801100410_create_lesli_shield_role_privileges.rb +45 -0
- data/db/migrate/v1/0801110110_create_lesli_shield_user_roles.rb +43 -0
- data/db/migrate/v1/0801111210_create_lesli_shield_user_sessions.rb +56 -0
- data/db/migrate/v1/0801120110_create_lesli_shield_invites.rb +49 -0
- data/lib/lesli_shield/engine.rb +3 -3
- data/lib/lesli_shield/router.rb +21 -0
- data/lib/lesli_shield/version.rb +2 -2
- data/lib/lesli_shield.rb +1 -1
- data/lib/scss/_devise.scss +10 -0
- data/lib/scss/confirmations.scss +24 -24
- data/lib/tasks/lesli_shield_tasks.rake +1 -1
- data/readme.md +59 -20
- metadata +69 -44
- data/app/controllers/lesli_shield/dashboard/components_controller.rb +0 -60
- data/app/models/lesli_shield/dashboard/component.rb +0 -18
- data/app/views/lesli_shield/dashboards/edit.html.erb +0 -1
- data/app/views/lesli_shield/dashboards/index.html.erb +0 -9
- data/app/views/lesli_shield/dashboards/new.html.erb +0 -1
- data/app/views/lesli_shield/dashboards/show.html.erb +0 -1
- data/app/views/lesli_shield/roles/_session.html.erb +0 -2
- data/app/views/lesli_shield/roles/edit.html.erb +0 -12
- data/app/views/lesli_shield/roles/update.turbo_stream.erb +0 -3
- data/app/views/lesli_shield/users/update.turbo_stream.erb +0 -3
- data/lib/lesli_shield/routing.rb +0 -23
- data/lib/vue/application.js +0 -83
- data/lib/vue/apps/sessions/index.vue +0 -50
- data/lib/vue/passwords.js +0 -137
- data/lib/vue/registrations.js +0 -144
- data/lib/vue/sessions.js +0 -148
- data/lib/vue/stores/sessions.js +0 -43
- data/lib/vue/stores/translations.json +0 -162
- /data/app/views/lesli_shield/roles/{_form-information.html.erb → _form.html.erb} +0 -0
- /data/db/migrate/v1/{0801120310_create_lesli_shield_user_shortcuts.rb → 0801111010_create_lesli_shield_user_shortcuts.rb} +0 -0
- /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)
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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,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)
|
|
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
|
|
20
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
21
21
|
|
|
22
|
-
Made with ♥ by
|
|
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
|
|
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
|
-
#
|
|
56
|
-
|
|
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
|
-
#
|
|
59
|
-
|
|
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.
|
|
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
|
-
|
|
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
|