lesli 5.0.11 → 5.0.12

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 (152) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/lesli_manifest.js +0 -13
  3. data/app/assets/icons/lesli/engine-security.svg +1 -0
  4. data/app/assets/icons/lesli/engine-shield.svg +1 -0
  5. data/app/assets/images/lesli/lesli-logo.svg +4 -0
  6. data/app/assets/stylesheets/lesli/templates/application.css +21862 -209
  7. data/app/assets/stylesheets/lesli/templates/public.css +19098 -1
  8. data/app/assets/stylesheets/lesli/users/confirmations.css +19219 -0
  9. data/app/assets/stylesheets/lesli/users/passwords.css +19202 -0
  10. data/app/assets/stylesheets/lesli/users/registrations.css +19594 -0
  11. data/app/assets/stylesheets/lesli/users/sessions.css +19594 -1
  12. data/app/controllers/lesli/abouts_controller.rb +12 -18
  13. data/app/controllers/lesli/application_controller.rb +25 -25
  14. data/app/controllers/lesli/application_lesli_controller.rb +5 -6
  15. data/app/controllers/lesli/interfaces/application/authorization.rb +1 -1
  16. data/app/controllers/lesli/interfaces/application/customization.rb +1 -1
  17. data/app/controllers/lesli/interfaces/application/requester.rb +2 -2
  18. data/app/controllers/lesli/interfaces/application/responder.rb +8 -8
  19. data/app/controllers/lesli/interfaces/controllers/actions.rb +250 -0
  20. data/app/controllers/lesli/interfaces/controllers/activities.rb +215 -0
  21. data/app/controllers/lesli/interfaces/controllers/discussions.rb +270 -0
  22. data/app/controllers/lesli/interfaces/controllers/files.rb +467 -0
  23. data/app/controllers/lesli/interfaces/controllers/subscribers.rb +234 -0
  24. data/app/helpers/lesli/assets_helper.rb +4 -4
  25. data/app/helpers/lesli/navigation_helper.rb +38 -81
  26. data/app/lib/lesli/system.rb +4 -3
  27. data/app/models/concerns/account_initializer.rb +46 -42
  28. data/{lib/scss/devise/registrations.scss → app/models/lesli/account/detail.rb} +7 -3
  29. data/app/models/lesli/account.rb +12 -5
  30. data/app/models/lesli/cloud_object/action.rb +70 -0
  31. data/app/models/lesli/cloud_object/activity.rb +311 -0
  32. data/app/models/lesli/cloud_object/custom_field.rb +158 -0
  33. data/app/models/lesli/cloud_object/discussion.rb +219 -0
  34. data/app/models/lesli/cloud_object/subscriber.rb +186 -0
  35. data/app/models/lesli/shared/dashboard.rb +16 -5
  36. data/app/models/lesli/user/session.rb +0 -2
  37. data/app/models/lesli/user.rb +13 -13
  38. data/app/operators/lesli/user_registration_operator.rb +3 -3
  39. data/app/views/lesli/layouts/application-devise.html.erb +6 -6
  40. data/app/views/lesli/layouts/application-lesli.html.erb +1 -1
  41. data/app/views/lesli/partials/_application-data.html.erb +2 -1
  42. data/app/views/lesli/partials/_application-lesli-engines.html.erb +14 -39
  43. data/app/views/lesli/partials/_application-lesli-header.html.erb +4 -4
  44. data/app/views/lesli/partials/_application-lesli-icons.html.erb +1 -1
  45. data/app/views/lesli/partials/_application-lesli-panels.html.erb +7 -7
  46. data/app/views/lesli/wrappers/_application-devise.html.erb +5 -7
  47. data/config/initializers/devise.rb +335 -335
  48. data/config/initializers/lesli.rb +2 -1
  49. data/config/locales/translations.en.yml +4 -0
  50. data/config/locales/translations.es.yml +4 -0
  51. data/config/locales/translations.fr.yml +28 -0
  52. data/config/locales/translations.it.yml +28 -0
  53. data/config/locales/translations.pt.yml +28 -0
  54. data/config/routes.rb +1 -10
  55. data/db/migrate/{v1.0/0010003010_create_lesli_user_details.rb → v1/0010000110_create_lesli_accounts.rb} +19 -13
  56. data/db/migrate/{v1.0/0010000110_create_lesli_accounts.rb → v1/0010001010_create_lesli_account_details.rb} +5 -7
  57. data/db/migrate/{v1.0/0010001010_create_lesli_account_settings.rb → v1/0010001110_create_lesli_account_settings.rb} +2 -2
  58. data/db/seed/development/accounts.rb +10 -7
  59. data/db/seed/development/users.rb +20 -20
  60. data/db/seed/production/accounts.rb +10 -7
  61. data/lib/lesli/engine.rb +2 -12
  62. data/lib/lesli/version.rb +2 -2
  63. data/lib/lesli.rb +0 -1
  64. data/lib/scss/cloud-objects/discussion.scss +8 -5
  65. data/lib/scss/layouts/application-header.scss +3 -1
  66. data/lib/scss/layouts/application-navbar.scss +2 -1
  67. data/lib/scss/{elements/msg.scss → overrides/notification.scss} +16 -18
  68. data/lib/scss/pages/devise-simple.scss +4 -2
  69. data/lib/scss/pages/devise.scss +111 -107
  70. data/lib/scss/panels/panel-notification.scss +1 -1
  71. data/lib/scss/panels/{panel-ticket.scss → panel-support-ticket.scss} +3 -4
  72. data/lib/scss/templates/application.scss +7 -5
  73. data/lib/tasks/lesli/controllers.rake +1 -1
  74. data/lib/tasks/lesli/db.rake +24 -12
  75. data/lib/tasks/lesli_tasks.rake +6 -6
  76. data/lib/vue/application.js +13 -12
  77. data/lib/vue/{refactor/shared/cloudobjects → cloudobjects}/discussion/content.vue +10 -8
  78. data/lib/vue/cloudobjects/discussion/element.vue +170 -0
  79. data/lib/vue/{refactor/shared/cloudobjects → cloudobjects}/discussion/filters.vue +1 -1
  80. data/lib/vue/{refactor/shared/cloudobjects → cloudobjects}/discussion/new.vue +20 -16
  81. data/lib/vue/{refactor/shared/cloudobjects → cloudobjects}/discussion.vue +25 -24
  82. data/lib/vue/{refactor/stores/cloudobjects → cloudobjects/stores}/discussion.js +7 -16
  83. data/lib/vue/layouts/application-header.vue +5 -5
  84. data/lib/vue/panels/{panel-notifications.vue → panel-bell-notifications.vue} +15 -19
  85. data/lib/vue/panels/panel-support-tickets.vue +161 -0
  86. data/lib/vue/panels/stores/bell-notifications.js +46 -0
  87. data/lib/vue/panels/stores/support-tickets.js +103 -0
  88. data/lib/vue/shared/dashboards/apps/edit.vue +10 -10
  89. data/lib/vue/shared/dashboards/components/form.vue +31 -40
  90. data/lib/vue/shared/stores/dashboard.js +2 -0
  91. data/lib/vue/shared/stores/layout.js +2 -1
  92. data/lib/{scss/devise/confirmations.scss → vue/shared/stores/users.js} +22 -21
  93. data/lib/vue/stores/translations.json +109 -2
  94. data/lib/webpack/base.js +9 -8
  95. data/lib/webpack/core.js +8 -6
  96. data/readme.md +16 -15
  97. metadata +49 -76
  98. data/app/assets/icons/lesli/engine-guard.svg +0 -1
  99. data/app/assets/javascripts/lesli/users/sessions.js +0 -1
  100. data/app/controllers/users/confirmations_controller.rb +0 -66
  101. data/app/controllers/users/omniauth_callbacks_controller.rb +0 -30
  102. data/app/controllers/users/passwords_controller.rb +0 -71
  103. data/app/controllers/users/registrations_controller.rb +0 -141
  104. data/app/controllers/users/sessions_controller.rb +0 -141
  105. data/app/controllers/users/unlocks_controller.rb +0 -30
  106. data/app/views/devise/confirmations/new.html.erb +0 -2
  107. data/app/views/devise/confirmations/show.html.erb +0 -63
  108. data/app/views/devise/mailer/confirmation_instructions.html.erb +0 -5
  109. data/app/views/devise/mailer/email_changed.html.erb +0 -7
  110. data/app/views/devise/mailer/password_change.html.erb +0 -3
  111. data/app/views/devise/mailer/reset_password_instructions.html.erb +0 -8
  112. data/app/views/devise/mailer/unlock_instructions.html.erb +0 -7
  113. data/app/views/devise/passwords/edit.html.erb +0 -79
  114. data/app/views/devise/passwords/new.html.erb +0 -75
  115. data/app/views/devise/registrations/edit.html.erb +0 -43
  116. data/app/views/devise/registrations/new.html.erb +0 -147
  117. data/app/views/devise/sessions/new.html.erb +0 -114
  118. data/app/views/devise/shared/_demo.html.erb +0 -7
  119. data/app/views/devise/shared/_error_messages.html.erb +0 -15
  120. data/app/views/devise/shared/_links.html.erb +0 -96
  121. data/app/views/devise/unlocks/new.html.erb +0 -16
  122. data/db/migrate/v1.0/0010000210_create_lesli_roles.rb +0 -59
  123. data/db/migrate/v1.0/0010000310_create_lesli_users.rb +0 -97
  124. data/db/migrate/v1.0/0010003110_create_lesli_user_settings.rb +0 -44
  125. data/db/migrate/v1.0/0010003210_create_lesli_user_sessions.rb +0 -55
  126. data/db/migrate/v1.0/0010003410_create_lesli_user_powers.rb +0 -43
  127. data/db/migrate/v1.0/0010004010_create_lesli_user_logs.rb +0 -45
  128. data/db/migrate/v1.0/0010005010_create_lesli_descriptors.rb +0 -44
  129. data/db/migrate/v1.0/0010005110_create_lesli_descriptor_privileges.rb +0 -45
  130. data/db/migrate/v1.0/0010005210_create_lesli_descriptor_activities.rb +0 -49
  131. data/db/migrate/v1.0/0010005510_create_lesli_role_powers.rb +0 -51
  132. data/db/migrate/v1.0/0010005710_create_lesli_role_privileges.rb +0 -45
  133. data/lib/lesli/routing.rb +0 -26
  134. data/lib/scss/components/editor-richtext.scss +0 -88
  135. data/lib/scss/devise/oauth.scss +0 -34
  136. data/lib/scss/devise/passwords.scss +0 -33
  137. data/lib/scss/devise/sessions.scss +0 -35
  138. data/lib/scss/elements/avatar.scss +0 -48
  139. data/lib/scss/elements/calendar.scss +0 -47
  140. data/lib/scss/elements/toggle.scss +0 -102
  141. data/lib/vue/devise/confirmations.js +0 -33
  142. data/lib/vue/devise/passwords.js +0 -137
  143. data/lib/vue/devise/registrations.js +0 -157
  144. data/lib/vue/devise/sessions.js +0 -148
  145. data/lib/vue/panels/panel-tickets.vue +0 -181
  146. data/lib/vue/refactor/shared/cloudobjects/discussion/element.vue +0 -132
  147. data/lib/vue/shared/stores/account.js +0 -113
  148. /data/app/assets/icons/lesli/{engine-driver.svg → engine-calendar.svg} +0 -0
  149. /data/db/migrate/{v1.0 → v1}/0010000610_create_lesli_system_controllers.rb +0 -0
  150. /data/db/migrate/{v1.0 → v1}/0010000710_create_lesli_system_controller_actions.rb +0 -0
  151. /data/db/migrate/{v1.0 → v1}/0010001210_create_lesli_account_activities.rb +0 -0
  152. /data/db/migrate/{v1.0 → v1}/0010001410_create_lesli_account_logs.rb +0 -0
