lesli 5.0.21 → 5.0.23
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.
- checksums.yaml +4 -4
- data/Rakefile +4 -0
- data/app/assets/config/lesli_manifest.js +2 -2
- data/app/assets/images/lesli/brand/register-background.jpg +0 -0
- data/app/assets/stylesheets/lesli/application.css +192 -1
- data/app/controllers/lesli/abouts_controller.rb +12 -13
- data/app/controllers/lesli/application_controller.rb +1 -42
- data/app/controllers/lesli/application_lesli_controller.rb +8 -1
- data/app/controllers/lesli/apps_controller.rb +25 -0
- data/app/controllers/lesli/items/actions_controller.rb +122 -0
- data/app/{models/lesli/item/activity.rb → controllers/lesli/items/activities_controller.rb} +2 -2
- data/app/controllers/lesli/items/discussions_controller.rb +93 -0
- data/app/controllers/lesli/{system_controllers_controller.rb → resources_controller.rb} +3 -3
- data/app/controllers/lesli/shared/dashboards_controller.rb +11 -279
- data/app/helpers/lesli/customization_helper.rb +3 -3
- data/app/helpers/lesli/html_helper.rb +114 -2
- data/app/helpers/lesli/navigation_helper.rb +8 -25
- data/app/helpers/lesli/system_helper.rb +21 -4
- data/app/helpers/lesli/turbo_helper.rb +19 -2
- data/app/interfaces/lesli/requester_interface.rb +2 -29
- data/app/interfaces/lesli/responder_interface.rb +121 -61
- data/app/models/concerns/lesli/account_initializer.rb +13 -13
- data/{lib/rspec/factories/lesli_account.rb → app/models/concerns/lesli/account_logs.rb} +23 -9
- data/app/models/concerns/lesli/user_extensions.rb +33 -51
- data/app/models/lesli/account.rb +6 -5
- data/app/models/lesli/application_lesli_record.rb +14 -0
- data/app/models/lesli/items/action.rb +15 -0
- data/app/models/lesli/items/activity.rb +50 -0
- data/app/models/lesli/items/discussion.rb +15 -0
- data/app/models/lesli/{user/journal.rb → resource.rb} +9 -4
- data/app/models/lesli/role.rb +2 -17
- data/app/models/lesli/shared/dashboard.rb +1 -0
- data/app/models/lesli/user.rb +23 -77
- data/app/services/lesli/application_lesli_service.rb +21 -4
- data/app/{operators/lesli/controller_operator.rb → services/lesli/resource_service.rb} +92 -23
- data/app/services/lesli/role_service.rb +16 -10
- data/app/services/lesli/user_service.rb +28 -27
- data/app/views/lesli/abouts/welcome.html.erb +11 -11
- data/app/views/lesli/apps/show.html.erb +1 -1
- data/app/views/lesli/errors/not_found.html.erb +1 -1
- data/app/views/lesli/errors/unauthorized.html.erb +9 -11
- data/app/views/lesli/layouts/application-devise.html.erb +6 -9
- data/app/views/lesli/layouts/application-lesli.html.erb +9 -9
- data/app/views/lesli/layouts/application-public.html.erb +4 -18
- data/app/views/lesli/layouts/mailer.html.erb +1 -1
- data/app/views/lesli/partials/{_application-analytics.html.erb → _application-lesli-analytics.html.erb} +18 -9
- data/app/views/lesli/partials/{_application-lesli-scss.html.erb → _application-lesli-assets.html.erb} +9 -11
- data/{db/migrate/v1/0000110310_create_lesli_account_settings.rb → app/views/lesli/partials/_application-lesli-data.html.erb} +11 -7
- data/app/views/lesli/partials/{_application-head.html.erb → _application-lesli-head.html.erb} +2 -2
- data/app/views/lesli/partials/_application-lesli-header.html.erb +6 -6
- data/app/views/lesli/partials/_application-lesli-navigation.html.erb +3 -6
- data/app/views/lesli/partials/_application-lesli-notifications.html.erb +0 -1
- data/app/views/lesli/partials/turbo/_redirection.html.erb +5 -0
- data/app/views/lesli/{partials/_application-data.html.erb → shared/dashboards/edit.html.erb} +2 -6
- data/app/views/lesli/shared/dashboards/{_show.html.erb → show.html.erb} +3 -3
- data/config/brakeman.yml +55 -0
- data/config/importmap.rb +0 -3
- data/config/initializers/devise.rb +1 -2
- data/config/initializers/lesli.rb +27 -14
- data/config/initializers/lesli_migration_helpers.rb +0 -5
- data/config/locales/translations.en.yml +6 -2
- data/config/locales/translations.es.yml +5 -2
- data/config/locales/translations.fr.yml +1 -4
- data/config/locales/translations.it.yml +5 -2
- data/config/locales/translations.pt.yml +1 -4
- data/config/routes.rb +4 -6
- data/db/migrate/v1/{0000000310_create_lesli_users.rb → 0000000210_create_lesli_users.rb} +4 -0
- data/db/migrate/v1/{0000000210_create_lesli_roles.rb → 0000000310_create_lesli_roles.rb} +6 -0
- data/db/migrate/v1/{0000100110_create_lesli_system_controllers.rb → 0000000410_create_lesli_resources.rb} +8 -5
- data/db/seed/users.rb +1 -1
- data/db/seed/xyz.rb +3 -1
- data/lib/generators/lesli/spec/spec_generator.rb +0 -3
- data/lib/generators/lesli/view/view_generator.rb +0 -3
- data/lib/lesli/configuration.rb +1 -1
- data/{app/lib → lib}/lesli/courier.rb +40 -7
- data/lib/lesli/engine.rb +4 -5
- data/lib/lesli/{routing.rb → router.rb} +3 -2
- data/lib/lesli/version.rb +2 -2
- data/lib/lesli.rb +3 -2
- data/lib/migrate/common.rb +2 -0
- data/lib/migrate/items/action_structure.rb +2 -1
- data/lib/migrate/items/activity_structure.rb +12 -2
- data/lib/migrate/items/discussion_structure.rb +1 -1
- data/lib/scss/_apps.scss +1 -0
- data/lib/tasks/lesli/db.rake +5 -5
- data/lib/tasks/lesli/{controllers.rake → resources.rake} +4 -4
- data/lib/tasks/lesli_tasks.rake +13 -3
- data/lib/test/config.rb +111 -0
- data/{db/migrate/v1/0000130210_create_lesli_user_roles.rb → lib/test/helpers/response_integration_helper.rb} +12 -9
- data/{db/migrate/v1/0000100210_create_lesli_system_controller_actions.rb → lib/test/lesli.rb} +28 -9
- data/readme.md +61 -68
- metadata +49 -121
- data/app/helpers/lesli/assets_helper.rb +0 -110
- data/app/helpers/lesli/general_helper.rb +0 -96
- data/app/mailers/lesli/devise_mailer.rb +0 -67
- data/app/models/concerns/lesli/has_activities.rb +0 -29
- data/app/models/concerns/lesli/user_activities.rb +0 -163
- data/app/models/concerns/lesli/user_security.rb +0 -220
- data/app/models/lesli/account/detail.rb +0 -37
- data/app/models/lesli/account/log.rb +0 -57
- data/app/models/lesli/account/request.rb +0 -37
- data/app/models/lesli/descriptor/privilege.rb +0 -39
- data/app/models/lesli/descriptor.rb +0 -57
- data/app/models/lesli/role/action.rb +0 -73
- data/app/models/lesli/role/privilege.rb +0 -38
- data/app/models/lesli/system_controller/action.rb +0 -37
- data/app/models/lesli/system_controller.rb +0 -104
- data/app/models/lesli/user/activity.rb +0 -5
- data/app/models/lesli/user/detail.rb +0 -55
- data/app/models/lesli/user/request.rb +0 -38
- data/app/models/lesli/user/role.rb +0 -39
- data/app/models/lesli/user/session.rb +0 -79
- data/app/models/lesli/user/setting.rb +0 -46
- data/app/operators/lesli/role_operator.rb +0 -153
- data/app/services/lesli/role/action_service.rb +0 -75
- data/app/services/lesli/user/session_service.rb +0 -78
- data/app/validators/lesli/application_lesli_validator.rb +0 -67
- data/app/validators/lesli/users_validator.rb +0 -217
- data/app/views/lesli/emails/user_mailer/invitation.html.erb +0 -23
- data/app/views/lesli/partials/_application-lesli-annoouncements.html.erb +0 -49
- data/app/views/lesli/partials/_application-lesli-chatbox.html.erb +0 -35
- data/app/views/lesli/partials/_application-lesli-javascript.html.erb +0 -48
- data/app/views/lesli/partials/_application-lesli-panels.html.erb +0 -58
- data/app/views/lesli/partials/_application-public-footer.html.erb +0 -51
- data/app/views/lesli/partials/_application-public-javascript.html.erb +0 -49
- data/app/views/lesli/partials/_application-public-scss.html.erb +0 -35
- data/app/views/lesli/shared/dashboards/_edit.html.erb +0 -33
- data/app/views/lesli/wrappers/_application-devise-simple.erb +0 -59
- data/app/views/lesli/wrappers/_application-devise.html.erb +0 -76
- data/config/initializers/devise_rails_8_patch.rb +0 -8
- data/db/migrate/v1/0000110210_create_lesli_account_details.rb +0 -70
- data/db/migrate/v1/0000110410_create_lesli_account_activities.rb +0 -37
- data/db/migrate/v1/0000120210_create_lesli_role_actions.rb +0 -45
- data/db/migrate/v1/0000120310_create_lesli_role_privileges.rb +0 -45
- data/db/migrate/v1/0000130310_create_lesli_user_sessions.rb +0 -56
- data/db/migrate/v1/0000130410_create_lesli_user_activities.rb +0 -37
- data/db/migrate2/0000100510_create_lesli_account_locations.rb +0 -64
- data/db/migrate2/0000100610_create_lesli_account_currencies.rb +0 -48
- data/lib/assets/javascripts/lesli/i18n_js +0 -1095
- data/lib/migrate/shared/dashboard_structure.rb +0 -54
- data/lib/migrate/shared/setting_structure.rb +0 -20
- data/lib/rspec/config/spec_coverage.rb +0 -95
- data/lib/rspec/factories/lesli_role.rb +0 -62
- data/lib/rspec/factories/lesli_user.rb +0 -64
- data/lib/rspec/fixtures/files/lesli-icon.png +0 -0
- data/lib/rspec/fixtures/files/test_file_1.docx +0 -0
- data/lib/rspec/helpers/lesli_helper.rb +0 -54
- data/lib/rspec/helpers/rails_helper.rb +0 -134
- data/lib/rspec/helpers/response_request_helper.rb +0 -214
- data/lib/rspec/helpers/response_service_helper.rb +0 -66
- data/lib/rspec/helpers/spec_helper.rb +0 -99
- data/lib/rspec/lesli_api_tester.rb +0 -133
- data/lib/rspec/lesli_service_tester.rb +0 -46
- data/lib/rspec/testers/controller.rb +0 -63
- data/lib/rspec/testers/model.rb +0 -36
- data/lib/rspec/testers/request.rb +0 -93
data/app/models/lesli/user.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lesli
|
|
4
4
|
|
|
5
|
-
Copyright (c)
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
6
|
|
|
7
7
|
This program is free software: you can redistribute it and/or modify
|
|
8
8
|
it under the terms of the GNU General Public License as published by
|
|
@@ -32,10 +32,10 @@ Building a better future, one line of code at a time.
|
|
|
32
32
|
|
|
33
33
|
module Lesli
|
|
34
34
|
class User < ApplicationLesliRecord
|
|
35
|
-
include Lesli::UserSecurity
|
|
36
35
|
include Lesli::UserExtensions
|
|
37
|
-
|
|
36
|
+
include LesliShield::UserSecurity if defined?(LesliShield)
|
|
38
37
|
|
|
38
|
+
# user required configuration
|
|
39
39
|
validates(:email,
|
|
40
40
|
format: { with: URI::MailTo::EMAIL_REGEXP },
|
|
41
41
|
presence: true,
|
|
@@ -52,8 +52,6 @@ module Lesli
|
|
|
52
52
|
:confirmable,
|
|
53
53
|
:trackable
|
|
54
54
|
);
|
|
55
|
-
#:omniauthable, omniauth_providers: [:google_oauth2, :facebook]
|
|
56
|
-
|
|
57
55
|
|
|
58
56
|
# users belongs to an account only...
|
|
59
57
|
belongs_to :account, optional: true
|
|
@@ -67,24 +65,16 @@ module Lesli
|
|
|
67
65
|
# users data extensions
|
|
68
66
|
has_many :tokens
|
|
69
67
|
has_many :settings
|
|
70
|
-
has_many :sessions
|
|
71
|
-
has_many :
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
has_many :shortcuts, class_name: "LesliShield::User::Shortcuts"
|
|
75
|
-
|
|
68
|
+
has_many :sessions, class_name: 'LesliShield::User::Session'
|
|
69
|
+
has_many :requests, class_name: 'LesliAudit::UserRequest'
|
|
70
|
+
has_many :journals, class_name: 'LesliAudit::UserJournal'
|
|
71
|
+
has_many :logs, class_name: 'LesliAudit::UserLog'
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
#
|
|
79
|
-
has_many :
|
|
80
|
-
has_many :
|
|
81
|
-
has_many :privileges,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# callbacks
|
|
85
|
-
before_create :before_create_user
|
|
86
|
-
after_create :after_create_user
|
|
87
|
-
#after_update :update_associated_services
|
|
73
|
+
|
|
74
|
+
# Users can have many roles and too many privileges through the roles
|
|
75
|
+
has_many :user_roles, class_name: "LesliShield::User::Role"
|
|
76
|
+
has_many :roles, through: :user_roles, source: :role
|
|
77
|
+
has_many :privileges, through: :roles
|
|
88
78
|
|
|
89
79
|
|
|
90
80
|
# allow save duplicated users to execute callbacks
|
|
@@ -93,65 +83,21 @@ module Lesli
|
|
|
93
83
|
rescue ActiveRecord::RecordNotUnique => error
|
|
94
84
|
end
|
|
95
85
|
|
|
86
|
+
before_create :before_create_user
|
|
96
87
|
|
|
97
|
-
|
|
98
|
-
# @description Before creating a user we make sure there is no capitalized email
|
|
99
|
-
def before_create_user
|
|
100
|
-
self.email = self.email.downcase
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def after_create_user
|
|
105
|
-
self.activities.create(title: "create_user", description:"User created")
|
|
106
|
-
after_confirmation
|
|
107
|
-
after_account_assignation
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def after_account_assignation
|
|
112
|
-
return unless self.account
|
|
113
|
-
|
|
114
|
-
#Courier::One::Firebase::User.sync_user(self)
|
|
115
|
-
# Lesli::Courier.new(:lesli_calendar).from(:calendar_service, self).create({
|
|
116
|
-
# name: "Personal Calendar",
|
|
117
|
-
# default: true
|
|
118
|
-
# })
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
# Initialize user settings and dependencies needed
|
|
123
|
-
def after_confirmation
|
|
124
|
-
return unless self.confirmed?
|
|
125
|
-
|
|
126
|
-
self.activities.create(title: "create_user", description:"User confirmed")
|
|
127
|
-
|
|
128
|
-
# create an alias based on user name defined in user extensions
|
|
129
|
-
self.set_alias
|
|
88
|
+
private
|
|
130
89
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
90
|
+
def before_create_user
|
|
91
|
+
self.uid ||= loop do
|
|
92
|
+
candidate = generate_resource_uid(prefix:'LID')
|
|
93
|
+
break candidate unless self.account&.users&.exists?(uid: candidate)
|
|
94
|
+
end
|
|
134
95
|
end
|
|
135
96
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
# defined in user extensions
|
|
141
|
-
self.set_alias
|
|
142
|
-
|
|
143
|
-
return
|
|
144
|
-
if defined? CloudOne
|
|
145
|
-
|
|
146
|
-
data = {
|
|
147
|
-
full_name: self.user.full_name,
|
|
148
|
-
telephone: self.telephone,
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
CloudOne::Firebase::User.update_data(self.user, data)
|
|
152
|
-
|
|
153
|
-
end
|
|
154
|
-
end
|
|
97
|
+
def generate_resource_uid(prefix:'Lesli')
|
|
98
|
+
charset = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
99
|
+
letters = Array.new(4) { charset.chars.sample }.join
|
|
100
|
+
return "#{prefix}-#{letters}"
|
|
155
101
|
end
|
|
156
102
|
end
|
|
157
103
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lesli
|
|
4
4
|
|
|
5
|
-
Copyright (c)
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
6
|
|
|
7
7
|
This program is free software: you can redistribute it and/or modify
|
|
8
8
|
it under the terms of the GNU General Public License as published by
|
|
@@ -17,9 +17,9 @@ GNU General Public License for more details.
|
|
|
17
17
|
You should have received a copy of the GNU General Public License
|
|
18
18
|
along with this program. If not, see http://www.gnu.org/licenses/.
|
|
19
19
|
|
|
20
|
-
Lesli · Ruby on Rails SaaS
|
|
20
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
21
21
|
|
|
22
|
-
Made with ♥ by
|
|
22
|
+
Made with ♥ by LesliTech
|
|
23
23
|
Building a better future, one line of code at a time.
|
|
24
24
|
|
|
25
25
|
@contact hello@lesli.tech
|
|
@@ -28,7 +28,6 @@ Building a better future, one line of code at a time.
|
|
|
28
28
|
|
|
29
29
|
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
30
30
|
// ·
|
|
31
|
-
|
|
32
31
|
=end
|
|
33
32
|
|
|
34
33
|
# ·
|
|
@@ -149,6 +148,14 @@ module Lesli
|
|
|
149
148
|
self.resource
|
|
150
149
|
end
|
|
151
150
|
|
|
151
|
+
def cache_key_for_account(method=nil)
|
|
152
|
+
cache_key_builder('account',current_user.account.id,method)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def cache_key_for_user(method=nil)
|
|
156
|
+
cache_key_builder('user',current_user.id,method)
|
|
157
|
+
end
|
|
158
|
+
|
|
152
159
|
private
|
|
153
160
|
|
|
154
161
|
def response resource = nil
|
|
@@ -156,6 +163,16 @@ module Lesli
|
|
|
156
163
|
self
|
|
157
164
|
end
|
|
158
165
|
|
|
166
|
+
def cache_key_builder(namespace,namespace_id,method)
|
|
167
|
+
[
|
|
168
|
+
namespace,
|
|
169
|
+
namespace_id,
|
|
170
|
+
self.class.name.underscore,
|
|
171
|
+
method,
|
|
172
|
+
query[:cacheKey]
|
|
173
|
+
].compact.join(":").tr("/_", "-")
|
|
174
|
+
end
|
|
175
|
+
|
|
159
176
|
attr_reader :current_user
|
|
160
177
|
|
|
161
178
|
attr_reader :resource
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lesli
|
|
4
4
|
|
|
5
|
-
Copyright (c)
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
6
|
|
|
7
7
|
This program is free software: you can redistribute it and/or modify
|
|
8
8
|
it under the terms of the GNU General Public License as published by
|
|
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
|
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
33
|
module Lesli
|
|
34
|
-
class
|
|
34
|
+
class ResourceService < Lesli::ApplicationLesliService
|
|
35
35
|
|
|
36
36
|
DEVISE_CONTROLLERS = [
|
|
37
37
|
"users/registrations",
|
|
@@ -43,7 +43,72 @@ module Lesli
|
|
|
43
43
|
def initialize
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
def index matrix:false
|
|
47
|
+
|
|
48
|
+
# get a matrix of controllers and actions
|
|
49
|
+
c = Resource.actions.joins(:parent).select(
|
|
50
|
+
"parents_lesli_resources.engine as engine",
|
|
51
|
+
"parents_lesli_resources.route as route",
|
|
52
|
+
"parents_lesli_resources.identifier as controller",
|
|
53
|
+
"parents_lesli_resources.label as controller_name",
|
|
54
|
+
"parents_lesli_resources.id as controller_id",
|
|
55
|
+
"lesli_resources.action as action",
|
|
56
|
+
"lesli_resources.id as action_id",
|
|
57
|
+
"case lesli_resources.action
|
|
58
|
+
when 'index' then 1
|
|
59
|
+
when 'show' then 2
|
|
60
|
+
when 'new' then 3
|
|
61
|
+
when 'edit' then 4
|
|
62
|
+
when 'create' then 5
|
|
63
|
+
when 'update' then 6
|
|
64
|
+
when 'destroy' then 7
|
|
65
|
+
when 'options' then 8
|
|
66
|
+
else 9
|
|
67
|
+
end as importance
|
|
68
|
+
"
|
|
69
|
+
)
|
|
70
|
+
.where("parents_lesli_resources.deleted_at is NULL")
|
|
71
|
+
.order("importance DESC")
|
|
72
|
+
|
|
73
|
+
return c unless matrix
|
|
74
|
+
|
|
75
|
+
cc = {}
|
|
76
|
+
|
|
77
|
+
# convert the matrix to a hash of engines with controllers and available actions as values
|
|
78
|
+
# example:
|
|
79
|
+
# my_engine: { my_controller: [ my list of actions ]}
|
|
80
|
+
c.each do |c|
|
|
81
|
+
|
|
82
|
+
engine = c[:engine]
|
|
83
|
+
controller = c[:controller]
|
|
84
|
+
|
|
85
|
+
# create a uniq container for every action that belongs to a specific controller
|
|
86
|
+
if cc[engine].blank?
|
|
87
|
+
cc[engine] = {}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# create a uniq container for every action that belongs to a specific controller
|
|
91
|
+
if cc[engine][controller].blank?
|
|
92
|
+
cc[engine][controller] = {
|
|
93
|
+
id: c[:controller_id],
|
|
94
|
+
name: c[:controller_name],
|
|
95
|
+
route: c[:route],
|
|
96
|
+
actions: []
|
|
97
|
+
}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# push every action to his specic controller
|
|
101
|
+
cc[engine][controller][:actions].push({
|
|
102
|
+
id: c[:action_id],
|
|
103
|
+
action: c[:action]
|
|
104
|
+
})
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
return cc
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Scan new routes added and create role privileges
|
|
47
112
|
def build
|
|
48
113
|
|
|
49
114
|
# get all the engines, controllers and actions
|
|
@@ -60,24 +125,26 @@ module Lesli
|
|
|
60
125
|
# cloud_bell/notifications converts to CloudBell::Notifications
|
|
61
126
|
# sometimes we need a second split to deal with third level deep of controllers
|
|
62
127
|
# Example: "Account::Currency::ExchangeRatesController" from "account/currency/exchange_rates"
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}).find_or_create_by!(route: controller_route)
|
|
78
|
-
|
|
128
|
+
identifier = controller_route
|
|
129
|
+
.camelize
|
|
130
|
+
.gsub('/', '::')
|
|
131
|
+
|
|
132
|
+
name = identifier.demodulize.humanize
|
|
133
|
+
|
|
134
|
+
controller = Lesli::Resource.find_or_initialize_by(route: controller_route)
|
|
135
|
+
controller.assign_attributes(
|
|
136
|
+
label: name,
|
|
137
|
+
engine: engine,
|
|
138
|
+
identifier: identifier
|
|
139
|
+
)
|
|
140
|
+
controller.save!
|
|
141
|
+
|
|
79
142
|
controller_actions.each do |action_name|
|
|
80
|
-
controller.
|
|
143
|
+
controller.children.find_or_create_by!(
|
|
144
|
+
action: action_name,
|
|
145
|
+
identifier: action_name,
|
|
146
|
+
label: action_name.humanize
|
|
147
|
+
)
|
|
81
148
|
end
|
|
82
149
|
end
|
|
83
150
|
end
|
|
@@ -89,15 +156,15 @@ module Lesli
|
|
|
89
156
|
|
|
90
157
|
# Global container
|
|
91
158
|
controller_list = {
|
|
92
|
-
"
|
|
159
|
+
"rails_app" => {},
|
|
93
160
|
"lesli" => {}
|
|
94
161
|
}
|
|
95
162
|
|
|
96
163
|
# Get the list of controllers and actions of the main rails app
|
|
97
164
|
Rails.application.routes.routes.each do |route|
|
|
98
165
|
|
|
99
|
-
list = "
|
|
100
|
-
route = route.defaults
|
|
166
|
+
list = "rails_app"
|
|
167
|
+
route = route.defaults
|
|
101
168
|
|
|
102
169
|
# filter the non-used main app routes
|
|
103
170
|
next if route[:controller].blank?
|
|
@@ -106,6 +173,7 @@ module Lesli
|
|
|
106
173
|
next if route[:controller].include? "active_storage"
|
|
107
174
|
next if route[:controller].include? "view_components"
|
|
108
175
|
next if route[:controller].include? "turbo/native/navigation"
|
|
176
|
+
next if route[:controller].include? "lesli/abouts" #default welcome page
|
|
109
177
|
|
|
110
178
|
if DEVISE_CONTROLLERS.include?(route[:controller])
|
|
111
179
|
list = "lesli"
|
|
@@ -132,6 +200,7 @@ module Lesli
|
|
|
132
200
|
# validate if route has information, some special routes like redirects
|
|
133
201
|
# can generate an empty entry in the route hash
|
|
134
202
|
next if route.empty?
|
|
203
|
+
next if route[:controller].include? "rails/health"
|
|
135
204
|
|
|
136
205
|
# get the engine code
|
|
137
206
|
engine_code = engine_info[:code]
|
|
@@ -42,7 +42,7 @@ module Lesli
|
|
|
42
42
|
# according to object level permission
|
|
43
43
|
def list(params)
|
|
44
44
|
current_user.account.roles
|
|
45
|
-
.where("permission_level <= ?", current_user.
|
|
45
|
+
.where("permission_level <= ?", current_user.max_level_permission)
|
|
46
46
|
.order(permission_level: :desc, name: :asc)
|
|
47
47
|
.select(:id, :name, :permission_level)
|
|
48
48
|
end
|
|
@@ -52,29 +52,35 @@ module Lesli
|
|
|
52
52
|
# @description Return a paginated array of users, used mostly in frontend views
|
|
53
53
|
def index
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
:name => ["owner"]
|
|
57
|
-
).joins("
|
|
55
|
+
users_subquery = <<-SQL
|
|
58
56
|
left join (
|
|
59
57
|
select
|
|
60
58
|
count(1) users,
|
|
61
59
|
role_id
|
|
62
|
-
from
|
|
60
|
+
from lesli_shield_user_roles
|
|
63
61
|
inner join lesli_users as u
|
|
64
|
-
on u.id =
|
|
62
|
+
on u.id = lesli_shield_user_roles.user_id
|
|
65
63
|
and u.deleted_at is null
|
|
66
|
-
where
|
|
64
|
+
where lesli_shield_user_roles.deleted_at is null
|
|
67
65
|
group by (role_id)
|
|
68
66
|
) users on users.role_id = lesli_roles.id
|
|
69
|
-
|
|
67
|
+
SQL
|
|
68
|
+
|
|
69
|
+
actions_subquery = <<-SQL
|
|
70
70
|
left join (
|
|
71
71
|
select
|
|
72
72
|
count(1) actions,
|
|
73
73
|
role_id
|
|
74
|
-
from
|
|
74
|
+
from lesli_shield_role_actions
|
|
75
75
|
group by role_id
|
|
76
76
|
) actions on actions.role_id = lesli_roles.id
|
|
77
|
-
|
|
77
|
+
SQL
|
|
78
|
+
|
|
79
|
+
current_user.account.roles
|
|
80
|
+
.where.not(:name => ['owner'])
|
|
81
|
+
.where("lesli_roles.permission_level <= ?", current_user.max_level_permission)
|
|
82
|
+
.joins(users_subquery)
|
|
83
|
+
.joins(actions_subquery)
|
|
78
84
|
.select(
|
|
79
85
|
:id,
|
|
80
86
|
:name,
|
|
@@ -34,7 +34,6 @@ module Lesli
|
|
|
34
34
|
class UserService < Lesli::ApplicationLesliService
|
|
35
35
|
|
|
36
36
|
def find id
|
|
37
|
-
#super(current_user.account.users.joins(:detail).find_by(id: id))
|
|
38
37
|
super(current_user.account.users.find_by(id: id))
|
|
39
38
|
end
|
|
40
39
|
|
|
@@ -89,40 +88,36 @@ module Lesli
|
|
|
89
88
|
# TODO: Implement pg_search
|
|
90
89
|
def index params
|
|
91
90
|
|
|
92
|
-
#
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
from lesli_user_sessions us
|
|
109
|
-
where us.deleted_at is null
|
|
110
|
-
group by(us.user_id)
|
|
111
|
-
) sessions on sessions.user_id = lesli_users.id"
|
|
91
|
+
# Build user full name
|
|
92
|
+
fullname_sql = "TRIM(CONCAT(lesli_users.first_name, ' ', lesli_users.last_name))"
|
|
93
|
+
|
|
94
|
+
# Build user status
|
|
95
|
+
status_sql = "case when lesli_users.active is true then 'active' else 'inactive' end"
|
|
96
|
+
|
|
97
|
+
# Get all the roles assigned to the user
|
|
98
|
+
roles_subquery = <<-SQL
|
|
99
|
+
LEFT JOIN (
|
|
100
|
+
SELECT ur.user_id, string_agg(r.name, ', ' ORDER BY r.name) as rolenames
|
|
101
|
+
FROM lesli_shield_user_roles ur
|
|
102
|
+
JOIN lesli_roles r ON r.id = ur.role_id
|
|
103
|
+
WHERE ur.deleted_at IS NULL
|
|
104
|
+
GROUP BY ur.user_id
|
|
105
|
+
) roles ON roles.user_id = lesli_users.id
|
|
106
|
+
SQL
|
|
112
107
|
|
|
113
108
|
current_user.account.users
|
|
114
|
-
.joins(
|
|
115
|
-
.joins(sql_string_for_user_sessions)
|
|
116
|
-
.page(query[:pagination][:page])
|
|
117
|
-
.per(query[:pagination][:perPage])
|
|
109
|
+
.joins(roles_subquery)
|
|
118
110
|
.select(
|
|
119
111
|
:id,
|
|
120
|
-
"CONCAT(COALESCE(lesli_users.first_name, ''), ' ', COALESCE(lesli_users.last_name, '')) as fullname",
|
|
121
112
|
:email,
|
|
122
113
|
:active,
|
|
123
|
-
|
|
114
|
+
"#{status_sql} AS status",
|
|
115
|
+
"#{fullname_sql} AS fullname",
|
|
116
|
+
"COALESCE(roles.rolenames, '') AS rolenames",
|
|
124
117
|
Date2.new.date_time.db_column("current_sign_in_at")
|
|
125
118
|
)
|
|
119
|
+
.page(query.dig(:pagination, :page))
|
|
120
|
+
.per(query.dig(:pagination, :perPage))
|
|
126
121
|
end
|
|
127
122
|
|
|
128
123
|
# Creates a query that selects all user information from several tables if CloudLock is present
|
|
@@ -137,6 +132,12 @@ module Lesli
|
|
|
137
132
|
# })
|
|
138
133
|
|
|
139
134
|
if resource.update(params)
|
|
135
|
+
|
|
136
|
+
# Set the user alias based on the full_name.
|
|
137
|
+
if resource.alias.empty?
|
|
138
|
+
resource.update(alias: resource.full_name_initials())
|
|
139
|
+
end
|
|
140
|
+
|
|
140
141
|
# new_attributes = resource.detail.attributes.merge({
|
|
141
142
|
# active: resource.active
|
|
142
143
|
# })
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<style>
|
|
2
|
+
html, body, * {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
}
|
|
5
|
+
|
|
2
6
|
html, body {
|
|
3
7
|
margin: 0;
|
|
4
8
|
padding: 0;
|
|
5
9
|
}
|
|
6
10
|
|
|
7
|
-
html, body, * {
|
|
8
|
-
box-sizing: border-box;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
11
|
.page-welcome {
|
|
12
12
|
display: flex;
|
|
13
13
|
flex-direction: column;
|
|
@@ -59,11 +59,11 @@ html, body, * {
|
|
|
59
59
|
align-items: center;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
.buttons {
|
|
62
|
+
.page-welcome .buttons {
|
|
63
63
|
margin-bottom: 2rem;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
.buttons a {
|
|
66
|
+
.page-welcome .buttons a {
|
|
67
67
|
border: none;
|
|
68
68
|
display: inline-block;
|
|
69
69
|
text-decoration: none;
|
|
@@ -79,25 +79,25 @@ html, body, * {
|
|
|
79
79
|
line-height: 28px;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
.buttons a.doc {
|
|
82
|
+
.page-welcome .buttons a.doc {
|
|
83
83
|
background: #184fee;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
.buttons a.start {
|
|
86
|
+
.page-welcome .buttons a.start {
|
|
87
87
|
background: #444444;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
@media only screen and (max-width: 600px) {
|
|
91
|
-
.page-welcome svg {
|
|
91
|
+
.page-welcome .page-welcome svg {
|
|
92
92
|
width: 250px;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
.page-welcome h1 {
|
|
95
|
+
.page-welcome .page-welcome h1 {
|
|
96
96
|
padding: 0 1rem;
|
|
97
97
|
font-size: 2.7rem;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
.buttons a {
|
|
100
|
+
.page-welcome .buttons a {
|
|
101
101
|
padding: 14px 20px;
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -15,6 +15,7 @@ document.addEventListener('turbo:load', () => {
|
|
|
15
15
|
:admin,
|
|
16
16
|
:mailer,
|
|
17
17
|
:bell,
|
|
18
|
+
:contacts,
|
|
18
19
|
:calendar,
|
|
19
20
|
:papers,
|
|
20
21
|
:support,
|
|
@@ -27,7 +28,6 @@ document.addEventListener('turbo:load', () => {
|
|
|
27
28
|
|
|
28
29
|
<%= render(LesliView::Layout::Container.new("lesli-apps", dashboard: false)) do %>
|
|
29
30
|
<%= render("lesli_dashboard/dashboards/shared/header") if defined?(LesliDashboard) %>
|
|
30
|
-
|
|
31
31
|
<section class="columns is-multiline is-mobile is-centered engines">
|
|
32
32
|
<% @navigation_engines.each do |engine| %>
|
|
33
33
|
<%= public_send("navigation_engine_#{engine}") %>
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<style>
|
|
2
|
-
.error-
|
|
2
|
+
.error-403 .material-symbols {
|
|
3
3
|
font-size: 8rem;
|
|
4
|
-
color:
|
|
4
|
+
color: #7a0000;
|
|
5
5
|
}
|
|
6
|
-
.error-
|
|
6
|
+
.error-403 h2 {
|
|
7
7
|
font-size: 2rem;
|
|
8
8
|
color: #7a0000;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.error-
|
|
11
|
+
.error-403 p {
|
|
12
12
|
font-size: 1.4rem;
|
|
13
13
|
font-weight: 300;
|
|
14
14
|
}
|
|
15
15
|
</style>
|
|
16
16
|
<%= render(LesliView::Layout::Container.new("accounts")) do %>
|
|
17
|
-
<section class="hero is-medium error-
|
|
17
|
+
<section class="hero is-medium error-403">
|
|
18
18
|
<div class="hero-body has-text-centered">
|
|
19
19
|
|
|
20
20
|
<div class="mb-6">
|
|
@@ -25,19 +25,17 @@
|
|
|
25
25
|
</span>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
|
-
<h2 class="mb-4">
|
|
28
|
+
<h2 class="mb-4">403 <%= I18n.t("lesli.shared.message_error_unauthorized") %></h2>
|
|
29
29
|
|
|
30
30
|
<p>
|
|
31
|
-
|
|
32
|
-
Please ask the administrator to send you an invite to see this content.
|
|
31
|
+
<%= I18n.t("lesli.shared.message_error_unauthorized_credentials") %>
|
|
33
32
|
</p>
|
|
34
33
|
|
|
35
34
|
<div class="box mt-6">
|
|
36
35
|
<ul>
|
|
37
|
-
<!--li><%= @error_object[:error_message] %></li-->
|
|
38
36
|
<li>
|
|
39
|
-
<%= @error_object.dig(:
|
|
40
|
-
(<%= @error_object.dig(:
|
|
37
|
+
<%= @error_object.dig(:error_details, :controller) %>
|
|
38
|
+
(<%= @error_object.dig(:error_details, :action) %>)
|
|
41
39
|
</li>
|
|
42
40
|
<li><%= @error_object[:error_role] %></li>
|
|
43
41
|
</ul>
|