lesli 5.0.4 → 5.0.5

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/lesli/brand/app-logo2.svg +52 -0
  3. data/app/assets/javascripts/lesli/users/passwords.js +3 -3
  4. data/app/assets/javascripts/lesli/users/registrations.js +3 -3
  5. data/app/assets/javascripts/lesli/users/sessions.js +3 -3
  6. data/app/controllers/lesli/application_controller.rb +3 -3
  7. data/app/controllers/lesli/application_lesli_controller.rb +2 -2
  8. data/app/controllers/lesli/interfaces/application/authorization.rb +1 -1
  9. data/app/controllers/lesli/interfaces/application/requester.rb +1 -1
  10. data/app/controllers/lesli/shared/dashboards_controller.rb +308 -0
  11. data/app/controllers/users/confirmations_controller.rb +1 -1
  12. data/app/controllers/users/passwords_controller.rb +7 -10
  13. data/app/helpers/lesli/general_helper.rb +1 -1
  14. data/app/helpers/lesli/navigation_helper.rb +17 -16
  15. data/app/lib/lesli/system.rb +2 -1
  16. data/app/mailers/lesli/devise_mailer.rb +1 -1
  17. data/app/models/concerns/account_initializer.rb +9 -0
  18. data/app/models/lesli/account.rb +1 -0
  19. data/app/models/lesli/application_lesli_record.rb +1 -1
  20. data/app/models/lesli/shared/dashboard.rb +162 -0
  21. data/app/models/lesli/system_controller.rb +1 -0
  22. data/app/operators/lesli/controller_operator.rb +148 -0
  23. data/app/views/devise/passwords/new.html.erb +1 -1
  24. data/app/views/lesli/partials/_application-lesli-engines.html.erb +1 -1
  25. data/app/views/lesli/partials/_application-lesli-icons.html.erb +1 -1
  26. data/config/locales/translations.en.yml +17 -0
  27. data/config/locales/translations.es.yml +17 -0
  28. data/config/routes.rb +4 -2
  29. data/db/seed/development/users.rb +0 -1
  30. data/db/seeds.rb +16 -29
  31. data/lib/lesli/version.rb +1 -1
  32. data/lib/mailer_previews/devise_mailer_preview.rb +7 -0
  33. data/lib/sass/lesli/layouts/application-navbar.scss +1 -1
  34. data/lib/tasks/lesli/controllers.rake +1 -91
  35. data/lib/tasks/lesli/db.rake +36 -6
  36. data/lib/tasks/lesli/dev.rake +66 -0
  37. data/lib/tasks/lesli/engine.rake +59 -0
  38. data/lib/tasks/lesli/{role.rake → privileges.rake} +3 -3
  39. data/lib/tasks/lesli_tasks.rake +5 -0
  40. data/lib/vue/application.js +2 -1
  41. data/lib/vue/devise/passwords.js +8 -8
  42. data/lib/vue/devise/registrations.js +2 -2
  43. data/lib/vue/devise/sessions.js +11 -6
  44. data/lib/vue/layouts/application-header.vue +6 -1
  45. data/lib/vue/shared/dashboards/apps/edit.vue +215 -0
  46. data/lib/vue/{apps → shared}/dashboards/apps/index.vue +3 -5
  47. data/lib/vue/{apps → shared}/dashboards/apps/show.vue +26 -16
  48. data/lib/vue/{apps → shared}/dashboards/components/form.vue +31 -43
  49. data/lib/vue/shared/stores/dashboard.js +251 -0
  50. data/lib/vue/stores/translations.json +24 -72
  51. data/lib/vue/stores/{user.js → users.js} +1 -1
  52. data/lib/webpack/base.js +3 -2
  53. data/readme.md +1 -1
  54. metadata +46 -52
  55. data/lib/vue/apps/dashboards/apps/edit.vue +0 -105
  56. data/lib/vue/apps/dashboards/components/preview.vue +0 -172
  57. /data/app/assets/icons/lesli/{cloud-vault.svg → cloud-guard.svg} +0 -0
  58. /data/lib/vue/{apps → shared}/cloudobjects/action.vue +0 -0
  59. /data/lib/vue/{apps → shared}/cloudobjects/discussion/content.vue +0 -0
  60. /data/lib/vue/{apps → shared}/cloudobjects/discussion/element.vue +0 -0
  61. /data/lib/vue/{apps → shared}/cloudobjects/discussion/filters.vue +0 -0
  62. /data/lib/vue/{apps → shared}/cloudobjects/discussion/new.vue +0 -0
  63. /data/lib/vue/{apps → shared}/cloudobjects/discussion.vue +0 -0
  64. /data/lib/vue/{apps → shared}/cloudobjects/file/grid.vue +0 -0
  65. /data/lib/vue/{apps → shared}/cloudobjects/file/list.vue +0 -0
  66. /data/lib/vue/{apps → shared}/cloudobjects/file.vue +0 -0
  67. /data/lib/vue/{apps → shared}/dashboards/apps/new.vue +0 -0
  68. /data/lib/vue/{apps → shared}/workflows2/apps/actions/form.vue +0 -0
  69. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/chatroom-form.vue +0 -0
  70. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/cloud-object-clone-form.vue +0 -0
  71. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/cloud-object-file-form.vue +0 -0
  72. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/email-form.vue +0 -0
  73. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/notification-form.vue +0 -0
  74. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/send-cloud-object-file.vue +0 -0
  75. /data/lib/vue/{apps → shared}/workflows2/apps/actions/forms/task-form.vue +0 -0
  76. /data/lib/vue/{apps → shared}/workflows2/apps/actions/index.vue +0 -0
  77. /data/lib/vue/{apps → shared}/workflows2/apps/checks/form.vue +0 -0
  78. /data/lib/vue/{apps → shared}/workflows2/apps/checks/index.vue +0 -0
  79. /data/lib/vue/{apps → shared}/workflows2/apps/index.vue +0 -0
  80. /data/lib/vue/{apps → shared}/workflows2/apps/new.vue +0 -0
  81. /data/lib/vue/{apps → shared}/workflows2/apps/show.vue +0 -0
  82. /data/lib/vue/{apps → shared}/workflows2/components/associations.vue +0 -0
  83. /data/lib/vue/{apps → shared}/workflows2/components/chart.vue +0 -0
  84. /data/lib/vue/{apps → shared}/workflows2/components/workflow-form.vue +0 -0
  85. /data/lib/vue/{apps → shared}/workflows2/components/workflow-status-dropdown.vue +0 -0
