lesli_admin 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/lesli_admin/application.js +284 -841
  3. data/app/controllers/lesli_admin/accounts_controller.rb +3 -5
  4. data/app/controllers/lesli_admin/dashboard/components_controller.rb +60 -0
  5. data/app/controllers/lesli_admin/dashboards_controller.rb +26 -50
  6. data/app/models/lesli_admin/account.rb +6 -0
  7. data/app/{controllers/lesli_admin/profiles_controller.rb → models/lesli_admin/dashboard/component.rb} +13 -19
  8. data/app/models/lesli_admin/dashboard.rb +58 -0
  9. data/app/services/lesli_admin/account_service.rb +39 -0
  10. data/app/views/lesli_admin/dashboards/edit.html.erb +29 -7
  11. data/app/views/lesli_admin/dashboards/index.html.erb +29 -11
  12. data/app/views/lesli_admin/dashboards/new.html.erb +29 -6
  13. data/app/views/lesli_admin/dashboards/show.html.erb +31 -0
  14. data/app/views/lesli_admin/partials/_engine-navigation.html.erb +0 -1
  15. data/config/locales/translations.en.yml +26 -0
  16. data/config/locales/translations.es.yml +26 -0
  17. data/config/routes.rb +46 -5
  18. data/db/migrate/0101050110_create_lesli_admin_dashboards.rb +51 -0
  19. data/db/migrate/0101050210_create_lesli_admin_dashboard_components.rb +53 -0
  20. data/lib/lesli_admin/engine.rb +1 -0
  21. data/lib/lesli_admin/version.rb +1 -1
  22. data/lib/vue/application.js +28 -15
  23. data/lib/vue/apps/account/components/{address-form.vue → form-address.vue} +27 -42
  24. data/lib/vue/apps/account/components/form-contact.vue +122 -0
  25. data/lib/vue/apps/account/components/form-information.vue +12 -30
  26. data/lib/vue/apps/account/show.vue +13 -12
  27. data/lib/vue/apps/{users/components/integrations-information.vue → dashboards/components/lesli-version.vue} +36 -26
  28. data/lib/vue/apps/{profile/components/change-email.vue → dashboards/show.vue} +9 -6
  29. data/lib/vue/stores/translations.json +52 -18
  30. metadata +17 -30
  31. data/app/controllers/lesli_admin/users_controller.rb +0 -238
  32. data/app/services/lesli_admin/user_service.rb +0 -265
  33. data/app/views/lesli_admin/dashboards/_dashboard.html.erb +0 -2
  34. data/app/views/lesli_admin/dashboards/_form.html.erb +0 -17
  35. data/lib/vue/apps/account/components/contact-form.vue +0 -162
  36. data/lib/vue/apps/dashboard/show.vue +0 -30
  37. data/lib/vue/apps/profile/components/subscriptions.vue +0 -94
  38. data/lib/vue/apps/profile/show.vue +0 -152
  39. data/lib/vue/apps/users/components/information-card.vue +0 -116
  40. data/lib/vue/apps/users/components/information-form.vue +0 -177
  41. data/lib/vue/apps/users/components/management-roles.vue +0 -109
  42. data/lib/vue/apps/users/components/management-security.vue +0 -113
  43. data/lib/vue/apps/users/components/management-sessions.vue +0 -106
  44. data/lib/vue/apps/users/components/management-settings.vue +0 -94
  45. data/lib/vue/apps/users/index.vue +0 -206
  46. data/lib/vue/apps/users/new.vue +0 -181
  47. data/lib/vue/apps/users/show.vue +0 -116
  48. data/lib/vue/stores/user.js +0 -331
  49. data/lib/vue/stores/users.js +0 -175
