lesli_guard 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +38 -0
  3. data/app/assets/config/lesli_guard_manifest.js +38 -0
  4. data/app/assets/images/lesli_guard/guard-logo.svg +160 -0
  5. data/app/assets/javascripts/lesli_guard/application.js +4787 -0
  6. data/app/assets/stylesheets/lesli_guard/application.scss +33 -0
  7. data/app/assets/stylesheets/lesli_guard/dashboards.scss +32 -0
  8. data/app/assets/stylesheets/lesli_guard/descriptors.scss +32 -0
  9. data/app/assets/stylesheets/lesli_guard/roles.scss +32 -0
  10. data/app/assets/stylesheets/lesli_guard/system_controller.scss +32 -0
  11. data/app/assets/stylesheets/lesli_guard/users.scss +67 -0
  12. data/app/controllers/lesli_guard/accounts_controller.rb +60 -0
  13. data/app/controllers/lesli_guard/application_controller.rb +37 -0
  14. data/app/controllers/lesli_guard/dashboard/components_controller.rb +60 -0
  15. data/app/controllers/lesli_guard/dashboards_controller.rb +36 -0
  16. data/app/controllers/lesli_guard/descriptor/activities_controller.rb +122 -0
  17. data/app/controllers/lesli_guard/descriptor/privileges_controller.rb +112 -0
  18. data/app/controllers/lesli_guard/descriptors_controller.rb +129 -0
  19. data/app/controllers/lesli_guard/role/activities_controller.rb +76 -0
  20. data/app/controllers/lesli_guard/role/descriptors_controller.rb +97 -0
  21. data/app/controllers/lesli_guard/role/privileges_controller.rb +47 -0
  22. data/app/controllers/lesli_guard/roles_controller.rb +185 -0
  23. data/app/controllers/lesli_guard/user/roles_controller.rb +98 -0
  24. data/app/controllers/lesli_guard/user/sessions_controller.rb +71 -0
  25. data/app/controllers/lesli_guard/users_controller.rb +206 -0
  26. data/app/helpers/lesli_guard/accounts_helper.rb +4 -0
  27. data/app/helpers/lesli_guard/application_helper.rb +4 -0
  28. data/app/helpers/lesli_guard/dashboards_helper.rb +4 -0
  29. data/app/helpers/lesli_guard/descriptor/activities_helper.rb +4 -0
  30. data/app/helpers/lesli_guard/descriptor/privileges_helper.rb +4 -0
  31. data/app/helpers/lesli_guard/descriptors_helper.rb +4 -0
  32. data/app/helpers/lesli_guard/role/activities_helper.rb +4 -0
  33. data/app/helpers/lesli_guard/role/descriptors_helper.rb +4 -0
  34. data/app/helpers/lesli_guard/role/privileges_helper.rb +4 -0
  35. data/app/helpers/lesli_guard/roles_helper.rb +4 -0
  36. data/app/jobs/lesli_guard/application_job.rb +37 -0
  37. data/app/mailers/lesli_guard/application_mailer.rb +39 -0
  38. data/app/models/lesli_guard/account.rb +43 -0
  39. data/app/models/lesli_guard/application_record.rb +37 -0
  40. data/app/models/lesli_guard/dashboard/component.rb +42 -0
  41. data/app/models/lesli_guard/dashboard.rb +58 -0
  42. data/app/models/lesli_guard/descriptor/activity.rb +40 -0
  43. data/app/models/lesli_guard/descriptor/privilege.rb +40 -0
  44. data/app/models/lesli_guard/descriptor.rb +41 -0
  45. data/app/models/lesli_guard/role/activity.rb +40 -0
  46. data/app/services/lesli_guard/descriptor_privilege_service.rb +74 -0
  47. data/app/services/lesli_guard/descriptor_service.rb +152 -0
  48. data/app/services/lesli_guard/role_descriptor_service.rb +61 -0
  49. data/app/services/lesli_guard/role_service.rb +215 -0
  50. data/app/services/lesli_guard/user_service.rb +305 -0
  51. data/app/views/lesli_guard/accounts/_account.html.erb +2 -0
  52. data/app/views/lesli_guard/accounts/_form.html.erb +17 -0
  53. data/app/views/lesli_guard/accounts/edit.html.erb +10 -0
  54. data/app/views/lesli_guard/accounts/index.html.erb +14 -0
  55. data/app/views/lesli_guard/accounts/new.html.erb +9 -0
  56. data/app/views/lesli_guard/accounts/show.html.erb +10 -0
  57. data/app/views/lesli_guard/dashboards/show.html.erb +1 -0
  58. data/app/views/lesli_guard/descriptor/activities/_form.html.erb +32 -0
  59. data/app/views/lesli_guard/descriptor/activities/edit.html.erb +34 -0
  60. data/app/views/lesli_guard/descriptor/activities/index.html.erb +34 -0
  61. data/app/views/lesli_guard/descriptor/activities/new.html.erb +34 -0
  62. data/app/views/lesli_guard/descriptor/activities/show.html.erb +34 -0
  63. data/app/views/lesli_guard/descriptor/privileges/_form.html.erb +32 -0
  64. data/app/views/lesli_guard/descriptor/privileges/edit.html.erb +34 -0
  65. data/app/views/lesli_guard/descriptor/privileges/index.html.erb +34 -0
  66. data/app/views/lesli_guard/descriptor/privileges/new.html.erb +34 -0
  67. data/app/views/lesli_guard/descriptor/privileges/show.html.erb +34 -0
  68. data/app/views/lesli_guard/descriptors/_form.html.erb +32 -0
  69. data/app/views/lesli_guard/descriptors/edit.html.erb +34 -0
  70. data/app/views/lesli_guard/descriptors/index.html.erb +34 -0
  71. data/app/views/lesli_guard/descriptors/new.html.erb +34 -0
  72. data/app/views/lesli_guard/descriptors/show.html.erb +34 -0
  73. data/app/views/lesli_guard/partials/_engine-navigation.html.erb +38 -0
  74. data/app/views/lesli_guard/role/activities/_form.html.erb +32 -0
  75. data/app/views/lesli_guard/role/activities/edit.html.erb +34 -0
  76. data/app/views/lesli_guard/role/activities/index.html.erb +34 -0
  77. data/app/views/lesli_guard/role/activities/new.html.erb +34 -0
  78. data/app/views/lesli_guard/role/activities/show.html.erb +34 -0
  79. data/app/views/lesli_guard/role/descriptors/_form.html.erb +32 -0
  80. data/app/views/lesli_guard/role/descriptors/edit.html.erb +34 -0
  81. data/app/views/lesli_guard/role/descriptors/index.html.erb +34 -0
  82. data/app/views/lesli_guard/role/descriptors/new.html.erb +34 -0
  83. data/app/views/lesli_guard/role/descriptors/show.html.erb +34 -0
  84. data/app/views/lesli_guard/role/privileges/_form.html.erb +32 -0
  85. data/app/views/lesli_guard/role/privileges/edit.html.erb +34 -0
  86. data/app/views/lesli_guard/role/privileges/index.html.erb +34 -0
  87. data/app/views/lesli_guard/role/privileges/new.html.erb +34 -0
  88. data/app/views/lesli_guard/role/privileges/show.html.erb +34 -0
  89. data/app/views/lesli_guard/roles/edit.html.erb +34 -0
  90. data/app/views/lesli_guard/roles/index.html.erb +34 -0
  91. data/app/views/lesli_guard/roles/new.html.erb +34 -0
  92. data/app/views/lesli_guard/roles/show.html.erb +34 -0
  93. data/app/views/lesli_guard/users/edit.html.erb +10 -0
  94. data/app/views/lesli_guard/users/index.html.erb +34 -0
  95. data/app/views/lesli_guard/users/new.html.erb +34 -0
  96. data/app/views/lesli_guard/users/show.html.erb +1 -0
  97. data/config/locales/translations.en.yml +43 -0
  98. data/config/locales/translations.es.yml +43 -0
  99. data/config/routes.rb +90 -0
  100. data/db/migrate/v1/0801000110_create_lesli_guard_accounts.rb +42 -0
  101. data/db/migrate/v1/0801050110_create_lesli_guard_dashboards.rb +51 -0
  102. data/db/migrate/v1/0801050210_create_lesli_guard_dashboard_components.rb +53 -0
  103. data/lib/lesli_guard/engine.rb +18 -0
  104. data/lib/lesli_guard/version.rb +4 -0
  105. data/lib/lesli_guard.rb +6 -0
  106. data/lib/tasks/lesli_guard_tasks.rake +50 -0
  107. data/lib/vue/application.js +112 -0
  108. data/lib/vue/apps/descriptors/components/form.vue +136 -0
  109. data/lib/vue/apps/descriptors/edit.vue +83 -0
  110. data/lib/vue/apps/descriptors/index.vue +113 -0
  111. data/lib/vue/apps/descriptors/new.vue +69 -0
  112. data/lib/vue/apps/descriptors/show.vue +233 -0
  113. data/lib/vue/apps/roles/components/descriptors.vue +81 -0
  114. data/lib/vue/apps/roles/components/form.vue +253 -0
  115. data/lib/vue/apps/roles/components/privilegeCustom.vue +86 -0
  116. data/lib/vue/apps/roles/components/privilegeStandard.vue +196 -0
  117. data/lib/vue/apps/roles/edit.vue +118 -0
  118. data/lib/vue/apps/roles/index.vue +168 -0
  119. data/lib/vue/apps/roles/logs.vue +110 -0
  120. data/lib/vue/apps/roles/new.vue +86 -0
  121. data/lib/vue/apps/roles/show.vue +109 -0
  122. data/lib/vue/apps/users/components/information-card.vue +107 -0
  123. data/lib/vue/apps/users/components/information-form.vue +176 -0
  124. data/lib/vue/apps/users/components/integrations-information.vue +61 -0
  125. data/lib/vue/apps/users/components/management-roles.vue +107 -0
  126. data/lib/vue/apps/users/components/management-security.vue +113 -0
  127. data/lib/vue/apps/users/components/management-sessions.vue +101 -0
  128. data/lib/vue/apps/users/components/management-settings.vue +93 -0
  129. data/lib/vue/apps/users/index.vue +207 -0
  130. data/lib/vue/apps/users/new.vue +181 -0
  131. data/lib/vue/apps/users/show.vue +131 -0
  132. data/lib/vue/stores/descriptor.js +117 -0
  133. data/lib/vue/stores/descriptors.js +156 -0
  134. data/lib/vue/stores/role.js +203 -0
  135. data/lib/vue/stores/roles.js +58 -0
  136. data/lib/vue/stores/translations.json +98 -0
  137. data/lib/vue/stores/user.js +331 -0
  138. data/lib/vue/stores/users.js +176 -0
  139. data/license +674 -0
  140. data/readme.md +76 -0
  141. metadata +199 -0
@@ -0,0 +1,41 @@
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 LesliGuard
35
+ class Descriptor < ApplicationRecord
36
+
37
+ has_many :activities
38
+ has_many :privileges
39
+
40
+ end
41
+ end
@@ -0,0 +1,40 @@
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 LesliGuard
35
+ class Role::Activity < ApplicationRecord
36
+
37
+ belongs_to :role
38
+
39
+ end
40
+ end
@@ -0,0 +1,74 @@
1
+ module LesliGuard
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 LesliGuard
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 LesliGuard
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 LesliGuard
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
+ LesliGuard::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
+ LesliGuard::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