@@ -0,0 +1,308 @@
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
+ =end
32
+ module Lesli
33
+ module Shared
34
+ class DashboardsController < ApplicationLesliController
35
+ before_action :set_dashboard, only: [:show, :update, :destroy, :options]
36
+
37
+ def index
38
+ respond_to do |format|
39
+ format.html {}
40
+ format.json do
41
+ dynamic_info = self.class.dynamic_info
42
+ model = dynamic_info[:model]
43
+
44
+ dashboards = model.list(current_user, @query)
45
+ respond_with_successful(dashboards)
46
+ end
47
+ end
48
+ end
49
+
50
+ def show
51
+ respond_to do |format|
52
+ format.html {}
53
+ format.json do
54
+ return respond_with_not_found unless @dashboard
55
+ respond_with_successful(@dashboard.show)
56
+ end
57
+ end
58
+ end
59
+
60
+ def new
61
+ end
62
+
63
+ def edit
64
+ end
65
+
66
+ # @controller_action_param :name [String] The name of the new dashboard
67
+ # @controller_action_param :default [Boolean] A flag that marks this dashboard as default or not. The default dashboard is the dashboard all users will have access to on the root page
68
+ # @controller_action_param :main [Boolean] A flag that marks this dashboard as main. Since a user can have multiple dashboards, this is the one they will see on the root page when loging in
69
+ # @controller_action_param :roles_id [Integer] The id of the role that will have access to this dashboard
70
+ # @controller_action_param :user_main_id [Integer] The id of the user
71
+ # @controller_action_param :component_attributes [Array] Array of hashes that represent the attributes of the dashboard components
72
+ # @controller_action_param :component_attributes.name [String] The name of this component given to the user
73
+ # @controller_action_param :component_attributes.component_id [String] An enum value, that indicates which component is being loaded
74
+ # @controller_action_param :component_attributes.layout [Integer] Number from 1 to 12, bigger numbers default to 12, smallest numbers default to 1. The column size that the UI component will use
75
+ # @controller_action_param :component_attributes.index [Integer] The position of the component in the layout
76
+ # @controller_action_param :component_attributes.configuration [Hash] Specific filtering and configuration of the components
77
+ # @return [Json] Json that contains wheter the creation of the dashboard was successful or not.
78
+ # If it is not successful, it returns an error message
79
+ # @description Creates a new dashboard associated to the *current_user*'s *account*
80
+ # @example
81
+ # # Executing this controller's action from javascript's frontend
82
+ # let data = {
83
+ # dashboard: {
84
+ # name: "Sales Dashboard",
85
+ # default: false,
86
+ # roles_id: 3,
87
+ # components_attributes: [
88
+ # {
89
+ # name: 'Projects Count',
90
+ # component_id: projects_component,
91
+ # layout: 4,
92
+ # index: 3,
93
+ # configuration: {}
94
+ # }, {
95
+ # name: 'New Customers Count',
96
+ # component_id: new_customers_component,
97
+ # layout: 4,
98
+ # index: 3,
99
+ # configuration: {}
100
+ # }
101
+ # ]
102
+ # }
103
+ # };
104
+ # this.http.post('127.0.0.1/help/dashboards', data);
105
+ def create
106
+ dynamic_info = self.class.dynamic_info
107
+ module_name = dynamic_info[:module_name]
108
+ model = dynamic_info[:model]
109
+ full_module_name = dynamic_info[:full_module_name].underscore
110
+
111
+ dashboard = model.new(dashboard_params)
112
+ dashboard["#{full_module_name}_account_id".to_sym] = current_user.account.id
113
+ dashboard.user_creator = current_user
114
+
115
+ if dashboard.save
116
+ respond_with_successful(dashboard)
117
+ else
118
+ respond_with_error(dashboard.errors.full_messages.to_sentence)
119
+ end
120
+ end
121
+
122
+ # @controller_action_param :name [String] The name of the new dashboard
123
+ # @controller_action_param :default [Boolean] A flag that marks this dashboard as default or not. The default dashboard is the dashboard all users will have access to on the root page
124
+ # @controller_action_param :main [Boolean] A flag that marks this dashboard as main. Since a user can have multiple dashboards, this is the one they will see on the root page when loging in
125
+ # @controller_action_param :roles_id [Integer] The id of the role that will have access to this dashboard
126
+ # @controller_action_param :user_main_id [Integer] The id of the user
127
+ # @controller_action_param :component_attributes [Array] Array of hashes that represent the attributes of the dashboard components
128
+ # @controller_action_param :component_attributes.name [String] The name of this component given to the user
129
+ # @controller_action_param :component_attributes.component_id [String] An enum value, that indicates which component is being loaded
130
+ # @controller_action_param :component_attributes.layout [Integer] Number from 1 to 12, bigger numbers default to 12, smallest numbers default to 1. The column size that the UI component will use
131
+ # @controller_action_param :component_attributes.index [Integer] The position of the component in the layout
132
+ # @controller_action_param :component_attributes.configuration [Hash] Specific filtering and configuration of the components
133
+ # @return [Json] Json that contains wheter the dashboard was successfully updated or not.
134
+ # If it it not successful, it returns an error message
135
+ # @description Updates an existing dashboard associated to the *current_user*'s *account*.
136
+ # @example
137
+ # # Executing this controller's action from javascript's frontend
138
+ # let dashboard_id = 4;
139
+ # let data = {
140
+ # dashboard: {
141
+ # name: "Sales Dashboard",
142
+ # default: false,
143
+ # roles_id: 3,
144
+ # components_attributes: [
145
+ # {
146
+ # name: 'Projects Count',
147
+ # component_id: projects_component,
148
+ # layout: 4,
149
+ # index: 3,
150
+ # configuration: {}
151
+ # }, {
152
+ # name: 'New Customers Count',
153
+ # component_id: new_customers_component,
154
+ # layout: 4,
155
+ # index: 3,
156
+ # configuration: {}
157
+ # }
158
+ # ]
159
+ # }
160
+ # };
161
+ # this.http.put(`127.0.0.1/help/dashboards/${dashboard_id}`, data);
162
+ def update
163
+ return respond_with_not_found unless @dashboard
164
+
165
+ if @dashboard.update(dashboard_params)
166
+ respond_with_successful(@dashboard.show)
167
+ else
168
+ respond_with_error(@dashboard.errors.full_messages.to_sentence)
169
+ end
170
+ end
171
+
172
+ # @return [Json] Json that contains wheter the dashboard was successfully deleted or not.
173
+ # If it it not successful, it returns an error message
174
+ # @description Deletes an existing *dashboard* associated to the *current_user*'s *account*.
175
+ # Since the dashboard has details, these are also deleted. However, if there
176
+ # is an existing *cloud_object* associated to the *dashboard*, it cannot be deleted
177
+ # @example
178
+ # # Executing this controller's action from javascript's frontend
179
+ # let dashboard_id = 4;
180
+ # this.http.delete(`127.0.0.1/help/dashboards/${dashboard_id}`);
181
+ def destroy
182
+ return respond_with_not_found unless @dashboard
183
+
184
+ if @dashboard.destroy
185
+ respond_with_successful
186
+ else
187
+ respond_with_error(@dashboard.errors.full_messages.to_sentence)
188
+ end
189
+ end
190
+
191
+ def options
192
+ dynamic_info = self.class.dynamic_info
193
+ model = dynamic_info[:module_model]
194
+
195
+ respond_with_successful(model.options(current_user, @query))
196
+ end
197
+
198
+ def resource_component
199
+ dynamic_info = self.class.dynamic_info
200
+ component_model = dynamic_info[:component_model]
201
+
202
+ component_id = sanitize(params[:component_id].to_sym)
203
+
204
+ # We verify if the method exists, and if it is in the available component list
205
+ if component_model.respond_to?(component_id) && component_model.component_ids[component_id]
206
+ respond_with_successful(component_model.public_send(component_id, current_user, @query))
207
+ else
208
+ respond_with_not_found()
209
+ end
210
+ end
211
+
212
+ private
213
+
214
+ # @return [void]
215
+ # @description Sets the variable @dashboard. The variable contains the *cloud_object* *dashboard*
216
+ # to be handled by the controller action that called this method
217
+ # @example
218
+ # #suppose params[:id] = 1
219
+ # puts @dashboard # will display nil
220
+ # set_dashboard
221
+ # puts @dashboard # will display an instance of CloudHelp:TicketDashboard
222
+ def set_dashboard
223
+ dynamic_info = self.class.dynamic_info
224
+
225
+ model = dynamic_info[:module_model]
226
+ module_name = dynamic_info[:module_name]
227
+ module_name_full = dynamic_info[:module_name_full].underscore
228
+
229
+ # When params[:id] is 'default' order of priority is:
230
+ # Main dashboard for user goes first
231
+ # Main dashboard for role goes second
232
+ # Default dashboard goes third
233
+ if params[:id] == "default"
234
+ # Main dashboard for user
235
+ @dashboard = model.find_by(
236
+ #"#{full_module_name}_account_id".to_sym => current_user.account.id,
237
+ account_id: current_user.account.id,
238
+ main: true,
239
+ #user_main_id: current_user.id
240
+ )
241
+
242
+ return if @dashboard
243
+
244
+ # Main dashboard for role
245
+ # @dashboard = model.find_by(
246
+ # :account_id => current_user.account.id,
247
+ # role_id: current_user.roles.first.id
248
+ # )
249
+ # return if @dashboard
250
+
251
+ # Default dashboard
252
+ @dashboard = model.find_by(
253
+ account_id: current_user.account.id,
254
+ default: true
255
+ )
256
+ else
257
+ @dashboard = model.find_by(
258
+ id: params[:id],
259
+ :account_id => current_user.account.id,
260
+ )
261
+ end
262
+ end
263
+
264
+ def dashboard_params
265
+ params.require(:dashboard).permit(
266
+ :name,
267
+ :default,
268
+ :roles_id,
269
+ components_attributes: [
270
+ :id,
271
+ :name,
272
+ :component_id,
273
+ :layout,
274
+ :index,
275
+ {query_configuration: {}},
276
+ {custom_configuration: {}},
277
+ :_destroy
278
+ ]
279
+ )
280
+ end
281
+
282
+ private
283
+
284
+ # Build the Rails models and engine information for
285
+ # the current engine implementing the shared dashboards
286
+ # Example: For the LesliAudit engine
287
+ # {
288
+ # :module_name => "audit",
289
+ # :module_name_full => "LesliAudit",
290
+ # :module_model => "LesliAudit::Dashboard",
291
+ # :module_model_component => "LesliAudit::Dashboard::Component"
292
+ # }
293
+ def self.dynamic_info
294
+
295
+ module_info = self.name.split("::")
296
+
297
+ module_name = module_info[0].sub("Lesli", "").downcase
298
+
299
+ {
300
+ module_name: module_name,
301
+ module_name_full: module_info[0],
302
+ module_model: "#{ module_info[0] }::Dashboard".constantize,
303
+ module_model_component: "#{ module_info[0] }::Dashboard::Component".constantize
304
+ }
305
+ end
306
+ end
307
+ end
308
+ end
@@ -25,7 +25,7 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
25
25
  # register a log with a validation atempt for the user
