lesli_admin 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,18 +18,17 @@ GNU General Public License for more details.
18
18
  You should have received a copy of the GNU General Public License
19
19
  along with this program. If not, see http://www.gnu.org/licenses/.
20
20
 
21
- Lesli · Your Smart Business Assistant.
21
+ Lesli · Ruby on Rails SaaS Development Framework.
22
22
 
23
23
  Made with ♥ by https://www.lesli.tech
24
24
  Building a better future, one line of code at a time.
25
25
 
26
26
  @contact hello@lesli.tech
27
- @website https://lesli.tech
27
+ @website https://www.lesli.tech
28
28
  @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
29
29
 
30
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
31
31
  // ·
32
-
33
32
  */
34
33
 
35
34
 
@@ -40,7 +39,7 @@ import { useRouter, useRoute } from 'vue-router'
40
39
 
41
40
 
42
41
  // · import lesli stores
43
- import { useUser } from "Lesli/stores/user"
42
+ import { useUser } from "LesliAdmin/stores/user"
44
43
 
45
44
 
46
45
  // · implement stores
@@ -48,9 +47,10 @@ const storeUser = useUser()
48
47
  const router = useRouter()
49
48
  const route = useRoute()
50
49
 
51
- // · import profile components
52
50
 
51
+ // · import profile components
53
52
  import informationCard from "LesliAdmin/apps/users/components/information-card.vue"
