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.
Files changed (153) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +38 -0
  3. data/app/assets/config/lesli_security_manifest.js +38 -0
  4. data/app/assets/images/lesli_security/security-logo.svg +57 -0
  5. data/app/assets/javascripts/lesli_security/application.js +5583 -0
  6. data/app/assets/stylesheets/lesli_security/application.css +95 -0
  7. data/app/controllers/lesli_security/accounts_controller.rb +60 -0
  8. data/app/controllers/lesli_security/application_controller.rb +37 -0
  9. data/app/controllers/lesli_security/dashboard/components_controller.rb +60 -0
  10. data/app/controllers/lesli_security/dashboards_controller.rb +36 -0
  11. data/app/controllers/lesli_security/descriptor/activities_controller.rb +122 -0
  12. data/app/controllers/lesli_security/descriptor/privileges_controller.rb +112 -0
  13. data/app/controllers/lesli_security/descriptors_controller.rb +129 -0
  14. data/app/controllers/lesli_security/role/activities_controller.rb +76 -0
  15. data/app/controllers/lesli_security/role/descriptors_controller.rb +97 -0
  16. data/app/controllers/lesli_security/role/privileges_controller.rb +47 -0
  17. data/app/controllers/lesli_security/roles_controller.rb +185 -0
  18. data/app/controllers/lesli_security/user/roles_controller.rb +98 -0
  19. data/app/controllers/lesli_security/user/sessions_controller.rb +71 -0
  20. data/app/controllers/lesli_security/users_controller.rb +206 -0
  21. data/app/helpers/lesli_security/accounts_helper.rb +4 -0
  22. data/app/helpers/lesli_security/application_helper.rb +4 -0
  23. data/app/helpers/lesli_security/dashboards_helper.rb +4 -0
  24. data/app/helpers/lesli_security/descriptor/activities_helper.rb +4 -0
  25. data/app/helpers/lesli_security/descriptor/privileges_helper.rb +4 -0
  26. data/app/helpers/lesli_security/descriptors_helper.rb +4 -0
  27. data/app/helpers/lesli_security/role/activities_helper.rb +4 -0
  28. data/app/helpers/lesli_security/role/descriptors_helper.rb +4 -0
  29. data/app/helpers/lesli_security/role/privileges_helper.rb +4 -0
  30. data/app/helpers/lesli_security/roles_helper.rb +4 -0
  31. data/app/jobs/lesli_security/application_job.rb +37 -0
  32. data/app/mailers/lesli_security/application_mailer.rb +39 -0
  33. data/app/models/lesli_security/account.rb +43 -0
  34. data/app/models/lesli_security/application_record.rb +37 -0
  35. data/app/models/lesli_security/dashboard/component.rb +42 -0
  36. data/app/models/lesli_security/dashboard.rb +58 -0
  37. data/app/models/lesli_security/descriptor/activity.rb +40 -0
  38. data/app/models/lesli_security/descriptor/privilege.rb +40 -0
  39. data/app/models/lesli_security/descriptor.rb +41 -0
  40. data/app/models/lesli_security/role/activity.rb +40 -0
  41. data/app/services/lesli_security/descriptor_privilege_service.rb +74 -0
  42. data/app/services/lesli_security/descriptor_service.rb +152 -0
  43. data/app/services/lesli_security/role_descriptor_service.rb +61 -0
  44. data/app/services/lesli_security/role_service.rb +215 -0
  45. data/app/services/lesli_security/user_service.rb +305 -0
  46. data/app/views/lesli_security/accounts/_account.html.erb +2 -0
  47. data/app/views/lesli_security/accounts/_form.html.erb +17 -0
  48. data/app/views/lesli_security/accounts/edit.html.erb +10 -0
  49. data/app/views/lesli_security/accounts/index.html.erb +14 -0
  50. data/app/views/lesli_security/accounts/new.html.erb +9 -0
  51. data/app/views/lesli_security/accounts/show.html.erb +10 -0
  52. data/app/views/lesli_security/dashboards/show.html.erb +1 -0
  53. data/app/views/lesli_security/descriptor/activities/_form.html.erb +32 -0
  54. data/app/views/lesli_security/descriptor/activities/edit.html.erb +34 -0
  55. data/app/views/lesli_security/descriptor/activities/index.html.erb +34 -0
  56. data/app/views/lesli_security/descriptor/activities/new.html.erb +34 -0
  57. data/app/views/lesli_security/descriptor/activities/show.html.erb +34 -0
  58. data/app/views/lesli_security/descriptor/privileges/_form.html.erb +32 -0
  59. data/app/views/lesli_security/descriptor/privileges/edit.html.erb +34 -0
  60. data/app/views/lesli_security/descriptor/privileges/index.html.erb +34 -0
  61. data/app/views/lesli_security/descriptor/privileges/new.html.erb +34 -0
  62. data/app/views/lesli_security/descriptor/privileges/show.html.erb +34 -0
  63. data/app/views/lesli_security/descriptors/_form.html.erb +32 -0
  64. data/app/views/lesli_security/descriptors/edit.html.erb +34 -0
  65. data/app/views/lesli_security/descriptors/index.html.erb +34 -0
  66. data/app/views/lesli_security/descriptors/new.html.erb +34 -0
  67. data/app/views/lesli_security/descriptors/show.html.erb +34 -0
  68. data/app/views/lesli_security/partials/_engine-navigation.html.erb +38 -0
  69. data/app/views/lesli_security/role/activities/_form.html.erb +32 -0
  70. data/app/views/lesli_security/role/activities/edit.html.erb +34 -0
  71. data/app/views/lesli_security/role/activities/index.html.erb +34 -0
  72. data/app/views/lesli_security/role/activities/new.html.erb +34 -0
  73. data/app/views/lesli_security/role/activities/show.html.erb +34 -0
  74. data/app/views/lesli_security/role/descriptors/_form.html.erb +32 -0
  75. data/app/views/lesli_security/role/descriptors/edit.html.erb +34 -0
  76. data/app/views/lesli_security/role/descriptors/index.html.erb +34 -0
  77. data/app/views/lesli_security/role/descriptors/new.html.erb +34 -0
  78. data/app/views/lesli_security/role/descriptors/show.html.erb +34 -0
  79. data/app/views/lesli_security/role/privileges/_form.html.erb +32 -0
  80. data/app/views/lesli_security/role/privileges/edit.html.erb +34 -0
  81. data/app/views/lesli_security/role/privileges/index.html.erb +34 -0
  82. data/app/views/lesli_security/role/privileges/new.html.erb +34 -0
  83. data/app/views/lesli_security/role/privileges/show.html.erb +34 -0
  84. data/app/views/lesli_security/roles/edit.html.erb +34 -0
  85. data/app/views/lesli_security/roles/index.html.erb +34 -0
  86. data/app/views/lesli_security/roles/new.html.erb +34 -0
  87. data/app/views/lesli_security/roles/show.html.erb +34 -0
  88. data/app/views/lesli_security/users/edit.html.erb +10 -0
  89. data/app/views/lesli_security/users/index.html.erb +34 -0
  90. data/app/views/lesli_security/users/new.html.erb +34 -0
  91. data/app/views/lesli_security/users/show.html.erb +1 -0
  92. data/config/locales/translations.en.yml +44 -0
  93. data/config/locales/translations.es.yml +44 -0
  94. data/config/locales/translations.fr.yml +44 -0
  95. data/config/locales/translations.it.yml +44 -0
  96. data/config/locales/translations.pt.yml +44 -0
  97. data/config/routes.rb +90 -0
  98. data/db/migrate/v1/0010000210_create_lesli_roles.rb +60 -0
  99. data/db/migrate/v1/0010000310_create_lesli_users.rb +97 -0
  100. data/db/migrate/v1/0010003010_create_lesli_user_details.rb +49 -0
  101. data/db/migrate/v1/0010003110_create_lesli_user_settings.rb +44 -0
  102. data/db/migrate/v1/0010003210_create_lesli_user_sessions.rb +55 -0
  103. data/db/migrate/v1/0010003410_create_lesli_user_powers.rb +43 -0
  104. data/db/migrate/v1/0010004010_create_lesli_user_logs.rb +45 -0
  105. data/db/migrate/v1/0010005010_create_lesli_descriptors.rb +44 -0
  106. data/db/migrate/v1/0010005110_create_lesli_descriptor_privileges.rb +45 -0
  107. data/db/migrate/v1/0010005210_create_lesli_descriptor_activities.rb +49 -0
  108. data/db/migrate/v1/0010005510_create_lesli_role_powers.rb +51 -0
  109. data/db/migrate/v1/0010005710_create_lesli_role_privileges.rb +45 -0
  110. data/db/migrate/v1/0802000110_create_lesli_security_accounts.rb +42 -0
  111. data/db/migrate/v1/0802050110_create_lesli_security_dashboards.rb +51 -0
  112. data/db/migrate/v1/0802050210_create_lesli_security_dashboard_components.rb +53 -0
  113. data/lib/lesli_security/engine.rb +18 -0
  114. data/lib/lesli_security/version.rb +4 -0
  115. data/lib/lesli_security.rb +6 -0
  116. data/lib/scss/application.scss +38 -0
  117. data/lib/scss/users.scss +67 -0
  118. data/lib/tasks/lesli_security_tasks.rake +50 -0
  119. data/lib/vue/application.js +112 -0
  120. data/lib/vue/apps/descriptors/components/form.vue +136 -0
  121. data/lib/vue/apps/descriptors/edit.vue +83 -0
  122. data/lib/vue/apps/descriptors/index.vue +113 -0
  123. data/lib/vue/apps/descriptors/new.vue +69 -0
  124. data/lib/vue/apps/descriptors/show.vue +233 -0
  125. data/lib/vue/apps/roles/components/descriptors.vue +81 -0
  126. data/lib/vue/apps/roles/components/form.vue +253 -0
  127. data/lib/vue/apps/roles/components/privilegeCustom.vue +86 -0
  128. data/lib/vue/apps/roles/components/privilegeStandard.vue +196 -0
  129. data/lib/vue/apps/roles/edit.vue +118 -0
  130. data/lib/vue/apps/roles/index.vue +168 -0
  131. data/lib/vue/apps/roles/logs.vue +110 -0
  132. data/lib/vue/apps/roles/new.vue +86 -0
  133. data/lib/vue/apps/roles/show.vue +109 -0
  134. data/lib/vue/apps/users/components/information-card.vue +104 -0
  135. data/lib/vue/apps/users/components/information-form.vue +176 -0
  136. data/lib/vue/apps/users/components/integrations-information.vue +61 -0
  137. data/lib/vue/apps/users/components/management-roles.vue +107 -0
  138. data/lib/vue/apps/users/components/management-security.vue +113 -0
  139. data/lib/vue/apps/users/components/management-sessions.vue +101 -0
  140. data/lib/vue/apps/users/components/management-settings.vue +93 -0
  141. data/lib/vue/apps/users/index.vue +207 -0
  142. data/lib/vue/apps/users/new.vue +181 -0
  143. data/lib/vue/apps/users/show.vue +131 -0
  144. data/lib/vue/stores/descriptor.js +117 -0
  145. data/lib/vue/stores/descriptors.js +156 -0
  146. data/lib/vue/stores/role.js +203 -0
  147. data/lib/vue/stores/roles.js +58 -0
  148. data/lib/vue/stores/translations.json +277 -0
  149. data/lib/vue/stores/user.js +331 -0
  150. data/lib/vue/stores/users.js +166 -0
  151. data/license +674 -0
  152. data/readme.md +76 -0
  153. 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