26
26
  log = user.logs.create({ description: "confirmation_atempt_successful" })
27
27
 
28
- registration_operator = Lesli::User::RegistrationOperator.new(user)
28
+ registration_operator = Lesli::UserRegistrationOperator.new(user)
29
29
 
30
30
  # confirm the user
31
31
  registration_operator.confirm
@@ -34,16 +34,13 @@ class Users::PasswordsController < Devise::PasswordsController
34
34
 
35
35
  #user.logs.create({ title: "password_creation_successful" })
36
36
 
37
- # begin
38
- # #UserMailer.with(user: user, token: token).reset_password_instructions.deliver_now
39
- #super()
40
- Lesli::DeviseMailer.reset_password_instructions(user, token)
41
- respond_with_successful
42
- # rescue => exception
43
- # #Honeybadger.notify(exception)
44
- # respond_with_error(exception.message)
45
- # end
46
-
37
+ begin
38
+ Lesli::DeviseMailer.reset_password_instructions(user, token).deliver_now
39
+ respond_with_successful
40
+ rescue => exception
41
+ #Honeybadger.notify(exception)
42
+ respond_with_error(exception.message)
43
+ end
47
44
  end
48
45
 
49
46
  def update
@@ -35,7 +35,7 @@ module Lesli
35
35
  module GeneralHelper
