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.
@@ -29,4 +29,5 @@ Building a better future, one line of code at a time.
29
29
  // ·
30
30
  */
31
31
 
32
- body.lesli-admin-users { @import "users"; }
32
+ body.lesli-admin-users,
33
+ body.lesli-admin-profile { @import "users"; }
@@ -36,7 +36,7 @@ module LesliAdmin
36
36
  # GET /profiles/1
37
37
  def show
38
38
  respond_to do |format|
39
- format.html { }
39
+ format.html
40
40
  format.json { respond_with_successful(@profile.show) }
41
41
  end
42
42
  end
@@ -45,7 +45,7 @@ module LesliAdmin
45
45
 
46
46
  # Use callbacks to share common setup or constraints between actions.
47
47
  def set_profile
48
- @profile = Lesli::UserService.new(current_user, query).find(current_user.id)
48
+ @profile = UserService.new(current_user, query).find(current_user.id)
49
49
  end
50
50
 
51
51
  # Only allow a list of trusted parameters through.
@@ -31,23 +31,208 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module LesliAdmin
34
- class UsersController < ApplicationController
35
- #before_action :set_user, only: [:show]
34
+ class UsersController < Lesli::ApplicationLesliController
35
+ before_action :set_user, only: [
36
+ :show,
37
+ :update,
38
+ :destroy,
39
+ :requestpassword,
40
+ :passwordreset,
41
+ :revokeaccess,
42
+ :logout
43
+ ]
44
+
45
+ # GET /users/list
46
+ def list
47
+ respond_to do |format|
48
+ format.json {
49
+ respond_with_successful(UserService.new("current_user").list(query, params))
50
+ }
51
+ end
52
+ end
36
53
 
37
54
  # GET /users
38
55
  def index
56
+ respond_to do |format|
57
+ format.html
58
+ format.json {
59
+ return respond_with_pagination(UserService.new(current_user, query).index(params))
60
+ }
61
+ end
39
62
  end
40
63
 
41
64
  def show
65
+ respond_to do |format|
66
+ format.html
67
+ format.json {
68
+ return respond_with_not_found unless @user.found?
69
+ return respond_with_successful(@user.show)
70
+ }
71
+ end
42
72
  end
43
73
 
44
- def new
74
+ def create
75
+ user = UserService.new(current_user).create(user_params)
76
+ if user.successful?
77
+ respond_with_successful(user.result)
78
+ else
79
+ respond_with_error("Error creating user", user.errors)
80
+ end
45
81
  end
82
+
83
+ def update
46
84
 
47
- def edit
48
- end
85
+ # check if the user trully exists
86
+ return respond_with_not_found unless @user.found?
49
87
 
50
- private
88
+ # update the user information
89
+ @user.update(user_params)
51
90
 
91
+ # check saved
92
+ if @user.successful?
93
+ respond_with_successful(@user.result)
94
+ else
95
+ respond_with_error(@user.errors)
96
+ end
97
+ end
98
+
99
+ def destroy
100
+ return respond_with_not_found unless @user
101
+
102
+ # get the user found in the UserServices
103
+ user = @user.result
104
+
105
+ if user.delete
106
+ current_user.logs.create({ title: "deleted_user", description: "by_user_id: #{ current_user.email }" })
107
+ respond_with_successful()
108
+ else
109
+ respond_with_error(user.errors.full_messages.to_sentence)
110
+ end
111
+ end
112
+
113
+ # Force the user to update his password
114
+ def requestpassword
115
+ if @user.request_password
116
+ respond_with_successful
117
+ else
118
+ respond_with_error
119
+ end
120
+ end
121
+
122
+ # Reset password (generate random)
123
+ def passwordreset
124
+
125
+ pass = @user.password_reset
126
+
127
+ if pass
128
+ respond_with_successful(pass)
129
+ else
130
+ respond_with_error
131
+ end
132
+ end
133
+
134
+ # this method is going to close all the open user sessions
135
+ def logout
136
+ if @user.logout
137
+ respond_with_successful
138
+ else
139
+ respond_with_error
140
+ end
141
+ end
142
+
143
+ # Remove all user access
144
+ def revokeaccess
145
+ if @user.revoke_access
146
+ respond_with_successful
147
+ else
148
+ respond_with_error
149
+ end
150
+ end
151
+
152
+ def become
153
+
154
+ # always should be disabled
155
+ if Rails.configuration.lesli.dig(:security, :enable_becoming) != true
156
+ return respond_with_unauthorized
157
+ end
158
+
159
+ # Allow only sysadmin to become as user
160
+ return respond_with_unauthorized if current_user.email != Rails.application.config.lesli.dig(:account, :user, :email) # sysadmin user
161
+
162
+ # Search for desire user
163
+ becoming_user = User.find(params[:id])
164
+
165
+ # Return an error if user does not exist
166
+ return respond_with_error I18n.t("core.shared.messages_warning_user_not_found") if becoming_user.blank?
167
+
168
+ # Extrictly save a log when becoming
169
+ current_user.activities.create!({
170
+ users_id: becoming_user.id,
171
+ owner_id: current_user.id,
172
+ description: "#{current_user.full_name} -> #{becoming_user.full_name}",
173
+ category: "action_become"
174
+ })
175
+
176
+ # Sign in as the becoming user
177
+ sign_in(:user, becoming_user)
178
+
179
+ # Create a new session for the becoming user
180
+ becoming_session = becoming_user.sessions.create({
181
+ :user_agent => get_user_agent,
182
+ :user_remote => request.remote_ip,
183
+ :session_source => "become_session",
184
+ :last_used_at => LC::Date.now,
185
+ :expiration_at => 60.minutes.from_now
186
+ })
187
+
188
+ # assign the session of the becomer user to the becoming user
189
+ session[:user_session_id] = becoming_session[:id]
190
+
191
+ # Response successful
192
+ respond_with_successful([current_user, becoming_user])
193
+
194
+ end
195
+
196
+ def options
197
+ respond_with_successful({
198
+ #regions: current_user.account.locations.where(level: "region"),
199
+ salutations: User::Detail.salutations.map {|k, v| {value: k, text: v}},
200
+ locales: Rails.application.config.lesli.dig(:configuration, :locales_available),
201
+ mfa_methods: Rails.application.config.lesli.dig(:configuration, :mfa_methods)
202
+ })
203
+ end
204
+
205
+ private
206
+
207
+ # @return [void]
208
+ # @description Sets the requested user based on the current_users's account
209
+ # @example
210
+ # # Executing this method from a controller action:
211
+ # set_user
212
+ # puts @user
213
+ # # This will either display nil or an instance of Account::User
214
+ def set_user
215
+ @user = UserService.new(current_user).find(params[:id])
216
+ end
217
+
218
+ def user_params
219
+ params.require(:user).permit(
220
+ :active,
221
+ :email,
222
+ :alias,
223
+ :roles_id,
224
+ :first_name,
225
+ :last_name,
226
+ :telephone,
227
+ detail_attributes: [
228
+ :title,
229
+ :salutation,
230
+ :address,
231
+ :work_city,
232
+ :work_region,
233
+ :work_address
234
+ ]
235
+ )
236
+ end
52
237
  end