@@ -35,28 +35,22 @@ module Lesli
35
35
 
36
36
  # GET /status
37
37
  def show
38
- # instance name from builder
39
- instance = Lesli.config.instance
40
-
41
- # get installed engines
42
- @lesli_engines = Lesli::System.engines.map { |engine, engine_info|
43
- {
44
- :name => engine_info[:name],
45
- :code => engine_info[:code],
46
- :path => engine_info[:path],
47
- :version => engine_info[:version],
48
- :build => engine_info[:build]
49
- }
50
- }
51
-
52
38
  respond_to do |format|
53
39
  format.html {}
54
40
  format.json {
55
41
  if Rails.env.production?
56
- respond_with_successful({ :Lesli => "Ruby on Rails SaaS Development Framework."})
57
- end
58
-
59
- if !Rails.env.production?
42
+ respond_with_successful({ :Lesli => "Ruby on Rails SaaS Development Framework." })
43
+ else
44
+ # get installed engines
45
+ @lesli_engines = Lesli::System.engines.map { |engine, engine_info|
46
+ {
47
+ :name => engine_info[:name],
48
+ :code => engine_info[:code],
49
+ :path => engine_info[:path],
50
+ :build => engine_info[:build],
51
+ :version => engine_info[:version]
52
+ }
53
+ }
60
54
  respond_with_successful(@lesli_engines)
61
55
  end
62
56
  }