36
36
  # build a url path to change locales
37
37
  def language_url(locale)
38
- "/language?locale=#{locale}"
38
+ "/lesli/language?locale=#{locale}"
39
39
  end
40
40
 
41
41
  # return flag code according to locale code
@@ -32,6 +32,14 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  module Lesli
34
34
  module NavigationHelper
35
+
36
+ # Prints a separator line
37
+ def navigation_separator
38
+ content_tag(:li) do
39
+ content_tag(:hr)
40
+ end
41
+ end
42
+
35
43
  # Prints a html link inside a list item
36
44
  def navigation_item(path, label, icon = nil, reload: false)
37
45
  # default vue router links for single page applications
@@ -58,15 +66,9 @@ module Lesli
58
66
  end
59
67
  end
60
68
 
61
- # Prints a separator line
62
- def navigation_separator
63
- content_tag(:li) do
64
- content_tag(:hr)
65
- end
66
- end
67
-
68
69
  # 00.00 System administration
69
70
  def navigation_engine_admin(title: "Administration", subtitle: "Users, privileges, access roles.")
71
+ return unless defined? LesliAdmin
70
72
  navigation_engine_item(title, subtitle, "admin", lesli_admin.root_path, controller_path.include?("lesli_admin"))
71
73
  end
72
74
 
