lesli 5.0.18 → 5.0.20
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/app/assets/stylesheets/lesli/application.css +1 -0
- data/app/controllers/lesli/abouts_controller.rb +3 -0
- data/app/controllers/lesli/application_controller.rb +3 -1
- data/app/controllers/lesli/application_lesli_controller.rb +1 -1
- data/app/helpers/lesli/navigation_helper.rb +6 -0
- data/app/interfaces/lesli/responder_interface.rb +35 -19
- data/app/models/concerns/account_initializer.rb +2 -3
- data/app/models/concerns/user_security.rb +5 -4
- data/app/models/lesli/role/action.rb +3 -2
- data/app/models/lesli/shared/dashboard.rb +2 -2
- data/app/models/lesli/user/session.rb +1 -1
- data/app/operators/lesli/role_operator.rb +9 -4
- data/app/services/lesli/role/action_service.rb +2 -3
- data/app/views/lesli/abouts/welcome.html.erb +8 -5
- data/app/views/lesli/apps/show.html.erb +23 -40
- data/app/views/lesli/errors/not_found.html.erb +32 -0
- data/app/views/lesli/errors/unauthorized.html.erb +48 -0
- data/app/views/lesli/layouts/application-lesli.html.erb +1 -2
- data/app/views/lesli/partials/_application-analytics.html.erb +2 -2
- data/app/views/lesli/partials/_application-lesli-header.html.erb +68 -65
- data/app/views/lesli/partials/_application-lesli-navigation.html.erb +22 -6
- data/config/importmap.rb +0 -10
- data/config/initializers/devise.rb +28 -0
- data/config/initializers/devise_rails_8_patch.rb +8 -0
- data/config/initializers/lesli.rb +27 -23
- data/db/migrate/v1/0000120310_create_lesli_role_privileges.rb +2 -2
- data/db/seed/users.rb +13 -9
- data/lib/generators/lesli/install/USAGE +5 -0
- data/lib/generators/lesli/install/install_generator.rb +49 -0
- data/lib/generators/lesli/install/templates/lesli.rb +6 -0
- data/lib/lesli/engine.rb +2 -14
- data/lib/lesli/routing.rb +8 -14
- data/lib/lesli/version.rb +2 -2
- data/lib/rspec/testers/request.rb +15 -6
- data/lib/scss/_apps.scss +93 -0
- data/lib/scss/application.scss +34 -0
- data/lib/tasks/lesli/db.rake +6 -6
- data/lib/tasks/lesli_tasks.rake +3 -0
- data/readme.md +11 -21
- metadata +48 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 126a19d2153659244f65bb4a49db4618786defe3328e86f2d7217bea1fb66ffb
|
4
|
+
data.tar.gz: 89b09d6eec6bb3e320c2eb09e07ae50011d047cf12668479c1565a117954506f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c51533de90a1b6ac70ed9d41f5b329fbbbb35660a348f1ce37aebf1cd29ead7ccaf94e5884c6389c1939c7e62a8b72a48317322b2c010f57a2bbb6a9f98cb3c
|
7
|
+
data.tar.gz: b1aec4ddf728cdd79d7a44ec0b2d5836773cf53d31ed09ceecbb068daeeadba185d6661063aaa1769a1beaf12748b21236ecbede30f032f268b8750cddf6a417
|
@@ -0,0 +1 @@
|
|
1
|
+
body.lesli.apps.show .lesli-element-header{margin-bottom:5rem !important}body.lesli.apps.show .engines{gap:24px;margin-inline-end:auto;margin-inline-start:auto}body.lesli.apps.show .engines a{flex-basis:318px;text-align:center;padding:2rem .4rem 2.8rem;border:#fff 1px solid;border-radius:6px;background-color:#fff;transition:all ease-in-out .2s;box-shadow:rgba(9,30,66,.25) 0px 4px 8px -2px,rgba(9,30,66,.08) 0px 0px 0px 1px}body.lesli.apps.show .engines a:hover{border-color:var(--lesli-color-primary);transform:translateY(-2px)}body.lesli.apps.show .engines a.is-active{background-color:#f0f4ff;border-color:var(--lesli-color-primary)}body.lesli.apps.show .engines a svg{margin-right:.4rem;fill:var(--lesli-color-primary)}body.lesli.apps.show .engines a p{font-size:14}body.lesli.apps.show .engines a span{font-weight:600;font-size:20px}body.lesli.apps.show .engines a span,body.lesli.apps.show .engines a p{color:var(--lesli-color-primary)}
|
@@ -34,6 +34,9 @@ module Lesli
|
|
34
34
|
class AboutsController < ApplicationLesliController
|
35
35
|
layout "lesli/layouts/application-public", only: [:welcome]
|
36
36
|
|
37
|
+
skip_before_action :authenticate_request, only: [:welcome] if defined?(LesliShield)
|
38
|
+
skip_before_action :authorize_request, only: [:welcome] if defined?(LesliShield)
|
39
|
+
|
37
40
|
# def status
|
38
41
|
# respond_with_successful({ :Lesli => "Ruby on Rails SaaS Development Framework." })
|
39
42
|
# end
|
@@ -33,8 +33,8 @@ Building a better future, one line of code at a time.
|
|
33
33
|
module Lesli
|
34
34
|
class ApplicationLesliController < ApplicationController
|
35
35
|
|
36
|
-
include Lesli::ResponderInterface
|
37
36
|
include Lesli::RequesterInterface
|
37
|
+
include Lesli::ResponderInterface
|
38
38
|
include Lesli::CustomizationInterface
|
39
39
|
include LesliAudit::LoggerInterface if defined?(LesliAudit)
|
40
40
|
include LesliShield::AuthenticationInterface if defined?(LesliShield)
|
@@ -33,6 +33,12 @@ Building a better future, one line of code at a time.
|
|
33
33
|
module Lesli
|
34
34
|
module NavigationHelper
|
35
35
|
|
36
|
+
def navigation_partial
|
37
|
+
engine = lesli_engine[:code]
|
38
|
+
path = engine == "root" ? "partials/navigation" : "#{engine}/partials/navigation"
|
39
|
+
lookup_context.exists?(path, [], true) ? path : nil
|
40
|
+
end
|
41
|
+
|
36
42
|
# Prints a separator line
|
37
43
|
def navigation_separator
|
38
44
|
content_tag(:li) do
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Lesli
|
4
4
|
|
5
|
-
Copyright (c)
|
5
|
+
Copyright (c) 2025, 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,17 +17,17 @@ 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 ·
|
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
|
26
|
-
@website https://lesli.tech
|
26
|
+
@website https://www.lesli.tech
|
27
27
|
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
28
28
|
|
29
|
-
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
30
|
-
// ·
|
29
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
30
|
+
// ·
|
31
31
|
=end
|
32
32
|
|
33
33
|
module Lesli
|
@@ -72,27 +72,43 @@ module Lesli
|
|
72
72
|
end
|
73
73
|
|
74
74
|
# JSON not found response
|
75
|
-
def respond_with_not_found
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
def respond_with_not_found message=nil
|
76
|
+
|
77
|
+
@message = message || I18n.t("core.shared.messages_danger_not_found")
|
78
|
+
respond_to do |format|
|
79
|
+
format.json{ respond_with_http(404, { message: @message }) }
|
80
|
+
format.html{ render('lesli/errors/not_found', status: :not_found) }
|
81
|
+
end
|
79
82
|
end
|
80
83
|
|
81
84
|
# JSON not found response
|
82
85
|
def respond_with_unauthorized(detail = {})
|
83
|
-
error_object = {}
|
84
86
|
|
85
|
-
error_object
|
86
|
-
|
87
|
+
@error_object = {
|
88
|
+
error_role: nil,
|
89
|
+
error_detail: nil,
|
90
|
+
error_message: I18n.t("core.shared.view_text_unauthorized_request")
|
91
|
+
}
|
87
92
|
|
88
|
-
|
93
|
+
unless Rails.env.production?
|
94
|
+
@error_object[:error_detail] = detail unless detail.empty?
|
95
|
+
if current_user.present?
|
96
|
+
@error_object[:error_role] = "( #{current_user.lesliroles.map(&:name).join(', ')} )"
|
97
|
+
end
|
98
|
+
end
|
89
99
|
|
90
100
|
respond_to do |format|
|
91
|
-
format.json
|
92
|
-
format.html
|
93
|
-
|
94
|
-
# format.xlsx
|
95
|
-
#
|
101
|
+
format.json{ render(status: :unauthorized, json: @error_object) }
|
102
|
+
format.html{ render('lesli/errors/unauthorized', status: :unauthorized) }
|
103
|
+
|
104
|
+
# format.xlsx do
|
105
|
+
# if Rails.env.production?
|
106
|
+
# redirect_to "/401" # Or a specific Excel error download if applicable
|
107
|
+
# else
|
108
|
+
# # For development, you might still want a JSON response for debugging
|
109
|
+
# render status: :unauthorized, json: error_object.to_json
|
110
|
+
# end
|
111
|
+
# end
|
96
112
|
end
|
97
113
|
end
|
98
114
|
|
@@ -58,8 +58,7 @@ module AccountInitializer
|
|
58
58
|
# Add base privileges to roles
|
59
59
|
Lesli::RoleOperator.new(owner).add_owner_actions
|
60
60
|
Lesli::RoleOperator.new(admin).add_owner_actions
|
61
|
-
Lesli::RoleOperator.new(limited).
|
62
|
-
|
61
|
+
Lesli::RoleOperator.new(limited).add_profile_actions
|
63
62
|
|
64
63
|
end
|
65
64
|
|
@@ -69,7 +68,7 @@ module AccountInitializer
|
|
69
68
|
|
70
69
|
LesliSystem.engines.each do |engine, data|
|
71
70
|
|
72
|
-
next if ["Lesli", "LesliBabel", "
|
71
|
+
next if ["Lesli", "LesliBabel", "Root"].include?(engine)
|
73
72
|
|
74
73
|
# Skip if the engine is not defined
|
75
74
|
next unless Object.const_defined?(engine)
|
@@ -73,10 +73,11 @@ module UserSecurity
|
|
73
73
|
# current_user.has_privileges?(controllers, actions)
|
74
74
|
def has_privileges_for?(controller, action)
|
75
75
|
begin
|
76
|
-
return
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
return self.privileges.where(
|
77
|
+
controller: controller,
|
78
|
+
action: action,
|
79
|
+
active: true
|
80
|
+
).exists?
|
80
81
|
rescue => exception
|
81
82
|
return false
|
82
83
|
end
|
@@ -34,14 +34,15 @@ module Lesli
|
|
34
34
|
class Role::Action < ApplicationLesliRecord
|
35
35
|
belongs_to :role
|
36
36
|
|
37
|
-
|
37
|
+
after_create :synchronize_privileges
|
38
|
+
after_update :synchronize_privileges
|
38
39
|
after_destroy :synchronize_privileges
|
39
40
|
|
40
41
|
belongs_to :action, class_name: "SystemController::Action"
|
41
42
|
belongs_to :system_controller_action, class_name: "SystemController::Action", foreign_key: "action_id"
|
42
43
|
|
43
44
|
def synchronize_privileges
|
44
|
-
Lesli::RoleOperator.new(self).synchronize
|
45
|
+
Lesli::RoleOperator.new(self.role, self).synchronize
|
45
46
|
end
|
46
47
|
|
47
48
|
def self.index current_user, query, role
|
@@ -34,13 +34,13 @@ module Lesli
|
|
34
34
|
module Shared
|
35
35
|
class DashboardFallback < ::Lesli::ApplicationLesliRecord
|
36
36
|
self.abstract_class = true
|
37
|
-
def self.
|
37
|
+
def self.initialize_account(account)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
base_class = "::LesliDashboard::Shared::Dashboard".safe_constantize || DashboardFallback
|
42
42
|
|
43
|
-
class Dashboard <
|
43
|
+
class Dashboard < base_class
|
44
44
|
self.abstract_class = true
|
45
45
|
end
|
46
46
|
end
|
@@ -34,12 +34,14 @@ module Lesli
|
|
34
34
|
class RoleOperator < Lesli::ApplicationLesliService
|
35
35
|
|
36
36
|
@role = nil
|
37
|
+
@action = nil
|
37
38
|
|
38
|
-
def initialize role
|
39
|
+
def initialize role, action=nil
|
39
40
|
@role = role
|
41
|
+
@action = action
|
40
42
|
end
|
41
43
|
|
42
|
-
def
|
44
|
+
def add_profile_actions
|
43
45
|
|
44
46
|
# Adding default system actions for profile descriptor
|
45
47
|
[
|
@@ -100,12 +102,15 @@ module Lesli
|
|
100
102
|
lesli_role_actions.role_id as role_id,
|
101
103
|
lesli_system_controllers.route as controller,
|
102
104
|
lesli_system_controller_actions.name as action,
|
103
|
-
|
105
|
+
lesli_role_actions.deleted_at IS NULL as active
|
104
106
|
)).with_deleted
|
105
107
|
|
106
108
|
|
107
109
|
# get privileges only for the given role, this is needed to sync only modified roles
|
108
|
-
records = records.where("lesli_role_actions.role_id" => @role)
|
110
|
+
records = records.where("lesli_role_actions.role_id" => @role.id)
|
111
|
+
|
112
|
+
# get privileges only for the given role action, this is needed to sync only modified actions
|
113
|
+
records = records.where("lesli_role_actions.id" => @action.id) if @action
|
109
114
|
|
110
115
|
|
111
116
|
# we use the deleted_at column to know if a privilege is enable or disable, NULL values
|
@@ -6,7 +6,7 @@ module Lesli
|
|
6
6
|
super(Lesli::Role::Action.with_deleted.find(id))
|
7
7
|
end
|
8
8
|
|
9
|
-
def index
|
9
|
+
def index role_id
|
10
10
|
|
11
11
|
def clean action
|
12
12
|
{
|
@@ -21,6 +21,7 @@ module Lesli
|
|
21
21
|
role_actions = {}
|
22
22
|
|
23
23
|
Lesli::Role::Action.with_deleted.joins(system_controller_action: :system_controller)
|
24
|
+
.where(:role_id => role_id)
|
24
25
|
.select(
|
25
26
|
:id,
|
26
27
|
:role_id,
|
@@ -68,8 +69,6 @@ module Lesli
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
|
-
|
72
|
-
|
73
72
|
role_actions
|
74
73
|
end
|
75
74
|
end
|
@@ -20,9 +20,9 @@ html, body, * {
|
|
20
20
|
background-color: #ffffff;
|
21
21
|
background-position: 0 0,55px 55px;
|
22
22
|
background-image:
|
23
|
-
radial-gradient(#0d52bf
|
24
|
-
radial-gradient(#0d52bf
|
25
|
-
animation: rotateBackground
|
23
|
+
radial-gradient(#0d52bf 1px, transparent 2px),
|
24
|
+
radial-gradient(#0d52bf 1px, #ffffff 2px);
|
25
|
+
animation: rotateBackground 10s linear infinite;
|
26
26
|
}
|
27
27
|
|
28
28
|
.page-welcome svg {
|
@@ -118,15 +118,18 @@ html, body, * {
|
|
118
118
|
The Open Source Ruby on Rails <span>SaaS Development Framework</span>
|
119
119
|
</h1>
|
120
120
|
<div class="buttons">
|
121
|
-
<a class="doc" target="blank" href="https://www.lesli.dev/">
|
121
|
+
<a class="doc" target="blank" href="https://www.lesli.dev/lesli/">
|
122
122
|
Documentation
|
123
123
|
</a>
|
124
124
|
<a class="start" target="blank" href="https://www.lesli.dev/start/">
|
125
125
|
Getting started
|
126
126
|
</a>
|
127
127
|
</div>
|
128
|
-
|
128
|
+
<% unless defined?(LesliShield) %>
|
129
|
+
<%= link_to("Apps", "/lesli/apps") unless defined?(LesliDashboard) %>
|
130
|
+
<% end %>
|
129
131
|
<% if defined?(LesliShield) %>
|
132
|
+
<%= link_to("Apps", "/lesli/apps") if user_signed_in? && !defined?(LesliDashboard) %>
|
130
133
|
<%= link_to("Dashboard", "/dashboard") if user_signed_in? && defined?(LesliDashboard) %>
|
131
134
|
<%= link_to("Logout", "/logout") if user_signed_in? %>
|
132
135
|
<%= link_to("Login", "/login") unless user_signed_in? %>
|
@@ -5,49 +5,32 @@ document.addEventListener('turbo:load', () => {
|
|
5
5
|
|
6
6
|
data.engines.forEach(id => {
|
7
7
|
const el = document.getElementById(id.replace("lesli"))
|
8
|
-
console.log(id.replace("lesli",""))
|
9
|
-
console.log(el)
|
10
8
|
if (el) el.style.display = 'none'
|
11
9
|
})
|
12
10
|
})
|
13
11
|
</script>
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
<%# 08. Security & Privacy %>
|
39
|
-
<%= navigation_engine_shield %>
|
40
|
-
<%= navigation_engine_security %>
|
41
|
-
|
42
|
-
<%# 09. Integrations %>
|
43
|
-
<%= navigation_engine_babel %>
|
44
|
-
</div>
|
45
|
-
<button class="button is-hidden-tablet">
|
46
|
-
<span class="icon">
|
47
|
-
<i class="ri-close-line"></i>
|
48
|
-
</span>
|
49
|
-
<span>close</span>
|
50
|
-
</button>
|
51
|
-
</div>
|
12
|
+
<%
|
13
|
+
@navigation_engines = [
|
14
|
+
:dashboard,
|
15
|
+
:admin,
|
16
|
+
:mailer,
|
17
|
+
:bell,
|
18
|
+
:calendar,
|
19
|
+
:papers,
|
20
|
+
:support,
|
21
|
+
:shield,
|
22
|
+
:security,
|
23
|
+
:audit,
|
24
|
+
:babel
|
25
|
+
]
|
26
|
+
%>
|
27
|
+
|
28
|
+
<%= render(LesliView::Layout::Container.new("lesli-apps", dashboard: false)) do %>
|
29
|
+
<%= render("lesli_dashboard/dashboards/shared/header") if defined?(LesliDashboard) %>
|
30
|
+
|
31
|
+
<section class="columns is-multiline is-mobile is-centered engines">
|
32
|
+
<% @navigation_engines.each do |engine| %>
|
33
|
+
<%= public_send("navigation_engine_#{engine}") %>
|
34
|
+
<% end %>
|
52
35
|
</section>
|
53
36
|
<% end %>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<style>
|
2
|
+
.error-404 .material-symbols {
|
3
|
+
font-size: 8rem;
|
4
|
+
color: rgb(190,190,190);
|
5
|
+
}
|
6
|
+
.error-404 h2 {
|
7
|
+
font-size: 2rem;
|
8
|
+
color: #3d211b;
|
9
|
+
}
|
10
|
+
|
11
|
+
.error-404 p {
|
12
|
+
font-size: 1.4rem;
|
13
|
+
font-weight: 300;
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
<%= render(LesliView::Layout::Container.new("accounts")) do %>
|
17
|
+
<section class="hero is-medium error-404">
|
18
|
+
<div class="hero-body has-text-centered">
|
19
|
+
|
20
|
+
<div class="mb-6">
|
21
|
+
<%= render(LesliView::Elements::Empty.new(text:nil)) %>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<h2 class="mb-4">404 Not found</h2>
|
25
|
+
|
26
|
+
<p>
|
27
|
+
<%= @message %>
|
28
|
+
</p>
|
29
|
+
</div>
|
30
|
+
</section>
|
31
|
+
<% end %>
|
32
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<style>
|
2
|
+
.error-401 .material-symbols {
|
3
|
+
font-size: 8rem;
|
4
|
+
color: rgb(190,190,190);
|
5
|
+
}
|
6
|
+
.error-401 h2 {
|
7
|
+
font-size: 2rem;
|
8
|
+
color: #7a0000;
|
9
|
+
}
|
10
|
+
|
11
|
+
.error-401 p {
|
12
|
+
font-size: 1.4rem;
|
13
|
+
font-weight: 300;
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
<%= render(LesliView::Layout::Container.new("accounts")) do %>
|
17
|
+
<section class="hero is-medium error-401">
|
18
|
+
<div class="hero-body has-text-centered">
|
19
|
+
|
20
|
+
<div class="mb-6">
|
21
|
+
<span class="icon">
|
22
|
+
<span class="material-symbols">
|
23
|
+
shield_lock
|
24
|
+
</span>
|
25
|
+
</span>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<h2 class="mb-4">401 Unauthorized</h2>
|
29
|
+
|
30
|
+
<p>
|
31
|
+
We could not validate your credentials.
|
32
|
+
Please ask the administrator to send you an invite to see this content.
|
33
|
+
</p>
|
34
|
+
|
35
|
+
<div class="box mt-6">
|
36
|
+
<ul>
|
37
|
+
<!--li><%= @error_object[:error_message] %></li-->
|
38
|
+
<li>
|
39
|
+
<%= @error_object.dig(:error_detail, :controller) %>
|
40
|
+
(<%= @error_object.dig(:error_detail, :action) %>)
|
41
|
+
</li>
|
42
|
+
<li><%= @error_object[:error_role] %></li>
|
43
|
+
</ul>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</section>
|
47
|
+
<% end %>
|
48
|
+
|
@@ -40,14 +40,13 @@ Building a better future, one line of code at a time.
|
|
40
40
|
</head>
|
41
41
|
<body class="<%= application_body_class %>">
|
42
42
|
<%= render(partial: "lesli/partials/application-lesli-header") %>
|
43
|
-
<%= render(partial: "lesli/partials/application-lesli-navigation") %>
|
44
43
|
<%= render(partial: "lesli/partials/application-lesli-notifications") %>
|
45
44
|
<main class="lesli-application-app">
|
46
45
|
<%= render(partial: "lesli/partials/application-lesli-sidebar") %>
|
47
46
|
<%= render(partial: "lesli/partials/application-lesli-content") %>
|
48
47
|
</main>
|
49
48
|
<%= render(partial: "lesli_assets/partials/application-lesli-icons-engines") %>
|
50
|
-
|
49
|
+
<%= render(partial: "lesli/partials/application-analytics") %>
|
51
50
|
<%= yield(:application_lesli_body_bottom) %>
|
52
51
|
</body>
|
53
52
|
</html>
|
@@ -36,14 +36,14 @@ Building a better future, one line of code at a time.
|
|
36
36
|
<% protected_controllers = ["confirmations"] %>
|
37
37
|
|
38
38
|
<% # Get an specific site tracking id or use the development default %>
|
39
|
-
<% tracking_id = Rails.application.credentials.dig(:providers, :
|
39
|
+
<% tracking_id = Rails.application.credentials.dig(:providers, :google, :tag_manager) || ENV["PROVIDERS_GOOGLE_TAG_MANAGER"] %>
|
40
40
|
|
41
41
|
<% # check if analytics is enabled in the settings file %>
|
42
42
|
<% enable_analytics = Lesli.config.security[:enable_analytics] %>
|
43
43
|
|
44
44
|
<% if Rails.env.production? && enable_analytics && tracking_id %>
|
45
45
|
|
46
|
-
<%
|
46
|
+
<% unless protected_controllers.include?(controller_name) %>
|
47
47
|
|
48
48
|
<!-- Google tag (gtag.js) -->
|
49
49
|
<script async src="https://www.googletagmanager.com/gtag/js?id=<%= tracking_id %>"></script>
|