@@ -71,38 +71,38 @@ module Lesli
71
71
  # })
72
72
  end
73
73
 
74
- # Set the user language based on url configuration or browser/os default language (ready for public pages)
75
- def set_locale
76
- # language defined in the http header request
77
- locale = request.headers["Require-Language"] unless request.headers["Require-Language"].blank?
74
+ # # Set the user language based on url configuration or browser/os default language (ready for public pages)
75
+ # def set_locale
76
+ # # language defined in the http header request
77
+ # locale = request.headers["Require-Language"] unless request.headers["Require-Language"].blank?
78
78
 
79
- # use locale defined in the url
80
- locale = params[:locale] if locale.blank?
79
+ # # use locale defined in the url
80
+ # locale = params[:locale] if locale.blank?
81
81
 
82
- # use the language from the browser/os
83
- locale = browser_locale if locale.blank?
82
+ # # use the language from the browser/os
83
+ # locale = browser_locale if locale.blank?
84
84
 
85
- # use the default locale if no custom locale was found
86
- return I18n.locale = I18n.default_locale if locale.blank?
85
+ # # use the default locale if no custom locale was found
86
+ # return I18n.locale = I18n.default_locale if locale.blank?
87
87
 
88
- # use default locale if requested language is not supported
89
- return I18n.locale = I18n.default_locale unless I18n.available_locales.include?(locale.to_sym)
88
+ # # use default locale if requested language is not supported
89
+ # return I18n.locale = I18n.default_locale unless I18n.available_locales.include?(locale.to_sym)
90
90
 