53
238
  end
@@ -31,36 +31,8 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module LesliAdmin
34
- class Account < Lesli::Account
35
-
36
- # accounts always belongs to a user
37
- belongs_to :user, optional: true
38
-
39
- # account resources
40
- has_many :users
41
-
42
- has_one :bell, class_name: "LesliBell::Account"
43
-
44
-
45
-
46
- # account statuses
47
- enum status: [
48
- :registered,
49
- :onboarding,
50
- :active,
51
- :suspended
52
- ]
53
-
54
-
55
- # company region (GDPR)
56
- enum region: {
57
- latin_america: "latin_america",
58
- united_states: "united_states",
59
- european_union: "european_union"
60
- }
61
-
62
-
63
- # required a name for the lesli account
64
- validates :company_name, :presence => true
34
+ class Account < ApplicationRecord
35
+ belongs_to :account, class_name: "Lesli::Account"
36
+ has_many :users, class_name: "Lesli::User"
65
37
  end
66
38
  end
@@ -0,0 +1,265 @@
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,6 +1,5 @@
1
1
  ---
2
2
  :en:
3
- users:
4
- title_users: Users
5
- dashboards:
6
- button_my: My button in my dashboard
3
+ lesli_admin:
4
+ shared:
5
+ button_save: Save
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  :es:
3
- users:
4
- title_users: Usuarios
5
- dashboards:
6
- button_my: Mi boton en mi dashboard
3
+ lesli_admin:
4
+ shared:
5
+ button_save: Guardar
data/config/routes.rb CHANGED
@@ -3,7 +3,7 @@ LesliAdmin::Engine.routes.draw do
3
3
  root to: "dashboards#show"
4
4
  resource :dashboard, only: [:show]
5
5
 
6
- resource :profile
6
+ resource :profile, only: [:show]
7
7
 
8
8
  resource :account, only: [:show]
9
9
  resources :users, only: [:index, :show, :new]
@@ -0,0 +1,42 @@
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
+ class CreateLesliAdminAccounts < ActiveRecord::Migration[6.0]
34
+ def change
35
+ create_table :lesli_admin_accounts do |t|
36
+ t.integer :status
37
+ t.datetime :deleted_at, index: true
38
+ t.timestamps
39
+ end
40
+ add_reference(:lesli_admin_accounts, :account, foreign_key: { to_table: :lesli_accounts })
41
+ end
42
+ end
@@ -1,4 +1,4 @@
1
1
  module LesliAdmin
2
- VERSION = "0.2.0"
3
- BUILD = "1696737766"
2
+ VERSION = "0.3.0"
3
+ BUILD = "1697000148"
4
4
  end
@@ -36,7 +36,7 @@ import { ref, reactive, onMounted, watch, computed } from "vue"
36
36
 
37
37
 
38
38
  // · import lesli stores
39
- import { useAccount } from "LesliAdmin/stores/account"
39
+ import { useAccount } from "Lesli/stores/account"
40
40
 
41
41
 
42
42
  // · implement stores
@@ -36,7 +36,7 @@ import { computed, onMounted } from "vue"
36
36
 
37
37
 
38
38
  // · import lesli stores
39
- import { useAccount } from "LesliAdmin/stores/account"
39
+ import { useAccount } from "Lesli/stores/account"
40
40
 
41
41
 
42
42
  // · import account components
@@ -6,7 +6,6 @@ import { lesliChartLine } from "lesli-vue/components"
6
6
  <template>
7
7
  <lesli-application-container>
8
8
  <lesli-header title="Dashboard"></lesli-header>
9
-
10
9
  <div class="columns">
11
10
  <div class="column">
12
11
  <lesli-application-component>