lesli_security 0.3.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/Rakefile +38 -0
- data/app/assets/config/lesli_security_manifest.js +38 -0
- data/app/assets/images/lesli_security/security-logo.svg +57 -0
- data/app/assets/javascripts/lesli_security/application.js +5583 -0
- data/app/assets/stylesheets/lesli_security/application.css +95 -0
- data/app/controllers/lesli_security/accounts_controller.rb +60 -0
- data/app/controllers/lesli_security/application_controller.rb +37 -0
- data/app/controllers/lesli_security/dashboard/components_controller.rb +60 -0
- data/app/controllers/lesli_security/dashboards_controller.rb +36 -0
- data/app/controllers/lesli_security/descriptor/activities_controller.rb +122 -0
- data/app/controllers/lesli_security/descriptor/privileges_controller.rb +112 -0
- data/app/controllers/lesli_security/descriptors_controller.rb +129 -0
- data/app/controllers/lesli_security/role/activities_controller.rb +76 -0
- data/app/controllers/lesli_security/role/descriptors_controller.rb +97 -0
- data/app/controllers/lesli_security/role/privileges_controller.rb +47 -0
- data/app/controllers/lesli_security/roles_controller.rb +185 -0
- data/app/controllers/lesli_security/user/roles_controller.rb +98 -0
- data/app/controllers/lesli_security/user/sessions_controller.rb +71 -0
- data/app/controllers/lesli_security/users_controller.rb +206 -0
- data/app/helpers/lesli_security/accounts_helper.rb +4 -0
- data/app/helpers/lesli_security/application_helper.rb +4 -0
- data/app/helpers/lesli_security/dashboards_helper.rb +4 -0
- data/app/helpers/lesli_security/descriptor/activities_helper.rb +4 -0
- data/app/helpers/lesli_security/descriptor/privileges_helper.rb +4 -0
- data/app/helpers/lesli_security/descriptors_helper.rb +4 -0
- data/app/helpers/lesli_security/role/activities_helper.rb +4 -0
- data/app/helpers/lesli_security/role/descriptors_helper.rb +4 -0
- data/app/helpers/lesli_security/role/privileges_helper.rb +4 -0
- data/app/helpers/lesli_security/roles_helper.rb +4 -0
- data/app/jobs/lesli_security/application_job.rb +37 -0
- data/app/mailers/lesli_security/application_mailer.rb +39 -0
- data/app/models/lesli_security/account.rb +43 -0
- data/app/models/lesli_security/application_record.rb +37 -0
- data/app/models/lesli_security/dashboard/component.rb +42 -0
- data/app/models/lesli_security/dashboard.rb +58 -0
- data/app/models/lesli_security/descriptor/activity.rb +40 -0
- data/app/models/lesli_security/descriptor/privilege.rb +40 -0
- data/app/models/lesli_security/descriptor.rb +41 -0
- data/app/models/lesli_security/role/activity.rb +40 -0
- data/app/services/lesli_security/descriptor_privilege_service.rb +74 -0
- data/app/services/lesli_security/descriptor_service.rb +152 -0
- data/app/services/lesli_security/role_descriptor_service.rb +61 -0
- data/app/services/lesli_security/role_service.rb +215 -0
- data/app/services/lesli_security/user_service.rb +305 -0
- data/app/views/lesli_security/accounts/_account.html.erb +2 -0
- data/app/views/lesli_security/accounts/_form.html.erb +17 -0
- data/app/views/lesli_security/accounts/edit.html.erb +10 -0
- data/app/views/lesli_security/accounts/index.html.erb +14 -0
- data/app/views/lesli_security/accounts/new.html.erb +9 -0
- data/app/views/lesli_security/accounts/show.html.erb +10 -0
- data/app/views/lesli_security/dashboards/show.html.erb +1 -0
- data/app/views/lesli_security/descriptor/activities/_form.html.erb +32 -0
- data/app/views/lesli_security/descriptor/activities/edit.html.erb +34 -0
- data/app/views/lesli_security/descriptor/activities/index.html.erb +34 -0
- data/app/views/lesli_security/descriptor/activities/new.html.erb +34 -0
- data/app/views/lesli_security/descriptor/activities/show.html.erb +34 -0
- data/app/views/lesli_security/descriptor/privileges/_form.html.erb +32 -0
- data/app/views/lesli_security/descriptor/privileges/edit.html.erb +34 -0
- data/app/views/lesli_security/descriptor/privileges/index.html.erb +34 -0
- data/app/views/lesli_security/descriptor/privileges/new.html.erb +34 -0
- data/app/views/lesli_security/descriptor/privileges/show.html.erb +34 -0
- data/app/views/lesli_security/descriptors/_form.html.erb +32 -0
- data/app/views/lesli_security/descriptors/edit.html.erb +34 -0
- data/app/views/lesli_security/descriptors/index.html.erb +34 -0
- data/app/views/lesli_security/descriptors/new.html.erb +34 -0
- data/app/views/lesli_security/descriptors/show.html.erb +34 -0
- data/app/views/lesli_security/partials/_engine-navigation.html.erb +38 -0
- data/app/views/lesli_security/role/activities/_form.html.erb +32 -0
- data/app/views/lesli_security/role/activities/edit.html.erb +34 -0
- data/app/views/lesli_security/role/activities/index.html.erb +34 -0
- data/app/views/lesli_security/role/activities/new.html.erb +34 -0
- data/app/views/lesli_security/role/activities/show.html.erb +34 -0
- data/app/views/lesli_security/role/descriptors/_form.html.erb +32 -0
- data/app/views/lesli_security/role/descriptors/edit.html.erb +34 -0
- data/app/views/lesli_security/role/descriptors/index.html.erb +34 -0
- data/app/views/lesli_security/role/descriptors/new.html.erb +34 -0
- data/app/views/lesli_security/role/descriptors/show.html.erb +34 -0
- data/app/views/lesli_security/role/privileges/_form.html.erb +32 -0
- data/app/views/lesli_security/role/privileges/edit.html.erb +34 -0
- data/app/views/lesli_security/role/privileges/index.html.erb +34 -0
- data/app/views/lesli_security/role/privileges/new.html.erb +34 -0
- data/app/views/lesli_security/role/privileges/show.html.erb +34 -0
- data/app/views/lesli_security/roles/edit.html.erb +34 -0
- data/app/views/lesli_security/roles/index.html.erb +34 -0
- data/app/views/lesli_security/roles/new.html.erb +34 -0
- data/app/views/lesli_security/roles/show.html.erb +34 -0
- data/app/views/lesli_security/users/edit.html.erb +10 -0
- data/app/views/lesli_security/users/index.html.erb +34 -0
- data/app/views/lesli_security/users/new.html.erb +34 -0
- data/app/views/lesli_security/users/show.html.erb +1 -0
- data/config/locales/translations.en.yml +44 -0
- data/config/locales/translations.es.yml +44 -0
- data/config/locales/translations.fr.yml +44 -0
- data/config/locales/translations.it.yml +44 -0
- data/config/locales/translations.pt.yml +44 -0
- data/config/routes.rb +90 -0
- data/db/migrate/v1/0010000210_create_lesli_roles.rb +60 -0
- data/db/migrate/v1/0010000310_create_lesli_users.rb +97 -0
- data/db/migrate/v1/0010003010_create_lesli_user_details.rb +49 -0
- data/db/migrate/v1/0010003110_create_lesli_user_settings.rb +44 -0
- data/db/migrate/v1/0010003210_create_lesli_user_sessions.rb +55 -0
- data/db/migrate/v1/0010003410_create_lesli_user_powers.rb +43 -0
- data/db/migrate/v1/0010004010_create_lesli_user_logs.rb +45 -0
- data/db/migrate/v1/0010005010_create_lesli_descriptors.rb +44 -0
- data/db/migrate/v1/0010005110_create_lesli_descriptor_privileges.rb +45 -0
- data/db/migrate/v1/0010005210_create_lesli_descriptor_activities.rb +49 -0
- data/db/migrate/v1/0010005510_create_lesli_role_powers.rb +51 -0
- data/db/migrate/v1/0010005710_create_lesli_role_privileges.rb +45 -0
- data/db/migrate/v1/0802000110_create_lesli_security_accounts.rb +42 -0
- data/db/migrate/v1/0802050110_create_lesli_security_dashboards.rb +51 -0
- data/db/migrate/v1/0802050210_create_lesli_security_dashboard_components.rb +53 -0
- data/lib/lesli_security/engine.rb +18 -0
- data/lib/lesli_security/version.rb +4 -0
- data/lib/lesli_security.rb +6 -0
- data/lib/scss/application.scss +38 -0
- data/lib/scss/users.scss +67 -0
- data/lib/tasks/lesli_security_tasks.rake +50 -0
- data/lib/vue/application.js +112 -0
- data/lib/vue/apps/descriptors/components/form.vue +136 -0
- data/lib/vue/apps/descriptors/edit.vue +83 -0
- data/lib/vue/apps/descriptors/index.vue +113 -0
- data/lib/vue/apps/descriptors/new.vue +69 -0
- data/lib/vue/apps/descriptors/show.vue +233 -0
- data/lib/vue/apps/roles/components/descriptors.vue +81 -0
- data/lib/vue/apps/roles/components/form.vue +253 -0
- data/lib/vue/apps/roles/components/privilegeCustom.vue +86 -0
- data/lib/vue/apps/roles/components/privilegeStandard.vue +196 -0
- data/lib/vue/apps/roles/edit.vue +118 -0
- data/lib/vue/apps/roles/index.vue +168 -0
- data/lib/vue/apps/roles/logs.vue +110 -0
- data/lib/vue/apps/roles/new.vue +86 -0
- data/lib/vue/apps/roles/show.vue +109 -0
- data/lib/vue/apps/users/components/information-card.vue +104 -0
- data/lib/vue/apps/users/components/information-form.vue +176 -0
- data/lib/vue/apps/users/components/integrations-information.vue +61 -0
- data/lib/vue/apps/users/components/management-roles.vue +107 -0
- data/lib/vue/apps/users/components/management-security.vue +113 -0
- data/lib/vue/apps/users/components/management-sessions.vue +101 -0
- data/lib/vue/apps/users/components/management-settings.vue +93 -0
- data/lib/vue/apps/users/index.vue +207 -0
- data/lib/vue/apps/users/new.vue +181 -0
- data/lib/vue/apps/users/show.vue +131 -0
- data/lib/vue/stores/descriptor.js +117 -0
- data/lib/vue/stores/descriptors.js +156 -0
- data/lib/vue/stores/role.js +203 -0
- data/lib/vue/stores/roles.js +58 -0
- data/lib/vue/stores/translations.json +277 -0
- data/lib/vue/stores/user.js +331 -0
- data/lib/vue/stores/users.js +166 -0
- data/license +674 -0
- data/readme.md +76 -0
- metadata +225 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module LesliSecurity
|
|
2
|
+
class DescriptorPrivilegeService < Lesli::ApplicationLesliService
|
|
3
|
+
|
|
4
|
+
def index params
|
|
5
|
+
|
|
6
|
+
# First we create a pivot table to convert from:
|
|
7
|
+
# controller_id
|
|
8
|
+
# list
|
|
9
|
+
# index
|
|
10
|
+
# show
|
|
11
|
+
# create
|
|
12
|
+
# update
|
|
13
|
+
# destroy
|
|
14
|
+
# to:
|
|
15
|
+
# controller_id | list | index | show | create | update | destroy |
|
|
16
|
+
# so this is more easy to manage by the API clients
|
|
17
|
+
# NOTE: it is necessary to group by controller id so we ger only one
|
|
18
|
+
# row by controller
|
|
19
|
+
privileges_pivot = Lesli::SystemController.joins(:actions)
|
|
20
|
+
.where("lesli_system_controller_actions.deleted_at IS NULL")
|
|
21
|
+
.group(:system_controller_id)
|
|
22
|
+
.select(
|
|
23
|
+
:system_controller_id,
|
|
24
|
+
"MAX(CASE WHEN lesli_system_controller_actions.name = 'list' THEN lesli_system_controller_actions.id end) AS list_action",
|
|
25
|
+
"MAX(CASE WHEN lesli_system_controller_actions.name = 'index' THEN lesli_system_controller_actions.id end) AS index_action",
|
|
26
|
+
"MAX(CASE WHEN lesli_system_controller_actions.name = 'show' THEN lesli_system_controller_actions.id end) AS show_action",
|
|
27
|
+
"MAX(CASE WHEN lesli_system_controller_actions.name = 'create' THEN lesli_system_controller_actions.id end) AS create_action",
|
|
28
|
+
"MAX(CASE WHEN lesli_system_controller_actions.name = 'update' THEN lesli_system_controller_actions.id end) AS update_action",
|
|
29
|
+
"MAX(CASE WHEN lesli_system_controller_actions.name = 'destroy' THEN lesli_system_controller_actions.id end) AS destroy_action"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# We join to the SystemControllers table again to get the controller name
|
|
33
|
+
# IMPORTANT: We dont get the name from the previos SQL query due we dont want to group by the name string
|
|
34
|
+
# then we have to join to the descriptor_privileges table six times (one time for every action, list, index, etc)
|
|
35
|
+
# we have to do that due we need to check which privileges we have activated
|
|
36
|
+
# later in the select statement we get the id for the list action and if the id is not null get true/false if
|
|
37
|
+
# action is assigned to the descriptor privileges
|
|
38
|
+
# we consider a privilege as active when it has an action assigned and the deleted_at column is null
|
|
39
|
+
# we remove the nulls using "attributes.compact" it is important to remove all the nulls due a null action id
|
|
40
|
+
# means the specific action is not implemented in any application routes, which means there is no view, controller
|
|
41
|
+
# or model defined for that action
|
|
42
|
+
Lesli::SystemController.joins("INNER JOIN (#{privileges_pivot.to_sql}) privileges ON privileges.system_controller_id = lesli_system_controllers.id")
|
|
43
|
+
.joins("left join lesli_descriptor_privileges dp_list on dp_list.descriptor_id = #{params[:descriptor_id]} and dp_list.action_id = privileges.list_action")
|
|
44
|
+
.joins("left join lesli_descriptor_privileges dp_index on dp_index.descriptor_id = #{params[:descriptor_id]} and dp_index.action_id = privileges.index_action")
|
|
45
|
+
.joins("left join lesli_descriptor_privileges dp_show on dp_show.descriptor_id = #{params[:descriptor_id]} and dp_show.action_id = privileges.show_action")
|
|
46
|
+
.joins("left join lesli_descriptor_privileges dp_create on dp_create.descriptor_id = #{params[:descriptor_id]} and dp_create.action_id = privileges.create_action")
|
|
47
|
+
.joins("left join lesli_descriptor_privileges dp_update on dp_update.descriptor_id = #{params[:descriptor_id]} and dp_update.action_id = privileges.update_action")
|
|
48
|
+
.joins("left join lesli_descriptor_privileges dp_destroy on dp_destroy.descriptor_id = #{params[:descriptor_id]} and dp_destroy.action_id = privileges.destroy_action")
|
|
49
|
+
.order(:name)
|
|
50
|
+
.select(
|
|
51
|
+
"name as controller",
|
|
52
|
+
"privileges.list_action",
|
|
53
|
+
"case when privileges.list_action is not null then case when dp_list.action_id is null then false else true end end as list_active",
|
|
54
|
+
|
|
55
|
+
"privileges.index_action",
|
|
56
|
+
"case when privileges.index_action is not null then case when dp_index.action_id is null or dp_index.deleted_at is not null then false else true end end as index_active",
|
|
57
|
+
|
|
58
|
+
"privileges.show_action",
|
|
59
|
+
"case when privileges.show_action is not null then case when dp_show.action_id is null or dp_show.deleted_at is not null then false else true end end as show_active",
|
|
60
|
+
|
|
61
|
+
"privileges.create_action",
|
|
62
|
+
"case when privileges.create_action is not null then case when dp_create.action_id is null or dp_create.deleted_at is not null then false else true end end as create_active",
|
|
63
|
+
|
|
64
|
+
"privileges.update_action",
|
|
65
|
+
"case when privileges.update_action is not null then case when dp_update.action_id is null or dp_update.deleted_at is not null then false else true end end as update_active",
|
|
66
|
+
|
|
67
|
+
"privileges.destroy_action",
|
|
68
|
+
"case when privileges.destroy_action is not null then case when dp_destroy.action_id is null or dp_update.deleted_at is not null then false else true end end as destroy_active",
|
|
69
|
+
).map do |privilege|
|
|
70
|
+
privilege.attributes.compact
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
|
|
32
|
+
=end
|
|
33
|
+
|
|
34
|
+
module LesliSecurity
|
|
35
|
+
class DescriptorService < Lesli::ApplicationLesliService
|
|
36
|
+
|
|
37
|
+
# @overwrite
|
|
38
|
+
# @return {Object}
|
|
39
|
+
# @description Finds a descriptor according the ID given
|
|
40
|
+
def find id
|
|
41
|
+
self.resource = self.current_user.account.descriptors.find_by_id(id)
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @overwrite
|
|
46
|
+
# @return [Array] Paginated index of users.
|
|
47
|
+
# @description Return a paginated array of users, used mostly in frontend views
|
|
48
|
+
def index
|
|
49
|
+
|
|
50
|
+
descriptors = current_user.account.descriptors.where.not(
|
|
51
|
+
:name => ["owner"]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Count the amount of privileges assigned to every descriptor
|
|
55
|
+
descriptors = descriptors.joins(%(
|
|
56
|
+
left join (
|
|
57
|
+
select
|
|
58
|
+
count(1) as total,
|
|
59
|
+
descriptor_id
|
|
60
|
+
from lesli_descriptor_privileges
|
|
61
|
+
--where apga.status = TRUE
|
|
62
|
+
group by descriptor_id
|
|
63
|
+
) as actions
|
|
64
|
+
on actions.descriptor_id = lesli_descriptors.id
|
|
65
|
+
))
|
|
66
|
+
|
|
67
|
+
descriptors = descriptors.select(
|
|
68
|
+
:id,
|
|
69
|
+
:name,
|
|
70
|
+
"coalesce(actions.total, 0) as privileges_count",
|
|
71
|
+
Date2.new.date_time.db_timestamps("lesli_descriptors")
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# skip native descriptors
|
|
75
|
+
#descriptors = descriptors.where.not("descriptors.name in (?)", ["owner", "sysadmin", "profile"])
|
|
76
|
+
|
|
77
|
+
# Filter results by search string
|
|
78
|
+
# unless search_string.blank?
|
|
79
|
+
# descriptors = descriptors.where("(LOWER(descriptors.name) SIMILAR TO ?)", search_string)
|
|
80
|
+
# end
|
|
81
|
+
|
|
82
|
+
return descriptors
|
|
83
|
+
.page(query[:pagination][:page])
|
|
84
|
+
.per(query[:pagination][:perPage])
|
|
85
|
+
.order("#{query[:order][:by]} #{query[:order][:dir]} NULLS LAST")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @overwrite
|
|
89
|
+
# @return {Hash}
|
|
90
|
+
# @description Retrives the descriptor with specific keys/attributes
|
|
91
|
+
def show
|
|
92
|
+
{
|
|
93
|
+
:id => resource.id,
|
|
94
|
+
:name => resource.name,
|
|
95
|
+
:privileges => resource.privileges
|
|
96
|
+
.joins(system_controller_action: :system_controller)
|
|
97
|
+
.select(
|
|
98
|
+
"lesli_descriptor_privileges.id",
|
|
99
|
+
"lesli_system_controllers.name as controlle_name",
|
|
100
|
+
"lesli_system_controller_actions.name as action_name",
|
|
101
|
+
"lesli_descriptor_privileges.created_at"
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @overwrite
|
|
107
|
+
# @return {Object}
|
|
108
|
+
# @param {params} Hash of the permitted attributes for a descriptor
|
|
109
|
+
# @description Creates a new descriptor
|
|
110
|
+
def create params
|
|
111
|
+
descriptor = current_user.account.descriptors.new(params)
|
|
112
|
+
|
|
113
|
+
if descriptor.save
|
|
114
|
+
self.resource = descriptor
|
|
115
|
+
# TODO: keep track of the activities
|
|
116
|
+
else
|
|
117
|
+
self.error(descriptor.errors.full_messages.to_sentence)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
self
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @overwrite
|
|
124
|
+
# @return {Object}
|
|
125
|
+
# @param {params} Hash of the permitted attributes for a descriptor
|
|
126
|
+
# @description Updates descriptor's attributes and saves logs if it went without problem
|
|
127
|
+
def update params
|
|
128
|
+
|
|
129
|
+
# TODO: keep track of the activities
|
|
130
|
+
|
|
131
|
+
unless self.resource.update(params)
|
|
132
|
+
self.error(self.resource.errors.full_messages.to_sentence)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
self
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @overwrite
|
|
139
|
+
# @return {Object}
|
|
140
|
+
# @description Deletes the descriptor
|
|
141
|
+
def destroy
|
|
142
|
+
|
|
143
|
+
# TODO: keep track of the activities
|
|
144
|
+
|
|
145
|
+
unless self.resource.destroy
|
|
146
|
+
self.error(self.resource.errors.full_messages.to_sentence)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
self
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module LesliSecurity
|
|
2
|
+
class RoleDescriptorService < Lesli::ApplicationLesliService
|
|
3
|
+
|
|
4
|
+
def index role
|
|
5
|
+
|
|
6
|
+
# Left join to the role power table, so we can get the records
|
|
7
|
+
# from the assigned descriptors and the available descriptors
|
|
8
|
+
sanitized_role_power_join = ActiveRecord::Base.sanitize_sql([%(
|
|
9
|
+
left join lesli_role_powers
|
|
10
|
+
on lesli_role_powers.descriptor_id = lesli_descriptors.id
|
|
11
|
+
and lesli_role_powers.role_id = ?
|
|
12
|
+
), role.id])
|
|
13
|
+
|
|
14
|
+
current_user.account.descriptors
|
|
15
|
+
.where.not(:name => "owner")
|
|
16
|
+
.joins(sanitized_role_power_join)
|
|
17
|
+
.select(
|
|
18
|
+
"coalesce(lesli_role_powers.descriptor_id, lesli_descriptors.id) as id",
|
|
19
|
+
"lesli_descriptors.name as name",
|
|
20
|
+
"lesli_descriptors.description as description",
|
|
21
|
+
# we take a descriptor as active if it is already in the role power table
|
|
22
|
+
# to validate this we use the following logic:
|
|
23
|
+
# if the role power is not deleted (deleted_at column must be null)
|
|
24
|
+
# and the descriptor_id is not null in the role power table
|
|
25
|
+
"case when lesli_role_powers.deleted_at is null and lesli_role_powers.id is not null then true else false end as active"
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def privileges role
|
|
30
|
+
|
|
31
|
+
# Inner join the role power table with the descriptors
|
|
32
|
+
# so we get only the descriptors that are assigned to the specific role
|
|
33
|
+
sanitized_role_power_join = ActiveRecord::Base.sanitize_sql([%(
|
|
34
|
+
inner join lesli_role_powers
|
|
35
|
+
on lesli_role_powers.descriptor_id = lesli_descriptors.id
|
|
36
|
+
and lesli_role_powers.deleted_at is null
|
|
37
|
+
and lesli_role_powers.role_id = ?
|
|
38
|
+
), role.id])
|
|
39
|
+
|
|
40
|
+
current_user.account.descriptors
|
|
41
|
+
.where.not(:name => "owner")
|
|
42
|
+
.joins(sanitized_role_power_join)
|
|
43
|
+
.select(
|
|
44
|
+
"coalesce(lesli_role_powers.descriptor_id, lesli_descriptors.id) as id",
|
|
45
|
+
"lesli_descriptors.name as name",
|
|
46
|
+
"lesli_role_powers.plist",
|
|
47
|
+
"lesli_role_powers.pindex",
|
|
48
|
+
"lesli_role_powers.pshow",
|
|
49
|
+
"lesli_role_powers.pcreate",
|
|
50
|
+
"lesli_role_powers.pupdate",
|
|
51
|
+
"lesli_role_powers.pdestroy",
|
|
52
|
+
Lesli::Descriptor::Privilege.joins(action: :system_controller).where("lesli_descriptor_privileges.descriptor_id = lesli_descriptors.id and lesli_system_controller_actions.name = 'list'").arel.exists.as("has_list"),
|
|
53
|
+
Lesli::Descriptor::Privilege.joins(action: :system_controller).where("lesli_descriptor_privileges.descriptor_id = lesli_descriptors.id and lesli_system_controller_actions.name = 'index'").arel.exists.as("has_index"),
|
|
54
|
+
Lesli::Descriptor::Privilege.joins(action: :system_controller).where("lesli_descriptor_privileges.descriptor_id = lesli_descriptors.id and lesli_system_controller_actions.name = 'show'").arel.exists.as("has_show"),
|
|
55
|
+
Lesli::Descriptor::Privilege.joins(action: :system_controller).where("lesli_descriptor_privileges.descriptor_id = lesli_descriptors.id and lesli_system_controller_actions.name = 'create'").arel.exists.as("has_create"),
|
|
56
|
+
Lesli::Descriptor::Privilege.joins(action: :system_controller).where("lesli_descriptor_privileges.descriptor_id = lesli_descriptors.id and lesli_system_controller_actions.name = 'update'").arel.exists.as("has_update"),
|
|
57
|
+
Lesli::Descriptor::Privilege.joins(action: :system_controller).where("lesli_descriptor_privileges.descriptor_id = lesli_descriptors.id and lesli_system_controller_actions.name = 'destroy'").arel.exists.as("has_destroy")
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,215 @@
|
|
|
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 platform.
|
|
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
|
+
|
|
32
|
+
=end
|
|
33
|
+
|
|
34
|
+
module LesliSecurity
|
|
35
|
+
class RoleService < Lesli::ApplicationLesliService
|
|
36
|
+
|
|
37
|
+
def find id
|
|
38
|
+
self.resource = current_user.account.roles.find_by_id(id)
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# @return [Array] Paginated index of users.
|
|
44
|
+
# @description Return a paginated array of users, used mostly in frontend views
|
|
45
|
+
def index
|
|
46
|
+
|
|
47
|
+
current_user.account.roles.where.not(
|
|
48
|
+
:name => ["owner"]
|
|
49
|
+
).joins("
|
|
50
|
+
left join (
|
|
51
|
+
select
|
|
52
|
+
count(1) users,
|
|
53
|
+
role_id
|
|
54
|
+
from lesli_user_powers
|
|
55
|
+
inner join lesli_users as u
|
|
56
|
+
on u.id = lesli_user_powers.user_id
|
|
57
|
+
and u.deleted_at is null
|
|
58
|
+
where lesli_user_powers.deleted_at is null
|
|
59
|
+
group by (role_id)
|
|
60
|
+
) users on users.role_id = lesli_roles.id
|
|
61
|
+
").where("lesli_roles.object_level_permission <= ?", current_user.max_object_level_permission)
|
|
62
|
+
.select(
|
|
63
|
+
:id,
|
|
64
|
+
:name,
|
|
65
|
+
:active,
|
|
66
|
+
:isolated,
|
|
67
|
+
:description,
|
|
68
|
+
:path_default,
|
|
69
|
+
:object_level_permission,
|
|
70
|
+
"users.users"
|
|
71
|
+
)
|
|
72
|
+
.page(query[:pagination][:page])
|
|
73
|
+
.per(query[:pagination][:perPage])
|
|
74
|
+
.order(object_level_permission: :desc, name: :asc)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @overwrite
|
|
78
|
+
# @return {Object}
|
|
79
|
+
# @description Retrives the role
|
|
80
|
+
def show
|
|
81
|
+
self.resource
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @overwrite
|
|
85
|
+
# @return {Object}
|
|
86
|
+
# @param {params} Hash of the permitted attributes for a role
|
|
87
|
+
# @description Creates a new role
|
|
88
|
+
def create params
|
|
89
|
+
|
|
90
|
+
role = current_user.account.roles.new(params)
|
|
91
|
+
|
|
92
|
+
unless current_user.can_work_with_role?(role)
|
|
93
|
+
self.error(I18n.t("core.roles.messages_danger_creating_role_object_level_permission_too_high"))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# check if user can work with that object level permission
|
|
97
|
+
if role.object_level_permission.to_f >= current_user.roles.map(&:object_level_permission).max()
|
|
98
|
+
self.error(I18n.t("core.roles.messages_danger_creating_role_object_level_permission_too_high"))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# do not create if errors found
|
|
102
|
+
return self unless self.successful?
|
|
103
|
+
|
|
104
|
+
# Try to save role and logs if it went OK
|
|
105
|
+
if role.save
|
|
106
|
+
self.resource = role
|
|
107
|
+
#Role::Activity.log_create(current_user, self.resource)
|
|
108
|
+
else
|
|
109
|
+
self.error(role.errors.full_messages.to_sentence)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
self
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @overwrite
|
|
116
|
+
# @return {Object}
|
|
117
|
+
# @param {params} Hash of the permitted attributes for a role
|
|
118
|
+
# @description Updates role's attributes and saves logs if it went without problem
|
|
119
|
+
def update params
|
|
120
|
+
old_attributes = self.resource.attributes
|
|
121
|
+
|
|
122
|
+
unless self.resource.update(params)
|
|
123
|
+
self.error(self.resource.errors.full_messages.to_sentence)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
if self.successful?
|
|
127
|
+
new_attributes = self.resource.attributes
|
|
128
|
+
|
|
129
|
+
LesliSecurity::Role::Activity.log_update(current_user, role, old_attributes, new_attributes)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
self
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @overwrite
|
|
136
|
+
# @return {Object}
|
|
137
|
+
# @description Deletes the role
|
|
138
|
+
def destroy
|
|
139
|
+
unless self.resource.destroy
|
|
140
|
+
self.error(self.resource.errors.full_messages.to_sentence)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
if self.successful?
|
|
144
|
+
LesliSecurity::Role::Activity.log_destroy(current_user, self.resource)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
self
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def options
|
|
151
|
+
{
|
|
152
|
+
:object_level_permissions => self.roles_with_object_level_permission
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def roles_with_object_level_permission
|
|
159
|
+
levels = {}
|
|
160
|
+
|
|
161
|
+
# get all the different object level permission registered in the roles
|
|
162
|
+
existing_levels = current_user.account.roles
|
|
163
|
+
.select(:object_level_permission)
|
|
164
|
+
.order(object_level_permission: :desc)
|
|
165
|
+
.distinct
|
|
166
|
+
.map { |level| level.object_level_permission }
|
|
167
|
+
|
|
168
|
+
# Build the next available object levels
|
|
169
|
+
# basically we need to add the possibles object level permissions between the
|
|
170
|
+
# existing ones
|
|
171
|
+
existing_levels.each_with_index do |level_current, i|
|
|
172
|
+
|
|
173
|
+
level_next = 0
|
|
174
|
+
|
|
175
|
+
# get the next OLP in the list of the existing roles
|
|
176
|
+
level_next = existing_levels.to_a[i+1] unless existing_levels.to_a[i+1].nil?
|
|
177
|
+
|
|
178
|
+
# calculate the new next level, basically we get the level right in the middle
|
|
179
|
+
# between the existing levels, example:
|
|
180
|
+
# 1000 existing level
|
|
181
|
+
# 750 new projected level
|
|
182
|
+
# 500 existing level
|
|
183
|
+
level_new = (level_current + level_next) / 2
|
|
184
|
+
|
|
185
|
+
# add the levels to the levels object
|
|
186
|
+
levels[level_current] = []
|
|
187
|
+
|
|
188
|
+
next if level_next == 0
|
|
189
|
+
|
|
190
|
+
levels[level_new] = []
|
|
191
|
+
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Get all the existing roles
|
|
195
|
+
current_user.account.roles
|
|
196
|
+
.select(:id, :name, :object_level_permission)
|
|
197
|
+
.where.not(object_level_permission: nil).each do |role|
|
|
198
|
+
levels[role.object_level_permission] = [] if levels[role.object_level_permission].blank?
|
|
199
|
+
# push the role grouping by the object level permission
|
|
200
|
+
levels[role.object_level_permission].push(role)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
levels_sorted = []
|
|
204
|
+
|
|
205
|
+
levels.keys.each do |key|
|
|
206
|
+
levels_sorted.push({
|
|
207
|
+
level: key,
|
|
208
|
+
roles: levels[key]
|
|
209
|
+
})
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
levels_sorted
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|