@@ -1,265 +0,0 @@
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
-
33
- module LesliAdmin
34
- class UserService < Lesli::ApplicationLesliService
35
-
36
- # @return [Array] Paginated index of users.
37
- # @description Return a paginated array of users, used mostly in frontend views
38
- # TODO: Implement pg_search
39
- def index params
40
-
41
- # sql string to join to user_roles and get all the roles assigned to a user
42
- sql_string_for_user_roles = "left join (
43
- select
44
- ur.user_id, string_agg(r.\"name\", ', ') rolenames
45
- from user_roles ur
46
- join roles r
47
- on r.id = ur.role_id
48
- where ur.deleted_at is null
49
- group by ur.user_id
50
- ) roles on roles.user_id = users.id"
51
-
52
- # sql string to joing to user_sessions and get all the active sessions of a user
53
- sql_string_for_user_sessions = "left join (
54
- select
55
- max(last_used_at) as last_action_performed_at,
56
- user_id
57
- from user_sessions us
58
- where us.deleted_at is null
59
- group by(us.user_id)
60
- ) sessions on sessions.user_id = users.id"
61
-
62
- #users = current_user.account.users
63
- users = Lesli::Account.first.users
64
- #.joins(sql_string_for_user_roles)
65
- #.joins(sql_string_for_user_sessions)
66
- users = users.page(query[:pagination][:page])
67
- .per(query[:pagination][:perPage])
68
- .order("#{query[:order][:by]} #{query[:order][:dir]} NULLS LAST")
69
-
70
- users.select(
71
- :id,
72
- "CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, '')) as name",
73
- :email,
74
- :active,
75
- #:rolenames,
76
- #Date2.new.date_time.db_column("current_sign_in_at"),
77
- #Date2.new.date_time.db_column("last_action_performed_at")
78
- )
79
-
80
- end
81
-
82
-
83
- # Creates a query that selects all user information from several tables if CloudLock is present
84
- def show
85
-
86
- user = resource
87
-
88
- return {
89
- id: user[:id],
90
- email: user[:email],
91
- alias: user[:alias],
92
- active: user[:active],
93
- full_name: user.full_name,
94
- salutation: user[:salutation],
95
- first_name: user[:first_name],
96
- last_name: user[:last_name],
97
- telephone: user[:telephone],
98
-
99
- #locale: user.settings.select(:value).find_by(:name => "locale"),
100
-
101
- #roles: user.roles.map { |r| { id: r[:id], name: r[:name], permission_level: r[:object_level_permission]} },
102
-
103
- #mfa_enabled: user.mfa_settings[:enabled],
104
- #mfa_method: user.mfa_settings[:method],
105
-
106
- created_at: user[:created_at],
107
- updated_at: user[:updated_at],
108
- detail_attributes: {
109
- title: user.detail&[:title] || "",
110
- # address: user.detail[:address],
111
- # work_city: user.detail[:work_city],
112
- # work_region: user.detail[:work_region],
113
- # work_address: user.detail[:work_address]
114
- }
115
- }
116
- end
117
-
118
- def create user_params
119
-
120
- # check if request has an email to create the user
121
- if user_params[:email].blank?
122
- self.error(I18n.t("core.users.messages_danger_not_valid_email_found"))
123
- end
124
-
125
-
126
- # register the new user
127
- user = User.new({
128
- :active => true,
129
- :email => user_params[:email],
130
- :alias => user_params[:alias] || "",
131
- :first_name => user_params[:first_name] || "",
132
- :last_name => user_params[:last_name] || "",
133
- :telephone => user_params[:telephone] || "",
134
- #:detail_attributes => user_params[:detail_attributes] || {}
135
- })
136
-
137
-
138
-
139
- # assign a random password
140
- user.password = Devise.friendly_token
141
-
142
- # enrol user to my own account
143
- user.account = current_user.account
144
-
145
- # users created through the administration area does not need to confirm their accounts
146
- # instead we send a password reset link, so they can have access to the platform
147
- #user.confirm
148
-
149
- if user.save
150
-
151
- # if a role is provided to assign to the new user
152
- # unless user_params[:roles_id].blank?
153
- # # check if current user can work with the sent role
154
- # if current_user.can_work_with_role?(user_params[:roles_id])
155
- # # Search the role assigned
156
- # role = current_user.account.roles.find_by(id: user_params[:roles_id])
157
- # # assign role to the new user
158
- # user.user_roles.create({ role: role })
159
- # end
160
- # end
161
-
162
- # role validation - if new user does not have any role assigned
163
- # if user.roles.blank?
164
-
165
- # default_role_id = current_user.account.settings.find_by(:name => "default_role_id")&.value
166
- # owner_role_id = current_user.account.roles.find_by(:name => "owner").id
167
- # if default_role_id.present? && default_role_id != owner_role_id
168
- # # assign default role
169
- # user.user_roles.create({ role: current_user.account.roles.find_by(:id => default_role_id)})
170
-
171
- # else
172
- # # assign limited role
173
- # user.user_roles.create({ role: current_user.account.roles.find_by(:name => "limited") })
174
- # end
175
- # end
176
-
177
- # saving logs with information about the creation of the user
178
- # user.logs.create({ title: "user_created_at", description: Date2.new.date_time.to_s })
179
- # user.logs.create({ title: "user_created_by", description: current_user.email })
180
- # user.logs.create({ title: "user_created_with_role", description: user.user_roles.first.role.name + " " + user.user_roles.first.role.id.to_s})
181
- # User.log_activity_create(current_user, user)
182
-
183
- self.resource = user
184
-
185
- begin
186
- # users created through the administration area does not need to confirm their accounts
187
- # instead we send a password reset link, so they can have access to the platform
188
- #UserMailer.with(user: user).invitation_instructions.deliver_now
189
- rescue => exception
190
- #Honeybadger.notify(exception)
191
- #user.logs.create({ title: "user_creation_email_failed ", description: exception.message })
192
- end
193
-
194
- else
195
- self.error(user.errors.full_messages.to_sentence)
196
- end
197
-
198
- self
199
-
200
- end
201
-
202
- def update params
203
-
204
- # old_attributes = resource.detail.attributes.merge({
205
- # active: resource.active
206
- # })
207
-
208
- if resource.update(params)
209
- # new_attributes = resource.detail.attributes.merge({
210
- # active: resource.active
211
- # })
212
- #resource.log_activity_update(current_user, resource, old_attributes, new_attributes)
213
- else
214
- self.error(resource.errors.full_messages.to_sentence)
215
- end
216
-
217
- self
218
- end
219
-
220
-
221
- # force the user to change the password (at next login)
222
- def request_password
223
-
224
- # expire password
225
- resource.set_password_as_expired
226
-
227
- resource.logs.create({ title: "request_password", description: "by_user: " + current_user.email })
228
- end
229
-
230
-
231
- # generate a random password for the user
232
- def password_reset
233
-
234
- # generate random password
235
- pass = resource.password_reset
236
-
237
- resource.logs.create({ title: "password_reset", description: "by_user: " + current_user.email })
238
-
239
- pass
240
- end
241
-
242
- def logout
243
- # delete user active sessions
244
- resource.sessions.destroy_all
245
-
246
- resource.logs.create({ title: "close_sessions", description: "by_user: " + current_user.email })
247
- end
248
-
249
- def revoke_access
250
-
251
- # delete user active sessions
252
- self.logout
253
-
254
- # add delete date to the last active session
255
- resource.revoke_access
256
-
257
- resource.logs.create({ title: "revoke_access", description: "by_user: " + current_user.email })
258
- end
259
-
260
- def find id
261
- #super(current_user.account.users.joins(:detail).find_by(id: id))
262
- super(current_user.account.users.find_by(id: id))
263
- end
264
- end
265
- end
@@ -1,2 +0,0 @@
1
- <div id="<%= dom_id dashboard %>">
2
- </div>
@@ -1,17 +0,0 @@
1
- <%= form_with(model: dashboard) do |form| %>
2
- <% if dashboard.errors.any? %>
3
- <div style="color: red">
4
- <h2><%= pluralize(dashboard.errors.count, "error") %> prohibited this dashboard from being saved:</h2>
5
-
6
- <ul>
7
- <% dashboard.errors.each do |error| %>
8
- <li><%= error.full_message %></li>
9
- <% end %>
10
- </ul>
11
- </div>
12
- <% end %>
13
-
14
- <div>
15
- <%= form.submit %>
16
- </div>
17
- <% end %>
@@ -1,162 +0,0 @@
1
- <script setup>
2
- /*
3
-
4
- Lesli
5
-
6
- Copyright (c) 2023, Lesli Technologies, S. A.
7
-
8
- This program is free software: you can redistribute it and/or modify
9
- it under the terms of the GNU General Public License as published by
10
- the Free Software Foundation, either version 3 of the License, or
11
- (at your option) any later version.
12
-
13
- This program is distributed in the hope that it will be useful,
14
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- GNU General Public License for more details.
17
-
18
- You should have received a copy of the GNU General Public License
19
- along with this program. If not, see http://www.gnu.org/licenses/.
20
-
21
- Lesli · Your Smart Business Assistant.
22
-
23
- Made with ♥ by https://www.lesli.tech
24
- Building a better future, one line of code at a time.
25
-
26
- @contact hello@lesli.tech
27
- @website https://lesli.tech
28
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
29
-
30
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
31
- // ·
32
-
33
- */
34
-
35
-
36
- // · import vue tools
37
- import { computed } from "vue"
38
-
39
- // · import lesli stores
40
- import { useAccount } from "CloudAdmin/stores/account"
41
-
42
- // · implement stores
43
- const storeAccount = useAccount()
44
-
45
- // · translations
46
- const translations = {
47
- shared: I18n.t("core.shared"),
48
- core: {
49
- onboardings: I18n.t("core.onboardings"),
50
- accounts: I18n.t("core.accounts"),
51
- }
52
- }
53
-
54
- // . get reactive info from onboarding store
55
- const companyInfo = computed(()=> storeOnboarding.companyInfo)
56
-
57
- </script>
58
- <template>
59
- <form @submit.prevent="storeAccount.updateInfo">
60
- <div class="field">
61
- <label class="label">{{ translations.core.onboardings.view_text_email }}</label>
62
- <div class="control">
63
- <input
64
- class="input"
65
- type="text"
66
- :placeholder="translations.core.onboardings.view_placeholder_email"
67
- v-model="storeAccount.accountInfo.public_email"
68
- />
69
- </div>
70
- </div>
71
-
72
- <div class="field">
73
- <label class="label">{{translations.shared.view_text_telephone}}</label>
74
- <div class="control">
75
- <input
76
- class="input"
77
- type="text"
78
- :placeholder= "translations.core.onboardings.view_placeholder_phone"
79
- v-model="storeAccount.accountInfo.phone_number_1"
80
- />
81
- </div>
82
- </div>
83
-
84
- <p>{{translations.core.onboardings.view_title_social_profiles}}</p>
85
-
86
- <div class="field">
87
- <label class="label">{{ translations.core.accounts.column_github }}</label>
88
- <div class="control">
89
- <input
90
- class="input"
91
- type="text"
92
- :placeholder="translations.core.onboardings.view_placeholder_github"
93
- v-model="storeAccount.accountInfo.github"
94
- />
95
- </div>
96
- </div>
97
-
98
-
99
- <div class="field">
100
- <label class="label">{{ translations.core.accounts.column_twitter }}</label>
101
- <div class="control">
102
- <input
103
- class="input"
104
- type="text"
105
- :placeholder="translations.core.onboardings.view_placeholder_twitter"
106
- v-model="storeAccount.accountInfo.twitter"
107
- />
108
- </div>
109
- </div>
110
-
111
-
112
- <div class="field">
113
- <label class="label">{{ translations.core.accounts.column_youtube }}</label>
114
- <div class="control">
115
- <input
116
- class="input"
117
- type="text"
118
- :placeholder="translations.core.onboardings.view_placeholder_youtube"
119
- v-model="storeAccount.accountInfo.youtube"
120
- />
121
- </div>
122
- </div>
123
-
124
-
125
- <div class="field">
126
- <label class="label">{{ translations.core.accounts.column_linkedin }}</label>
127
- <div class="control">
128
- <input
129
- class="input"
130
- type="text"
131
- :placeholder="translations.core.onboardings.view_placeholder_linkedin"
132
- v-model="storeAccount.accountInfo.linkedin"
133
- />
134
- </div>
135
- </div>
136
-
137
-
138
- <div class="field">
139
- <label class="label">{{ translations.core.accounts.column_facebook }}</label>
140
- <div class="control">
141
- <input
142
- class="input"
143
- type="text"
144
- :placeholder="translations.core.onboardings.view_placeholder_facebook"
145
- v-model="storeAccount.accountInfo.facebook"
146
- />
147
- </div>
148
- </div>
149
-
150
- <div class="field">
151
- <div class="field-body">
152
- <div class="field">
153
- <div class="control">
154
- <lesli-button icon="save">
155
- {{ translations.shared.view_btn_save }}
156
- </lesli-button>
157
- </div>
158
- </div>
159
- </div>
160
- </div>
161
- </form>
162
- </template>
@@ -1,30 +0,0 @@
1
- <script setup>
2
-
3
- import { lesliChartLine } from "lesli-vue/components"
4
-
5
- </script>
6
- <template>
7
- <lesli-application-container>
8
- <lesli-header title="Dashboard"></lesli-header>
9
- <div class="columns">
10
- <div class="column">
11
- <lesli-application-component>
12
- <lesli-chart-line
13
- title="My daily activity graph"
14
- :series="[{ data:[4, 1, 4, 2, 5] }]"
15
- :labels="['Monday','Tuesday','Wednesday', 'Thursday', 'Friday']">
16
- </lesli-chart-line>
17
- </lesli-application-component>
18
- </div>
19
- <div class="column">
20
- <lesli-application-component>
21
- <lesli-chart-line
22
- title="My daily activity graph"
23
- :series="[{ name: 'Last week', data:[4, 1, 4, 2, 5] }, { name: 'Current week', data:[3, 2, 5, 4, 2] }]"
24
- :labels="['Monday','Tuesday','Wednesday', 'Thursday', 'Friday']">
25
- </lesli-chart-line>
26
- </lesli-application-component>
27
- </div>
28
- </div>
29
- </lesli-application-container>
30
- </template>
@@ -1,94 +0,0 @@
1
- <script setup>
2
- /*
3
-
4
- Lesli
5
-
6
- Copyright (c) 2023, Lesli Technologies, S. A.
7
-
8
- This program is free software: you can redistribute it and/or modify
9
- it under the terms of the GNU General Public License as published by
10
- the Free Software Foundation, either version 3 of the License, or
11
- (at your option) any later version.
12
-
13
- This program is distributed in the hope that it will be useful,
14
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- GNU General Public License for more details.
17
-
18
- You should have received a copy of the GNU General Public License
19
- along with this program. If not, see http://www.gnu.org/licenses/.
20
-
21
- Lesli · Your Smart Business Assistant.
22
-
23
- Made with ♥ by https://www.lesli.tech
24
- Building a better future, one line of code at a time.
25
-
26
- @contact hello@lesli.tech
27
- @website https://lesli.tech
28
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
29
-
30
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
31
- // ·
32
-
33
- */
34
-
35
-
36
-
37
- // · import vue tools
38
- import { ref, reactive, onMounted, watch, computed } from "vue"
39
-
40
-
41
- // · import lesli stores
42
- import { useUser } from "LesliApp/administration/stores/user"
43
-
44
- // · implement stores
45
- const storeUser = useUser()
46
-
47
- const engine = ref({ label:"", value:"" })
48
-
49
-
50
- onMounted(() => {
51
- storeUser.getSubscriptionsOptions ()
52
- })
53
-
54
- function selectEngine(){
55
- storeUser.getSubscriptions(engine.value.value)
56
-
57
- }
58
-
59
-
60
- const translations = {
61
- users: I18n.t("core.users"),
62
- shared: I18n.t("core.shared")
63
- }
64
-
65
- const columns = [{
66
- field: 'action',
67
- label: 'action'
68
- }, {
69
- field: 'notification_type',
70
- label: 'Notification type'
71
- }, {
72
- field: 'created_at',
73
- label: 'Created at'
74
- }]
75
-
76
- </script>
77
- <template>
78
-
79
- <div class="block">
80
- <lesli-select
81
- :options="storeUser.options.engines"
82
- @change="selectEngine"
83
- v-model="engine">
84
- </lesli-select>
85
- </div>
86
- <lesli-table
87
- :columns="columns"
88
- :records="storeUser.subscriptions">
89
- </lesli-table>
90
-
91
-
92
-
93
- </template>
94
-