@@ -243,10 +245,10 @@ module Lesli
243
245
 
244
246
  # 07.02 Help engine
245
247
  def navigation_engine_help(title: "Help", subtitle: "Support Ticket System")
246
- return unless defined? CloudHelp
248
+ return unless defined? LesliHelp
247
249
 
248
- navigation_engine_item(title, subtitle, "help", cloud_help.root_path,
249
- controller_path.include?("cloud_help"))
250
+ navigation_engine_item(title, subtitle, "help", lesli_help.root_path,
251
+ controller_path.include?("lesli_help"))
250
252
  end
251
253
 
252
254
  # 07.03 Portal engine
@@ -267,12 +269,11 @@ module Lesli
267
269
 
268
270
  # SECURITY & PRIVACY
269
271
 
270
- # 08.01 Vault engine
271
- def navigation_engine_vault(title: "Vault", subtitle: "")
272
- return unless defined? LesliVault
273
-
274
- navigation_engine_item(title, subtitle, "vault", lesli_vault.root_path,
275
- controller_path.include?("lesli_vault"))
272
+ # 08.01 Guard engine
273
+ def navigation_engine_guard(title: "Guard", subtitle: "Users, privileges and access roles.")
274
+ return unless defined? LesliGuard
275
+ navigation_engine_item(title, subtitle, "guard", lesli_guard.root_path,
276
+ controller_path.include?("lesli_guard"))
276
277
  end