53
+ import informationForm from "LesliAdmin/apps/users/components/information-form.vue"
54
54
  /*
55
55
  import informationForm from "CloudAdmin/apps/users/components/information-form.vue"
56
56
 
@@ -88,15 +88,19 @@ const tab = ref(0)
88
88
 
89
89
  // ·
90
90
  onMounted(() => {
91
- //storeUser.getUser()
91
+ storeUser.getUser()
92
92
  //storeUser.getOptions()
93
93
  })
94
94
 
95
95
  </script>
96
96
  <template>
97
97
  <lesli-application-container>
98
- {{ storeProfile.profile }}
99
98
  <information-card></information-card>
99
+ <lesli-tabs v-model="tab">
100
+ <lesli-tab-item icon="info_outline" title="Information">
101
+ <information-form></information-form>
102
+ </lesli-tab-item>
103
+ </lesli-tabs>
100
104
  </lesli-application-container>
101
105
  <!--
102
106
  <application-component>
@@ -117,7 +117,6 @@ const props = defineProps({
117
117
  // · initializing
118
118
  onMounted(() => {
119
119
  storeUsers.fetchUsers()
120
- i18n.t("lesli_admin.users.title_users")
121
120
  })
122
121
 
123
122
 
@@ -37,7 +37,7 @@ import { useRouter, useRoute } from 'vue-router'
37
37
 
38
38
 
39
39
  // · import lesli stores
40
- import { useUser } from "Lesli/stores/user"
40
+ import { useUser } from "LesliAdmin/stores/user"
41
41
 
42
42
 
43
43
  // · implement stores
@@ -1,20 +1,38 @@
1
1
  {
2
2
  "en": {
3
- "dashboards": {
4
- "button_my": "My button in my dashboard",
5
- "column_prueba_de_calendario": "my calendar"
3
+ "lesli": {
4
+ "shared": {
5
+ "title_lesli": ":lesli.shared.title_lesli:"
6
+ },
7
+ "users": {
8
+ "title_users": "Users"
9
+ }
6
10
  },
7
- "users": {
8
- "title_users": "Users"
11
+ "lesli_admin": {
12
+ "shared": {
13
+ "title_lesli": ":lesli.shared.title_lesli:"
14
+ },
15
+ "users": {
16
+ "title_users": "Users"
17
+ }
9
18
  }
10
19
  },
11
20
  "es": {
12
- "dashboards": {
13
- "button_my": "Mi boton en mi dashboard",
14
- "column_prueba_de_calendario": ":lesli_driver.dashboards.column_prueba_de_calendario:"
21
+ "lesli": {
22
+ "shared": {
23
+ "title_lesli": "Lesli en español "
24
+ },
25
+ "users": {
26
+ "title_users": "Usuarios"
27
+ }
15
28
  },
16
- "users": {
17
- "title_users": "Usuarios"
29
+ "lesli_admin": {
30
+ "shared": {
31
+ "title_lesli": "Lesli en español "
32
+ },
33
+ "users": {
34
+ "title_users": "Usuarios"
35
+ }
18
36
  }
19
37
  }
20
38
  }
@@ -0,0 +1,331 @@
1
+ /*
2
+ Lesli
3
+
4
+ Copyright (c) 2023, Lesli Technologies, S. A.
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see http://www.gnu.org/licenses/.
18
+
19
+ Lesli · Ruby on Rails Development Platform.
20
+
21
+ Made with ♥ by https://www.lesli.tech
22
+ Building a better future, one line of code at a time.
23
+
24
+ @contact hello@lesli.tech
25
+ @website https://www.lesli.tech
26
+ @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
27
+
28
+ // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
29
+ // ·
30
+ */
31
+
32
+
33
+ // ·
34
+ import { defineStore } from "pinia"
35
+
36
+
37
+ // ·
38
+ export const useUser = defineStore("lesli.user", {
39
+ state: () => {
40
+ return {
41
+ options: {
42
+ regions: [],
43
+ locales: [],
44
+ salutations: [],
45
+ mfa_methods: []
46
+ },
47
+ user: {
48
+ roles_id: null,
49
+ email: null,
50
+ alias: null,
51
+ first_name: null,
52
+ last_name: null,
53
+ telephone: null,
54
+ detail_attributes: {
55
+ salutation: null,
56
+ title: null,
57
+ }
58
+ },
59
+ roles: [],
60
+ sessions: {
61
+ pagination: {},
62
+ records: []
63
+ },
64
+ options: {
65
+ salutations: [],
66
+ locales: []
67
+ }
68
+ }
69
+ },
70
+ getters: {
71
+ initials() {
72
+ let initials = ""
73
+ if (this.user?.first_name) initials += this.user?.first_name[0];
74
+ if (this.user?.last_name) initials += this.user?.last_name[0];
75
+ return initials.toUpperCase()
76
+ }
77
+ },
78
+ actions: {
79
+
80
+ getOptions() {
81
+ this.http.get(this.url.lesli("users/options")).then(result => {
82
+ this.options = result
83
+ })
84
+ },
85
+
86
+ getUser(id=null) {
87
+
88
+ let url = this.url.admin("profile")
89
+
90
+ if (id !== null) {
91
+ console.log("aqui")
92
+ url = this.url.admin("users/:id", id)
93
+ }
94
+
95
+ // get an specifick user if id is provided
96
+ this.http.get(url).then(result => {
97
+ this.user = result
98
+ this.user.password = ""
99
+ this.user.password_confirmation = ""
100
+
101
+ this.language = result.locale ? result.locale.value : this.language
102
+
103
+ // Backend should return the list of roles ordered by object level permission
104
+ this.role_names = result.roles[0].name
105
+
106
+ }).catch(error => {
107
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
108
+ }).finally(() => {
109
+ this.loading = false
110
+ })
111
+ },
112
+
113
+ putUser() {
114
+ this.http.put(this.url.lesli("users/:id", this.user.id), {
115
+ user: {
116
+ active: this.user.active,
117
+ alias: this.user.alias,
118
+ first_name: this.user.first_name,
119
+ last_name: this.user.last_name,
120
+ telephone: this.user.telephone,
121
+ detail_attributes: {
122
+ title: this.user.detail_attributes.title,
123
+ salutation: this.user.detail_attributes.salutation
124
+ }
125
+ }
126
+ }).then(result => {
127
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
128
+ }).catch(error => {
129
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
130
+ })
131
+ },
132
+
133
+ deleteUser() {
134
+ this.dialog.confirmation({
135
+ title: "Delete user",
136
+ text: "Are you sure you want to delete user?",
137
+ confirmText: "Yes",
138
+ cancelText: "No"
139
+ })
140
+ .then(({ isConfirmed }) => {
141
+ if (isConfirmed) {
142
+ this.http.delete(this.url.lesli("/users/:id", this.user.id)).then(result => {
143
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
144
+ //this.url.go("/administration/users")
145
+ }).catch(error => {
146
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
147
+ })
148
+ }
149
+ })
150
+ },
151
+
152
+ getRoles() {
153
+ this.http.get(this.url.lesli("users/:id/roles", this.user.id)).then(result => {
154
+ this.roles = result
155
+ }).catch(error => {
156
+ console.log(error)
157
+ })
158
+ },
159
+
160
+ postRole(role) {
161
+ this.http.post(this.url.lesli('users/:id/roles', this.user.id), {
162
+ user_role: {
163
+ id: role.id
164
+ }
165
+ }).then(result => {
166
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
167
+ }).catch(error => {
168
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
169
+ })
170
+ },
171
+
172
+ deleteRole(role) {
173
+ this.http.delete(this.url.lesli('users/:user_id/roles/:role_id', {
174
+ user_id: this.user.id,
175
+ role_id: role.id
176
+ })).then(result => {
177
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
178
+ }).catch(error => {
179
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
180
+ })
181
+ },
182
+
183
+ doRequestPassword() {
184
+ this.http.post(this.url.lesli("users/:id/requestpassword", this.user.id)).then(result => {
185
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
186
+ }).catch(error => {
187
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
188
+ })
189
+ },
190
+
191
+ doPasswordReset() {
192
+ this.http.post(this.url.lesli("users/:id/passwordreset", this.user.id)).then(result => {
193
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
194
+ }).catch(error => {
195
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
196
+ })
197
+ },
198
+
199
+ doLogout() {
200
+ this.http.post(this.url.lesli("users/:id/logout", this.user.id)).then(result => {
201
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
202
+ }).catch(error => {
203
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
204
+ })
205
+ },
206
+
207
+ doRevokeAccess() {
208
+ this.http.post(this.url.lesli("users/:id/revokeaccess", this.user.id)).then(result => {
209
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
210
+ }).catch(error => {
211
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
212
+ })
213
+ },
214
+
215
+ fetchSessions() {
216
+ if (!this.sessions.length > 0) {
217
+ this.getSessions()
218
+ }
219
+ },
220
+
221
+ getSessions() {
222
+ this.http.get(this.url.lesli("users/:id/sessions", this.user.id )).then(result => {
223
+ this.sessions.pagination = result.pagination
224
+ this.sessions.records = result.records
225
+ }).catch(error => {
226
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
227
+ }).finally(() => {
228
+ this.loading = false
229
+ })
230
+ },
231
+
232
+ deleteSession(user_session_id){
233
+ this.dialog.confirmation({
234
+ title: "Close session",
235
+ text: 'Are you sure you want to close this session',
236
+ confirmText: "Yes",
237
+ cancelText: "No"
238
+ })
239
+ .then(({ isConfirmed }) => {
240
+ if (isConfirmed) {
241
+ this.http.delete(this.url.lesli("users/:id/sessions/:session_id", {
242
+ id: this.user.id,
243
+ session_id: user_session_id
244
+ })).then(result => {
245
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
246
+ }).catch(error => {
247
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
248
+ })
249
+ this.fetchSessions()
250
+ }
251
+ })
252
+ },
253
+
254
+ postLanguage() {
255
+ this.http.post(this.url.lesli('users/:id/settings', this.user.id), {
256
+ user_setting: {
257
+ name: 'locale',
258
+ value: this.user.locale.value
259
+ }
260
+ }).then(result => {
261
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
262
+ // TODO: Only if current_user changed his own language
263
+ // reload the page so the user can work with the new language
264
+ // setTimeout(() => window.location.reload(), 1000)
265
+ }).catch(error => {
266
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
267
+ })
268
+ },
269
+
270
+ getOptions() {
271
+ this.http.get(this.url.lesli("users/options")).then(result => {
272
+ this.options.salutations = result.salutations
273
+
274
+ this.options.locales = Object.keys(result.locales).map(key => {
275
+ return {label: result.locales[key], value: key}
276
+ })
277
+ }).catch(error => {
278
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
279
+ })
280
+ },
281
+ }
282
+ })
283
+
284
+
285
+
286
+
287
+ /*
288
+
289
+
290
+
291
+ updatePassword() {
292
+ this.http.put("/", {
293
+ user: {
294
+ password: this.user.password,
295
+ password_confirmation: this.user.password_confirmation
296
+ }
297
+ }).then(result => {
298
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
299
+ this.user.password = ""
300
+ this.user.password_confirmation = ""
301
+ }).catch(error => {
302
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
303
+ })
304
+ },
305
+
306
+ // This action is used to change the user status active or inactive
307
+ putUserStatus(){
308
+ this.dialog.confirmation({
309
+ title: "Change status",
310
+ text: "Are you sure you want to change the status of this user?",
311
+ confirmText: "Yes",
312
+ cancelText: "No"
313
+ })
314
+ .then(({ isConfirmed }) => {
315
+ if (isConfirmed) {
316
+ this.http.patch(this.url.lesli('users/:id', this.user.id), {
317
+ user: {
318
+ active: this.user.active
319
+ }
320
+ }).then(result => {
321
+ this.msg.success(I18n.t("core.users.messages_success_operation"))
322
+ }) .catch(error => {
323
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
324
+ })
325
+ } else {
326
+ this.user.active = !this.user.active
327
+ }
328
+ })
329
+ },
330
+
331
+ */
@@ -113,7 +113,7 @@ export const useUsers = defineStore("administration.users", {
113
113
 
114
114
  this.http.get(
115
115
  this.url
116
- .lesli("users")
116
+ .admin("users")
117
117
  .search(this.search_string)
118
118
  .paginate(this.index.pagination.page, this.filters.per_page)
119
119
  .filter(query_filters)
@@ -128,6 +128,31 @@ export const useUsers = defineStore("administration.users", {
128
128
  })
129
129
  },
130
130
 
131
+ getUser(id=null) {
132
+
133
+ // get the profile by default
134
+ let url = this.url.lesli("profile")
135
+
136
+ // get an specifick user if id is provided
137
+ if (id) { url = this.url.lesli("users/:id", id) }
138
+
139
+ this.http.get(url).then(result => {
140
+ this.user = result
141
+ this.user.password = ""
142
+ this.user.password_confirmation = ""
143
+
144
+ this.language = result.locale ? result.locale.value : this.language
145
+
146
+ // Backend should return the list of roles ordered by object level permission
147
+ this.role_names = result.roles[0].name
148
+
149
+ }).catch(error => {
150
+ this.msg.danger(I18n.t("core.shared.messages_danger_internal_error"))
151
+ }).finally(() => {
152
+ this.loading = false
153
+ })
154
+ },
155
+
131
156
  postUsers() {
132
157
  return this.http.post(this.url.admin("users"), {
133
158
  user: this.user
data/readme.md CHANGED
@@ -6,7 +6,7 @@
6
6
  <hr/>
7
7
  <p align="center">
8
8
  <a target="blank" href="https://rubygems.org/gems/lesli_admin">
9
- <img src="https://badge.fury.io/rb/lesli_admin.svg" alt="Gem Version" height="18">
9
+ <img src="https://badge.fury.io/rb/lesli_admin.svg" alt="Gem Version" height="24">
10
10
  </a>
11
11
  </p>
12
12
  <hr/>
@@ -32,12 +32,12 @@ end
32
32
 
33
33
 
34
34
  ### Documentation
35
- * [Roadmap](./docs/roadmap.md)
35
+ * [website](https://www.lesli.dev/admin/)
36
36
  * [database](./docs/database.md)
37
37
  * [documentation](https://www.lesli.dev/documentation/)
38
38
 
39
39
 
40
- ### Get in touch
40
+ ### Get in touch with Lesli
41
41
 
42
42
  * [Website: https://www.lesli.tech](https://www.lesli.tech)
43
43
  * [Email: hello@lesli.tech](hello@lesli.tech)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lesli_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Lesli Development Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-09 00:00:00.000000000 Z
11
+ date: 2023-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 7.0.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: lesli
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5'
27
41
  description: Administration area for the Lesli Framework
28
42
  email:
29
43
  - hello@lesli.tech
@@ -35,7 +49,6 @@ files:
35
49
  - app/assets/config/lesli_admin_manifest.js
36
50
  - app/assets/images/lesli_admin/admin-logo.svg
37
51
  - app/assets/javascripts/lesli_admin/application.js
38
- - app/assets/javascripts/lesli_admin/translations.js
39
52
  - app/assets/stylesheets/lesli_admin/application.scss
40
53
  - app/assets/stylesheets/lesli_admin/users.scss
41
54
  - app/controllers/lesli_admin/accounts_controller.rb
@@ -50,6 +63,7 @@ files:
50
63
  - app/mailers/lesli_admin/application_mailer.rb
51
64
  - app/models/lesli_admin/account.rb
52
65
  - app/models/lesli_admin/application_record.rb
66
+ - app/services/lesli_admin/user_service.rb
53
67
  - app/views/layouts/lesli_admin/application.html.erb
54
68
  - app/views/lesli_admin/accounts/_account.html.erb
55
69
  - app/views/lesli_admin/accounts/_form.html.erb
@@ -64,9 +78,6 @@ files:
64
78
  - app/views/lesli_admin/dashboards/new.html.erb
65
79
  - app/views/lesli_admin/dashboards/show.html.erb
66
80
  - app/views/lesli_admin/partials/_engine-navigation.html.erb
67
- - app/views/lesli_admin/profiles/edit.html.erb
68
- - app/views/lesli_admin/profiles/index.html.erb
69
- - app/views/lesli_admin/profiles/new.html.erb
70
81
  - app/views/lesli_admin/profiles/show.html.erb
71
82
  - app/views/lesli_admin/users/edit.html.erb
72
83
  - app/views/lesli_admin/users/index.html.erb
@@ -75,6 +86,7 @@ files:
75
86
  - config/locales/translations.en.yml
76
87
  - config/locales/translations.es.yml
77
88
  - config/routes.rb
89
+ - db/migrate/0101000110_create_lesli_admin_accounts.rb
78
90
  - lib/lesli_admin.rb
79
91
  - lib/lesli_admin/engine.rb
80
92
  - lib/lesli_admin/version.rb
@@ -101,6 +113,7 @@ files:
101
113
  - lib/vue/stores/account_settings.js
102
114
  - lib/vue/stores/roles.js
103
115
  - lib/vue/stores/translations.json
116
+ - lib/vue/stores/user.js
104
117
  - lib/vue/stores/users.js
105
118
  - readme.md
106
119
  homepage: https://www.lesli.dev/