91
- # set the new locale
92
- I18n.locale = locale
93
- end
91
+ # # set the new locale
92
+ # I18n.locale = locale
93
+ # end
94
94
 
95
- protected
95
+ # protected
96
96
 
97
- def browser_locale
98
- # get user's preferred language from browser
99
- user_browser_locale = request.headers["HTTP_ACCEPT_LANGUAGE"] || request.headers["Accept-Language"] || ""
97
+ # def browser_locale
98
+ # # get user's preferred language from browser
99
+ # user_browser_locale = request.headers["HTTP_ACCEPT_LANGUAGE"] || request.headers["Accept-Language"] || ""
100
100
 
101
- # extract locale from accept language header
102
- user_browser_locale.scan(/^[a-z]{2}/).find do |locale|
103
- # validate if browser language is in the list of supported languages
104
- I18n.available_locales.include?(locale.to_sym)
105
- end
106
- end
101
+ # # extract locale from accept language header
102
+ # user_browser_locale.scan(/^[a-z]{2}/).find do |locale|
103
+ # # validate if browser language is in the list of supported languages
104
+ # I18n.available_locales.include?(locale.to_sym)
105
+ # end
106
+ # end
107
107
  end
108
108
  end
@@ -42,12 +42,11 @@ module Lesli
42
42
 
43
43
  before_action :set_path
44
44
  before_action :set_locale
45
- before_action :authorize_request
46
- before_action :authorize_privileges
47
- before_action :set_helpers_for_request
48
- before_action :set_customization
49
-
50
- after_action :log_requests
45
+ before_action :authorize_request if defined?(LesliShield)
46
+ before_action :authorize_privilege if defined?(LesliSecurity)
47
+ before_action :set_customizer
48
+ before_action :set_requester
49
+ after_action :log_requests if defined?(LesliAudit)
51
50
 
52
51
  layout "lesli/layouts/application-lesli"
53
52
 
@@ -68,7 +68,7 @@ module Lesli
68
68
  # Check if current_user has privileges to complete this request
69
69
  # allowed core methods:
70
70
  # [:index, :create, :update, :destroy, :new, :show, :edit, :options, :search, :resources]
71
- def authorize_privileges
71
+ def authorize_privilege
72
72
 
73
73
  # check if user has access to the requested controller
74
74
  # this search is over all the privileges for all the roles of the user
@@ -4,7 +4,7 @@ module Lesli
4
4
  module Customization
5
5
 
6
6
  # set customization only for lesli_cloud instance
7
- def set_customization
7
+ def set_customizer
8
8
  =begin
9
9
  # @account is only for html and pdf requests
10
10
  return unless request.format.html? || request.format.pdf?
@@ -65,11 +65,11 @@ module Lesli
65
65
  end
66
66
 
67
67
  # Set default query params for:
68
- def set_helpers_for_request
68
+ def set_requester
69
69
  @query = {
70
70
  search: params[:search] || nil,
71
71
  pagination: {
72
- perPage: (params[:perPage] ? params[:perPage].to_i : 10),
72
+ perPage: (params[:perPage] ? params[:perPage].to_i : 12),
73
73
  page: (params[:page] ? params[:page].to_i : 1)
74
74
  },
75
75
  order: {
@@ -52,14 +52,14 @@ module Lesli
52
52
  # to make this work properly
53
53
  def respond_with_pagination(records, payload = nil)
54
54
  respond_with_http(200, {
55
- pagination: {
56
- page: records.current_page,
57
- pages: records.total_pages,
58
- total: records.total_count,
59
- results: records.length
60
- },
61
- records: payload || records
62
- })
55
+ pagination: {
56
+ page: records.current_page,
57
+ pages: records.total_pages,
58
+ total: records.total_count,
59
+ results: records.length
60
+ },
61
+ records: payload || records
62
+ })
63
63
  end
64
64
 
65
65
  # JSON not found response
@@ -0,0 +1,250 @@
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
+ module Lesli
34
+ module Interfaces
35
+ module Controllers
36
+ module Actions
37
+
38
+ # @return [Json] Json that contains a list of all actions related to a *cloud_object*
39
+ # @description Retrieves and returns all actions associated to a *cloud_object*. The id of the
40
+ # *cloud_object* is within the *params* attribute. If the child class provides a block, the function is
41
+ # yielded sending the actions as parameters. The block given *must* return the HTTP response
42
+ # @example
43
+ # # Executing this controller's action from javascript's frontend
44
+ # let ticket_id = 1;
45
+ # this.http.get(`127.0.0.1/help/tickets/${ticket_id}/actions`);
46
+ def index
47
+ set_cloud_object()
48
+ action_model = action_model() # If there is a custom action model, it must be returned in this method
49
+ cloud_object_model = action_model.cloud_object_model
50
+
51
+ @actions = action_model.index(current_user, @cloud_object)
52
+ if block_given?
53
+ yield(@actions)
54
+ else
55
+ respond_with_successful(@actions)
56
+ end
57
+ end
58
+
59
+ # @return [JSON] The json information about the selected action
60
+ # @description Retrieves and returns the information about the action. The id of the
61
+ # *cloud_object* and the id of the *action* are within the *params* attribute. If a block
62
+ # is provided, the execution will be yielded sending the action as first parameter
63
+ # @example
64
+ # # Executing this controller's action from javascript's frontend
65
+ # let ticket_id = 1;
66
+ # let action_id = 5;
67
+ # this.http.get(`127.0.0.1/help/tickets/${ticket_id}/actions/${action_id}`);
68
+ def show
69
+ set_action
70
+ return respond_with_not_found unless @action
71
+
72
+ if block_given?
73
+ yield(@action)
74
+ else
75
+ return respond_with_successful(@action)
76
+ end
77
+ end
78
+
79
+ # @controller_action_param :content [String] The commented message
80
+ # @controller_action_param :actions_id [Integer] The id of a actions that this message responds to
81
+ # @return [Json] Json that contains wheter the creation of the action was successful or not.
82
+ # If it is not successful, it returs an error message
83
+ # @description Creates a new action associated to a *cloud_object* and notifies all users subscribed to this event.
84
+ # The id of the *cloud_object* is within the *params* attribute
85
+ # @example
86
+ # # Executing this controller's action from javascript's frontend
87
+ # let ticket_id = 1;
88
+ # let data = {
89
+ # ticket_action: {
90
+ # content: "This is a comment on a ticket!"
91
+ # }
92
+ # };
93
+ # this.http.post(`127.0.0.1/help/tickets/${ticket_id}/actions`, data);
94
+ def create
95
+ action_model = action_model() # If there is a custom action model, it must be returned in this method
96
+ cloud_object_model = action_model.cloud_object_model
97
+
98
+ set_cloud_object
99
+ new_action_params = action_params.merge(
100
+ user_creator: current_user
101
+ )
102
+
103
+ action = @cloud_object.actions.new(new_action_params)
104
+ if action.save
105
+ if block_given?
106
+ yield(cloud_object, action)
107
+ else
108
+ respond_with_successful(action.show(current_user))
109
+ end
110
+ else
111
+ respond_with_error(action.errors.full_messages)
112
+ end
113
+ end
114
+
115
+ # @controller_action_param :content [String] The content of the action
116
+ # @controller_action_param :actions_id [Integer] The id of a actions that this message responds to
117
+ # @return [Json] Json that contains wheter the update of the action was successful or not.
118
+ # If it is not successful, it returs an error message
119
+ # @description Updates the action based on the id of the *cloud_object* and its own id.
120
+ # @example
121
+ # # Executing this controller's action from javascript's frontend
122
+ # let ticket_id = 1;
123
+ # let action_id = 22;
124
+ # data = {
125
+ # action: {
126
+ # content: "This is the new content of the action"
127
+ # }
128
+ # };
129
+ # this.http.patch(`127.0.0.1/help/tickets/${ticket_id}/actions/${action_id}`, data);
130
+ def update
131
+ set_action
132
+ return respond_with_not_found unless @action
133
+ return respond_with_unauthorized unless @action.is_editable_by?(current_user)
134
+
135
+ if @action.update(action_params)
136
+ respond_with_successful(@action.show(current_user))
137
+ else
138
+ respond_with_error(@action.errors.full_messages.to_sentence)
139
+ end
140
+ end
141
+
142
+ # @return [Json] A response that contains wheter the action was deleted or not.
143
+ # If it is not successful, it returns an error message
144
+ # @description Deletes a action from the database based on the id of the *cloud_object* and its own id.
145
+ # @example
146
+ # # Executing this controller's action from javascript's frontend
147
+ # let ticket_id = 1;
148
+ # let action_id = 22;
149
+ # this.http.delete(`127.0.0.1/help/tickets/${ticket_id}/actions/${action_id}`);
150
+ def destroy
151
+ set_action
152
+ return respond_with_not_found unless @action
153
+
154
+ if @action.destroy
155
+ respond_with_successful
156
+ else
157
+ respond_with_error(@action.errors.full_messages.to_sentence)
158
+ end
159
+ end
160
+
161
+ protected
162
+
163
+ # @return [Parameters] Allowed parameters for the action
164
+ # @description Sanitizes the parameters received from an HTTP call to only allow the specified ones.
165
+ # Allowed params are _:content_, _:actions_id_.
166
+ # @example
167
+ # # supose params contains {
168
+ # # "ticket_action": {
169
+ # # "id": 5,
170
+ # # "content": "This is a message!",
171
+ # # "cloud_help_ticket_actions_id": 4
172
+ # # }
173
+ # #}
174
+ # action_params = action_params
175
+ # puts action_params
176
+ # # will remove the _id_ field and only print {
177
+ # # "ticket_action": {
178
+ # # "content": "This is a message!",
179
+ # # "cloud_help_ticket_actions_id": 4
180
+ # # }
181
+ # #}
182
+ def action_params
183
+ action_model = action_model() # If there is a custom action model, it must be returned in this method
184
+ cloud_object_model = action_model.cloud_object_model
185
+
186
+ params.require(
187
+ "#{cloud_object_model.name.demodulize.underscore}_action".to_sym
188
+ ).permit(
189
+ :instructions,
190
+ :complete,
191
+ :group,
192
+ "#{action_model.table_name}_id".to_sym
193
+ )
194
+ end
195
+
196
+ # @return [void]
197
+ # @descriptions Sets the variable @cloud_object based on the paremeters send in the URL. If no,
198
+ # cloud_object is found or it is not within the current_user's account, nil is used instead
199
+ # @example
200
+ # # Imagine you are inside CloudFocus::Task::ActionsController
201
+ # puts @cloud_object # will display nil
202
+ # set_cloud_object
203
+ # puts @cloud_object # Will display an instance of CloudFocus::Task
204
+ def set_cloud_object
205
+ action_model = action_model() # If there is a custom action model, it must be returned in this method
206
+ cloud_object_model = action_model.cloud_object_model
207
+ account_model = cloud_object_model.reflect_on_association(:account).klass
208
+
209
+ @cloud_object = cloud_object_model.find_by(
210
+ id: params["#{cloud_object_model.name.demodulize.underscore}_id".to_sym],
211
+ "#{account_model.table_name}_id".to_sym => current_user.account.id
212
+ )
213
+ end
214
+
215
+ # @return [void]
216
+ # @description Sets the variable @action. The variable contains the action
217
+ # to be updated based on the id of the *cloud_object* and the id of the *action*
218
+ # @example
219
+ # #suppose params[:ticket_id] = 1
220
+ # #suppose params[:id] = 44
221
+ # puts @action # will display nil
222
+ # set_action
223
+ # puts @action # will display an instance of CloudHelp:Ticket::Action
224
+ def set_action
225
+ action_model = action_model() # If there is a custom action model, it must be returned in this method
226
+ cloud_object_model = action_model.cloud_object_model
227
+ account_model = cloud_object_model.reflect_on_association(:account).klass
228
+
229
+ @action = action_model.joins(:cloud_object).where(
230
+ "#{cloud_object_model.table_name}.id = #{params["#{cloud_object_model.name.demodulize.underscore}_id".to_sym]}",
231
+ "#{cloud_object_model.table_name}.#{account_model.table_name}_id = #{current_user.account.id}"
232
+ ).find_by(
233
+ id: params[:id]
234
+ )
235
+ end
236
+
237
+ # @return [CloudObject::Action] The action model that the controller will handle
238
+ # @descriptions Constantizes and returns the action model associated to this controller. This method
239
+ # can be overrided by the implementation in the child controller
240
+ # @example
241
+ # # Suppose you are inside CloudHelp::Ticket::ActionsController
242
+ # puts action_model().new
243
+ # # This will display a new instance of CloudHelp::Ticket::Action
244
+ def action_model
245
+ self.class.name.gsub("Controller","").singularize.constantize
246
+ end
247
+ end
248
+ end
249
+ end
250
+ 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 · 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
+ module Lesli
34
+ module Interfaces
35
+ module Controllers
36
+ module Activities
37
+
38
+ # @return [Json] Json that contains a list of all activities related to a *cloud_object*
39
+ # @description Retrieves and returns all activities associated to a *cloud_object*. The id of the
40
+ # *cloud_object* is within the *params* attribute
41
+ # @example
42
+ # # Executing this controller's activity from javascript's frontend
43
+ # let ticket_id = 1;
44
+ # this.http.get(`127.0.0.1/help/tickets/${ticket_id}/activities`);
45
+ def index
46
+ activity_model = activity_model() # If there is a custom activity model, it must be returned in this method
47
+ cloud_object_model = activity_model.cloud_object_model
48
+ translations_module = activity_model.name.split("::")[0].gsub("Cloud", "").underscore
49
+
50
+ @activities = activity_model.index(
51
+ current_user,
52
+ params["#{cloud_object_model.name.demodulize.underscore}_id".to_sym],
53
+ @query
54
+ )
55
+
56
+ if block_given?
57
+ yield(@activities)
58
+ else
59
+ respond_with_successful(@activities)
60
+ end
61
+ end
62
+
63
+ # @return [JSON] The json information about the selected activity
64
+ # @description Retrieves and returns the information about the activity. The id of the
65
+ # *cloud_object* and the id of the *activity* are within the *params* attribute. If a block
66
+ # is provided, the execution will be yielded sending the activity as first parameter
67
+ # @example
68
+ # # Executing this controller's action from javascript's frontend
69
+ # let ticket_id = 1;
70
+ # let activity_id = 5;
71
+ # this.http.get(`127.0.0.1/help/tickets/${ticket_id}/activities/${activity_id}`);
72
+ def show
73
+ set_activity
74
+ return respond_with_not_found unless @activity
75
+
76
+ if block_given?
77
+ yield(@activity)
78
+ else
79
+ return respond_with_successful(@activity)
80
+ end
81
+ end
82
+
83
+ # @controller_action_param :description [String] The description of the activity
84
+ # @controller_action_param :field [String] The field that was changed (if any)
85
+ # @controller_action_param :value_from [String] The initial field value of the activity (if any)
86
+ # @controller_action_param :value_to [String] The final field value of the activity (if any)
87
+ # @controller_action_param :category [String] An enum value, that indicates the type of activity recorded
88
+ # @return [Json] Json that contains wheter the creation of the activity was successful or not.
89
+ # If it is not successful, it returs an error message
90
+ # @description Creates a new activity associated to a *cloud_object*. The id of the
91
+ # *cloud_object* is within the *params* attribute
92
+ # @example
93
+ # # Executing this controller's activity from javascript's frontend
94
+ # let ticket_id = 1;
95
+ # let data = {
96
+ # ticket_activity: {
97
+ # description: "Created",
98
+ # category: "action_create"
99
+ # }
100
+ # };
101
+ # this.http.post(`127.0.0.1/help/tickets/${ticket_id}/activities`, data);
102
+ def create
103
+ activity_model = activity_model() # If there is a custom activity model, it must be returned in this method
104
+ cloud_object_model = activity_model.cloud_object_model
105
+
106
+ set_cloud_object
107
+ new_activity_params = activity_params.merge(
108
+ user_creator: current_user,
109
+ cloud_object: @cloud_object
110
+ )
111
+
112
+ activity = activity_model.new(new_activity_params)
113
+ if activity.save
114
+ if block_given?
115
+ yield(cloud_object, activity)
116
+ else
117
+ # Returning the 200 HTTP response
118
+ respond_with_successful(activity)
119
+ end
120
+ else
121
+ respond_with_error(activity.errors.full_messages)
122
+ end
123
+ end
124
+
125
+ protected
126
+
127
+ # @return [void]
128
+ # @descriptions Sets the variable @cloud_object based on the paremeters send in the URL. If no,
129
+ # cloud_object is found or it is not within the current_user's account, nil is used instead
130
+ # @example
131
+ # # Imagine you are inside CloudFocus::Task::ActivitiesController
132
+ # puts @cloud_object # will display nil
133
+ # set_cloud_object
134
+ # puts @cloud_object # Will display an instance of CloudFocus::Task
135
+ def set_cloud_object
136
+ activity_model = activity_model() # If there is a custom activity model, it must be returned in this method
137
+ cloud_object_model = activity_model.cloud_object_model
138
+ account_model = cloud_object_model.reflect_on_association(:account).klass
139
+
140
+ @cloud_object = cloud_object_model.find_by(
141
+ id: params["#{cloud_object_model.name.demodulize.underscore}_id".to_sym],
142
+ "#{account_model.table_name}_id".to_sym => current_user.account.id
143
+ )
144
+ end
145
+
146
+ # @return [void]
147
+ # @description Sets the variable @activity. The variable contains the activity
148
+ # to be updated based on the id of the *cloud_object* and the id of the *activity*
149
+ # @example
150
+ # #suppose params[:ticket_id] = 1
151
+ # #suppose params[:id] = 44
152
+ # puts @activity # will display nil
153
+ # set_activity
154
+ # puts @activity # will display an instance of CloudHelp:Ticket::Activity
155
+ def set_activity
156
+ activity_model = activity_model() # If there is a custom activity model, it must be returned in this method
157
+ cloud_object_model = activity_model.cloud_object_model
158
+ account_model = cloud_object_model.reflect_on_association(:account).klass
159
+
160
+ @activity = activity_model.joins(:cloud_object).where(
161
+ "#{cloud_object_model.table_name}.id = #{params["#{cloud_object_model.name.demodulize.underscore}_id".to_sym]}",
162
+ "#{cloud_object_model.table_name}.#{account_model.table_name}_id = #{current_user.account.id}"
163
+ ).find_by(
164
+ id: params[:id]
165
+ )
166
+ end
167
+
168
+ # @return [Parameters] Allowed parameters for the activity
169
+ # @description Sanitizes the parameters received from an HTTP call to only allow the specified ones.
170
+ # Allowed params are _:description_, _:field_name_, _:value_from_, _:value_toe_, _:category_
171
+ # @example
172
+ # # supose params contains {
173
+ # # "ticket_activity": {
174
+ # # "id": 5,
175
+ # # "description": "User requested this ticket",
176
+ # # "tags": "Important",
177
+ # # "info": "Example"
178
+ # # }
179
+ # #}
180
+ # activity_params = activity_params
181
+ # puts activity_params
182
+ # # will remove all unpermitted fields and only print {
183
+ # # "ticket_activity": {
184
+ # # "description": "User requested this ticket"
185
+ # # }
186
+ # #}
187
+ def activity_params
188
+ activity_model = activity_model() # If there is a custom activity model, it must be returned in this method
189
+ cloud_object_model = activity_model.cloud_object_model
190
+
191
+ params.require(
192
+ "#{cloud_object_model.name.demodulize.underscore}_activity".to_sym
193
+ ).permit(
194
+ :description,
195
+ :field_name,
196
+ :value_from,
197
+ :value_to,
198
+ :category
199
+ )
200
+ end
201
+
202
+ # @return [CloudObject::Activity] The activity model that the controller will handle
203
+ # @descriptions Constantizes and returns the activity model associated to this controller. This method
204
+ # can be overrided by the implementation in the child controller
205
+ # @example
206
+ # # Suppose you are inside CloudHelp::Ticket::ActivitiesController
207
+ # puts activity_model().new
208
+ # # This will display a new instance of CloudHelp::Ticket::Activity
209
+ def activity_model
210
+ self.class.name.gsub("Controller","").singularize.constantize
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end