277
278
 
278
279
  # 08.03 Audit engine
@@ -88,7 +88,8 @@ module Lesli
88
88
  "LesliAudit",
89
89
  "LesliBell",
90
90
  "LesliDriver",
91
- "LesliVault"
91
+ "LesliGuard",
92
+ "LesliHelp"
92
93
  ]
93
94
  end
94
95
  end
@@ -17,7 +17,7 @@ module Lesli
17
17
  }
18
18
 
19
19
  # send email
20
- email(
20
+ pp email(
21
21
  params,
22
22
  to: user.email,
23
23
  subject: email_subject,
@@ -79,6 +79,15 @@ module AccountInitializer
79
79
  end
80
80
  end
81
81
 
82
+ # 07.02 LesliHelp - Support Ticket System
83
+ if defined? LesliHelp
84
+ if self.help.blank?
85
+ self.help = LesliHelp::Account.new
86
+ self.help.account = self
87
+ self.help.save!
88
+ end
89
+ end
90
+
82
91
  # 08.03 LesliAudit - System analytics
83
92
  if defined? LesliAudit
84
93
  if self.audit.blank?
@@ -54,6 +54,7 @@ module Lesli
54
54
  has_many :currencies
55
55
  has_many :logs
56
56
 
57
+ has_one :help, class_name: "LesliHelp::Account"
57
58
  has_one :audit, class_name: "LesliAudit::Account"
58
59
  has_one :admin, class_name: "LesliAdmin::Account"
59
60
  has_one :driver, class_name: "LesliDriver::Account"
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- class ApplicationLesliRecord < ApplicationRecord
34
+ class ApplicationLesliRecord < ActiveRecord::Base
35
35
  self.abstract_class = true
36
36
  acts_as_paranoid
37
37
  end
@@ -0,0 +1,162 @@
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 · Your Smart Business Assistant.
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://lesli.tech
27
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
+
29
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // ·
31
+
32
+ =end
33
+
34
+ module Lesli
35
+ module Shared
36
+ class Dashboard < ::Lesli::ApplicationLesliRecord
37
+ self.abstract_class = true
38
+
39
+ belongs_to :user_creator, class_name: "User", foreign_key: "users_id", optional: true
40
+
41
+ after_update :verify_default_dashboard
42
+ after_create :verify_default_dashboard
43
+
44
+ enum component_ids: {}
45
+
46
+ # @return [void]
47
+ # @param account [LesliEngine::Account]
48
+ # @description Initializes a default dummy dashboard for the account. This guarantees that the users
49
+ # will be able to access the dashboard page. Even if it's empty.
50
+ # @example
51
+ # # Imagine you are adding a new engine to your instance (CloudProposal)
52
+ # # To execute this function, you must only do
53
+ # my_account = Account.first
54
+ # my_account.proposal = CloudProposal::Account.new
55
+ def self.initialize_data(account)
56
+ self.create!(
57
+ account: account,
58
+ name: "Default Dashboard",
59
+ default: true,
60
+ main: false
61
+ )
62
+ end
63
+
64
+ # @return [Hash] Hash of containing the information of the dashboard and its components.
65
+ # @description Returns a hash with information about the dashboard and all its *components*.
66
+ # Each component is returned in the configuration view, not the render view. This means that
67
+ # this method is ment to be used when updating the dashboard
68
+ # @example
69
+ # respond_with_successful(CloudHelp::Dashboard.first.show)
70
+ def show
71
+ attributes.merge({
72
+ components: components.order(index: :asc)
73
+ # components: [{
74
+ # name: "ticket",
75
+ # component_id: "ticket"
76
+ # },{
77
+ # name: "ticket",
78
+ # component_id: "ticket"
79
+ # }]
80
+ })
81
+ end
82
+
83
+ # @return [Hash] Hash containing the options to create and manage dashboards
84
+ # @param current_user [User] The user that made this request
85
+ # @param query [Hash] Query containing filters. Currently unused, but required
86
+ # @descriptions Returns a list of options needed to create and manage dashboard components. For now,
87
+ # the returned options are: A list of roles, the enoun containing the component_ids, generic configuration options
88
+ # for all dashboad components and a descriptions hash, that contains brief descriptions for each component to help
89
+ # the user understand what each component does. Any class that inherits from this one can send a block to add extra
90
+ # functionality. For example, the descriptions must be implemented directly from the engine.
91
+ # @example
92
+ # CloudHouse::Dashboard.options(User.find(2), nil)
93
+ def self.options(current_user, query)
94
+ dynamic_info = self.dynamic_info
95
+ component_model = dynamic_info[:module_model_component]
96
+
97
+ component_ids = component_model.component_ids.map do |comp|
98
+ {
99
+ value: comp,
100
+ text: comp
101
+ }
102
+ end
103
+
104
+ options = {
105
+ component_ids: component_ids,
106
+ #components_configuration_options: component_model.configuration_options,
107
+ descriptions: {}
108
+ }
109
+
110
+ if block_given?
111
+ yield(options)
112
+ else
113
+ return options
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ # @return [void]
120
+ # @descriptions This is an after_updated and after_create method that validates that at any moment in time, there is only
121
+ # one default dashboard in the engine. If there is another default dashboard, it's *default* field is set to false
122
+ # before committing the changes
123
+ # @example
124
+ # CloudFocus::Dasbhoard.where(default: false).first.update!(default: true)
125
+ # # This will automatically trigger this function and remove the *default* field from the old default dashboard
126
+ def verify_default_dashboard
127
+ if default
128
+ dashboards = self.class.where.not(id: id).where(account: account)
129
+ self.class.where.not(id: id).where(account: account).update_all(default: false)
130
+ end
131
+
132
+ unless self.class.where(account: account).find_by(default: true)
133
+ errors.add(:base, I18n.t("core.dashboards.messages_danger_default_dashboard_must_exist"))
134
+ raise ActiveRecord::Rollback
135
+ end
136
+ end
137
+
138
+ # Build the Rails models and engine information for
139
+ # the current engine implementing the shared dashboards
140
+ # Example: For the LesliAudit engine
141
+ # {
142
+ # :module_name => "audit",
143
+ # :module_name_full => "LesliAudit",
144
+ # :module_model => "LesliAudit::Dashboard",
145
+ # :module_model_component => "LesliAudit::Dashboard::Component"
146
+ # }
147
+ def self.dynamic_info
148
+
149
+ module_info = self.name.split("::")
150
+
151
+ module_name = module_info[0].sub("Lesli", "").downcase
152
+
153
+ {
154
+ module_name: module_name,
155
+ module_name_full: module_info[0],
156
+ module_model: "#{ module_info[0] }::Dashboard".constantize,
157
+ module_model_component: "#{ module_info[0] }::Dashboard::Component".constantize
158
+ }
159
+ end
160
+ end
161
+ end
162
+ end
@@ -85,6 +85,7 @@ module Lesli
85
85
  cc[engine][controller] = {
86
86
  id: c[:controller_id],
87
87
  name: c[:controller_name],
88
+ route: c[:route],
88
89
  actions: []
89
90
  }
90
91
  end