lesli 5.1.11 → 5.1.13
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 +3 -0
- data/app/assets/stylesheets/lesli/application.css +43 -3
- data/app/controllers/lesli/application_devise_controller.rb +9 -5
- data/app/controllers/lesli/application_lesli_controller.rb +4 -0
- data/app/controllers/lesli/items/attachments_controller.rb +200 -0
- data/app/controllers/lesli/items/discussions_controller.rb +94 -67
- data/app/controllers/lesli/items/tasks_controller.rb +132 -62
- data/app/helpers/lesli/turbo_helper.rb +0 -18
- data/app/interfaces/lesli/responder_interface.rb +58 -38
- data/app/mailers/lesli/application_lesli_mailer.rb +34 -8
- data/app/models/concerns/lesli/account_initializer.rb +11 -3
- data/app/models/concerns/lesli/account_logs.rb +5 -16
- data/app/models/concerns/lesli/items/activities.rb +29 -33
- data/app/models/concerns/lesli/items/attachments.rb +88 -0
- data/app/models/concerns/lesli/items/discussions.rb +25 -11
- data/app/models/concerns/lesli/items/ownership.rb +27 -0
- data/app/models/concerns/lesli/items/tasks.rb +26 -6
- data/app/models/concerns/lesli/user_extensions.rb +5 -9
- data/app/models/lesli/account.rb +10 -14
- data/app/models/lesli/items/activity.rb +25 -2
- data/app/models/lesli/items/attachment.rb +117 -0
- data/app/models/lesli/items/discussion.rb +6 -2
- data/app/models/lesli/items/task.rb +3 -1
- data/app/models/lesli/user.rb +12 -21
- data/app/views/lesli/abouts/welcome.html.erb +22 -20
- data/app/views/lesli/apps/show.html.erb +1 -1
- data/app/views/lesli/errors/not_found.html.erb +7 -21
- data/app/views/lesli/errors/unauthorized.html.erb +11 -27
- data/app/views/lesli/layouts/application-devise.html.erb +10 -9
- data/app/views/lesli/layouts/application-lesli.html.erb +1 -1
- data/app/views/lesli/partials/_application-lesli-assets.html.erb +3 -3
- data/app/views/lesli/partials/_application-lesli-header.html.erb +5 -9
- data/app/views/lesli/partials/_application-lesli-notifications.html.erb +19 -2
- data/app/views/lesli/partials/_application-lesli-sidebar.html.erb +3 -3
- data/config/initializers/lesli.rb +4 -1
- data/config/locales/translations.en.yml +34 -0
- data/config/locales/translations.es.yml +34 -0
- data/db/seed/accounts.rb +5 -5
- data/db/seed/users.rb +8 -16
- data/db/seed/xyz.rb +38 -17
- data/lib/lesli/engine.rb +0 -4
- data/lib/lesli/router.rb +5 -2
- data/lib/lesli/version.rb +2 -2
- data/lib/migrate/items/activity_structure.rb +8 -8
- data/lib/migrate/items/attachment_structure.rb +9 -14
- data/lib/migrate/items/discussion_structure.rb +5 -5
- data/lib/migrate/items/task_structure.rb +2 -3
- data/lib/migrate/shared/account_structure.rb +1 -1
- data/lib/tasks/lesli_tasks.rake +2 -3
- data/readme.md +3 -3
- data/test/fixtures/lesli_accounts.yml +18 -0
- data/test/fixtures/lesli_users.yml +23 -0
- metadata +18 -26
- data/app/assets/stylesheets/lesli/application.tailwind.css +0 -66
- data/config/brakeman.yml +0 -44
- data/config/initializers/devise.rb +0 -27
|
@@ -1,32 +1,18 @@
|
|
|
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
1
|
<%= render(LesliView::Layout::Container.new("accounts")) do %>
|
|
17
|
-
<section class="
|
|
18
|
-
<div class="
|
|
2
|
+
<section class="px-4 py-24 sm:px-6 sm:py-36" aria-labelledby="not-found-title">
|
|
3
|
+
<div class="mx-auto max-w-2xl text-center">
|
|
19
4
|
|
|
20
|
-
<div class="mb-6">
|
|
5
|
+
<div class="mb-6" aria-hidden="true">
|
|
21
6
|
<%= render(LesliView::Elements::Empty.new(text:nil)) %>
|
|
22
7
|
</div>
|
|
23
8
|
|
|
24
|
-
<h2 class="mb-4
|
|
9
|
+
<h2 id="not-found-title" class="mb-4 text-[2rem] font-semibold leading-tight text-[#3d211b]">
|
|
10
|
+
404 <%= I18n.t("lesli.shared.message_error_not_found") %>
|
|
11
|
+
</h2>
|
|
25
12
|
|
|
26
|
-
<p>
|
|
13
|
+
<p class="text-[1.4rem] font-light leading-relaxed text-neutral-700">
|
|
27
14
|
<%= @message %>
|
|
28
15
|
</p>
|
|
29
16
|
</div>
|
|
30
17
|
</section>
|
|
31
18
|
<% end %>
|
|
32
|
-
|
|
@@ -1,38 +1,23 @@
|
|
|
1
|
-
<style>
|
|
2
|
-
.error-403 .material-symbols {
|
|
3
|
-
font-size: 8rem;
|
|
4
|
-
color: #7a0000;
|
|
5
|
-
}
|
|
6
|
-
.error-403 h2 {
|
|
7
|
-
font-size: 2rem;
|
|
8
|
-
color: #7a0000;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.error-403 p {
|
|
12
|
-
font-size: 1.4rem;
|
|
13
|
-
font-weight: 300;
|
|
14
|
-
}
|
|
15
|
-
</style>
|
|
16
1
|
<%= render(LesliView::Layout::Container.new("accounts")) do %>
|
|
17
|
-
<section class="
|
|
18
|
-
<div class="
|
|
2
|
+
<section class="px-4 py-24 sm:px-6 sm:py-36" aria-labelledby="unauthorized-title">
|
|
3
|
+
<div class="mx-auto max-w-2xl text-center">
|
|
19
4
|
|
|
20
|
-
<div class="mb-6">
|
|
21
|
-
<span class="
|
|
22
|
-
|
|
23
|
-
shield_lock
|
|
24
|
-
</span>
|
|
5
|
+
<div class="mb-6" aria-hidden="true">
|
|
6
|
+
<span class="material-symbols !text-[8rem] leading-none text-danger-800">
|
|
7
|
+
shield_lock
|
|
25
8
|
</span>
|
|
26
9
|
</div>
|
|
27
10
|
|
|
28
|
-
<h2 class="mb-4
|
|
11
|
+
<h2 id="unauthorized-title" class="mb-4 text-[2rem] font-semibold leading-tight text-danger-800">
|
|
12
|
+
403 <%= I18n.t("lesli.shared.message_error_unauthorized") %>
|
|
13
|
+
</h2>
|
|
29
14
|
|
|
30
|
-
<p>
|
|
15
|
+
<p class="text-[1.4rem] font-light leading-relaxed text-neutral-700">
|
|
31
16
|
<%= I18n.t("lesli.shared.message_error_unauthorized_credentials") %>
|
|
32
17
|
</p>
|
|
33
18
|
|
|
34
|
-
<div class="
|
|
35
|
-
<ul>
|
|
19
|
+
<div class="mx-auto mt-6 max-w-xl rounded-lg border border-neutral-200 bg-white p-5 text-sm text-neutral-600 shadow-sm">
|
|
20
|
+
<ul class="space-y-1">
|
|
36
21
|
<li>
|
|
37
22
|
<%= @error_object.dig(:error_details, :controller) %>
|
|
38
23
|
(<%= @error_object.dig(:error_details, :action) %>)
|
|
@@ -43,4 +28,3 @@
|
|
|
43
28
|
</div>
|
|
44
29
|
</section>
|
|
45
30
|
<% end %>
|
|
46
|
-
|
|
@@ -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
|
|
@@ -27,28 +27,29 @@ Building a better future, one line of code at a time.
|
|
|
27
27
|
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
28
28
|
|
|
29
29
|
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
30
|
-
// ·
|
|
30
|
+
// ·
|
|
31
31
|
%>
|
|
32
32
|
|
|
33
|
-
<% public_app_controller = controller_path.split(
|
|
33
|
+
<% public_app_controller = controller_path.split("/")[1] || controller_path %>
|
|
34
34
|
|
|
35
35
|
<!DOCTYPE html>
|
|
36
|
-
<html lang="
|
|
36
|
+
<html lang="<%= I18n.locale %>">
|
|
37
37
|
<head>
|
|
38
38
|
<%= render(partial: "lesli/partials/application-lesli-head") %>
|
|
39
|
-
<%=
|
|
40
|
-
<%= stylesheet_link_tag(lesli_asset_path(:
|
|
41
|
-
|
|
39
|
+
<%= yield :head %>
|
|
40
|
+
<%= stylesheet_link_tag(lesli_asset_path(:lesli_assets, "public"), media: "all") %>
|
|
41
|
+
<%= stylesheet_link_tag(lesli_asset_path(:lesli_shield, public_app_controller), media: "all") %>
|
|
42
|
+
<%# Prevent browser history from reopening an authenticated page after logout. %>
|
|
42
43
|
<% if flash[:logout] == true %>
|
|
43
44
|
<script>
|
|
44
45
|
history.pushState(null, null, null, null, null);
|
|
45
|
-
window.addEventListener(
|
|
46
|
+
window.addEventListener("popstate", function () {
|
|
46
47
|
history.pushState(null, null, null, null, null);
|
|
47
48
|
});
|
|
48
49
|
</script>
|
|
49
50
|
<% end %>
|
|
50
51
|
</head>
|
|
51
|
-
<body class="<%= lesli_application_body_class
|
|
52
|
+
<body class="<%= lesli_application_body_class %>">
|
|
52
53
|
<%= yield %>
|
|
53
54
|
<%= render(partial: "lesli/partials/application-lesli-analytics") %>
|
|
54
55
|
</body>
|
|
@@ -45,7 +45,7 @@ Building a better future, one line of code at a time.
|
|
|
45
45
|
<body class="<%= lesli_application_body_class() %>">
|
|
46
46
|
<%= render(partial: "lesli/partials/application-lesli-header") %>
|
|
47
47
|
<%= render(partial: "lesli/partials/application-lesli-notifications") %>
|
|
48
|
-
<main class="
|
|
48
|
+
<main class="flex mb-10">
|
|
49
49
|
<%= render(partial: "lesli/partials/application-lesli-sidebar") %>
|
|
50
50
|
<%= render(partial: "lesli/partials/application-lesli-content") %>
|
|
51
51
|
</main>
|
|
@@ -50,9 +50,9 @@ Building a better future, one line of code at a time.
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
<%# Loading stylesheets from engines %>
|
|
53
|
-
<%= stylesheet_link_tag(lesli_asset_path(:lesli_assets, 'application
|
|
54
|
-
<%= stylesheet_link_tag(lesli_asset_path(:
|
|
55
|
-
<%= stylesheet_link_tag(lesli_asset_path(
|
|
53
|
+
<%= stylesheet_link_tag(lesli_asset_path(:lesli_assets, 'application'), media: "all") %>
|
|
54
|
+
<%= stylesheet_link_tag(lesli_asset_path(:lesli_view, 'view'), media: "all") %>
|
|
55
|
+
<%= stylesheet_link_tag(lesli_asset_path(), media: "all") %>
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
<%# Loading javascripts from engines %>
|
|
@@ -107,20 +107,16 @@ Building a better future, one line of code at a time.
|
|
|
107
107
|
<i class="ri-apps-2-line text-[24px] leading-none" aria-hidden="true"></i>
|
|
108
108
|
<% end %>
|
|
109
109
|
|
|
110
|
-
<% if defined?(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
current: current_page?(lesli_admin.profile_path) ? "page" : nil
|
|
116
|
-
},
|
|
110
|
+
<% if defined?(LesliShield) %>
|
|
111
|
+
|
|
112
|
+
<%= link_to lesli_shield.profile_path,
|
|
113
|
+
class: header_action_class,
|
|
114
|
+
aria: { label: profile_label },
|
|
117
115
|
title: profile_label,
|
|
118
116
|
data: { turbo_frame: "_top" } do %>
|
|
119
117
|
<i class="ri-user-smile-line text-[24px] leading-none" aria-hidden="true"></i>
|
|
120
118
|
<% end %>
|
|
121
|
-
<% end %>
|
|
122
119
|
|
|
123
|
-
<% if defined?(LesliShield) %>
|
|
124
120
|
<%= link_to main_app.destroy_user_session_path,
|
|
125
121
|
class: logout_action_class,
|
|
126
122
|
aria: { label: logout_label },
|
|
@@ -32,10 +32,27 @@ Building a better future, one line of code at a time.
|
|
|
32
32
|
=end
|
|
33
33
|
%>
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
<%
|
|
36
|
+
notification_classes = {
|
|
37
|
+
"info" => "border-info-300 bg-info-50 text-info-900",
|
|
38
|
+
"notice" => "border-success-300 bg-success-50 text-success-900",
|
|
39
|
+
"success" => "border-success-300 bg-success-50 text-success-900",
|
|
40
|
+
"warning" => "border-warning-300 bg-warning-50 text-warning-900",
|
|
41
|
+
"alert" => "border-danger-300 bg-danger-50 text-danger-900",
|
|
42
|
+
"danger" => "border-danger-300 bg-danger-50 text-danger-900",
|
|
43
|
+
"error" => "border-danger-300 bg-danger-50 text-danger-900",
|
|
44
|
+
"default" => "border-neutral-300 bg-neutral-50 text-neutral-900"
|
|
45
|
+
}.freeze
|
|
46
|
+
%>
|
|
47
|
+
|
|
48
|
+
<section
|
|
49
|
+
id="application-lesli-notifications"
|
|
50
|
+
class="fixed inset-x-0 z-[999] mx-auto w-[90%] max-w-[600px]"
|
|
51
|
+
aria-live="polite"
|
|
52
|
+
aria-atomic="true">
|
|
36
53
|
<% if flash.any? %>
|
|
37
54
|
<% flash.each do |type, message| %>
|
|
38
|
-
<div class="notification
|
|
55
|
+
<div class="animate-lesli-notification my-1 break-words rounded-lg border-2 px-4 py-3 text-center text-sm font-medium shadow-sm <%= notification_classes.fetch(type.to_s, notification_classes["default"]) %>">
|
|
39
56
|
<%= message %>
|
|
40
57
|
</div>
|
|
41
58
|
<% end %>
|
|
@@ -40,9 +40,9 @@ Building a better future, one line of code at a time.
|
|
|
40
40
|
|
|
41
41
|
<%# render navigation partial %>
|
|
42
42
|
<% if custom_sidebar_exists %>
|
|
43
|
-
<aside class="
|
|
44
|
-
<nav>
|
|
45
|
-
<ul>
|
|
43
|
+
<aside class="flex w-[50px] shrink-0 flex-col pt-12 pl-12 transition-all duration-200 ease-linear min-[769px]:w-[100px] min-[1024px]:w-[200px] min-[1216px]:w-[225px] min-[1408px]:w-[328px]">
|
|
44
|
+
<nav class="overflow-y-scroll rounded-lg bg-white pt-[.8rem] pb-4 pl-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" aria-label="Module navigation">
|
|
45
|
+
<ul>
|
|
46
46
|
<%= render partial: custom_sidebar_path %>
|
|
47
47
|
</ul>
|
|
48
48
|
</nav>
|
|
@@ -127,7 +127,10 @@ Lesli.configure do |config|
|
|
|
127
127
|
prefix: 'LA',
|
|
128
128
|
enable_logs: true,
|
|
129
129
|
enable_journals: true,
|
|
130
|
-
enable_analytics: true
|
|
130
|
+
enable_analytics: true,
|
|
131
|
+
journal_retention_days: 90,
|
|
132
|
+
analytics_retention_days: 400,
|
|
133
|
+
audit_retention_days: nil
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
|
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
:en:
|
|
3
3
|
lesli:
|
|
4
|
+
items:
|
|
5
|
+
activities:
|
|
6
|
+
empty: No activities have been recorded yet.
|
|
7
|
+
unknown_actor: Unknown user
|
|
8
|
+
discussions:
|
|
9
|
+
add: Add comment
|
|
10
|
+
created: Comment added successfully
|
|
11
|
+
empty: No comments have been added yet.
|
|
12
|
+
invalid: Comment could not be added
|
|
13
|
+
unknown_author: Unknown user
|
|
14
|
+
tasks:
|
|
15
|
+
add: Add task
|
|
16
|
+
complete_action: Mark task as complete
|
|
17
|
+
completed: Task completed successfully
|
|
18
|
+
created: Task created successfully
|
|
19
|
+
empty: No tasks have been added yet.
|
|
20
|
+
reopen_action: Mark task as incomplete
|
|
21
|
+
reopened: Task reopened successfully
|
|
22
|
+
attachments:
|
|
23
|
+
add: Add file
|
|
24
|
+
category: Category
|
|
25
|
+
choose_file: Choose a file
|
|
26
|
+
created: File uploaded successfully
|
|
27
|
+
deleted: File removed successfully
|
|
28
|
+
download: Download
|
|
29
|
+
empty: No files have been attached yet.
|
|
30
|
+
label: Label
|
|
31
|
+
remove: Remove
|
|
32
|
+
confirm_remove: Remove this file?
|
|
33
|
+
uploading: Uploading...
|
|
34
|
+
errors:
|
|
35
|
+
required: must be attached
|
|
36
|
+
too_large: must be smaller than %{size}
|
|
37
|
+
unsupported_type: has an unsupported file type
|
|
4
38
|
header:
|
|
5
39
|
applications: Applications
|
|
6
40
|
dashboard: Lesli Dashboard
|
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
:es:
|
|
3
3
|
lesli:
|
|
4
|
+
items:
|
|
5
|
+
activities:
|
|
6
|
+
empty: Todavía no se ha registrado actividad.
|
|
7
|
+
unknown_actor: Usuario desconocido
|
|
8
|
+
discussions:
|
|
9
|
+
add: Agregar comentario
|
|
10
|
+
created: Comentario agregado exitosamente
|
|
11
|
+
empty: Todavía no se han agregado comentarios.
|
|
12
|
+
invalid: No se pudo agregar el comentario
|
|
13
|
+
unknown_author: Usuario desconocido
|
|
14
|
+
tasks:
|
|
15
|
+
add: Agregar tarea
|
|
16
|
+
complete_action: Marcar tarea como completada
|
|
17
|
+
completed: Tarea completada exitosamente
|
|
18
|
+
created: Tarea creada exitosamente
|
|
19
|
+
empty: Todavía no se han agregado tareas.
|
|
20
|
+
reopen_action: Marcar tarea como pendiente
|
|
21
|
+
reopened: Tarea reabierta exitosamente
|
|
22
|
+
attachments:
|
|
23
|
+
add: Agregar archivo
|
|
24
|
+
category: Categoría
|
|
25
|
+
choose_file: Seleccionar archivo
|
|
26
|
+
created: Archivo subido exitosamente
|
|
27
|
+
deleted: Archivo eliminado exitosamente
|
|
28
|
+
download: Descargar
|
|
29
|
+
empty: Todavía no se han adjuntado archivos.
|
|
30
|
+
label: Etiqueta
|
|
31
|
+
remove: Eliminar
|
|
32
|
+
confirm_remove: ¿Eliminar este archivo?
|
|
33
|
+
uploading: Subiendo...
|
|
34
|
+
errors:
|
|
35
|
+
required: debe ser adjuntado
|
|
36
|
+
too_large: debe ser menor de %{size}
|
|
37
|
+
unsupported_type: tiene un tipo de archivo no permitido
|
|
4
38
|
header:
|
|
5
39
|
applications: Aplicaciones
|
|
6
40
|
dashboard: Panel de Lesli
|
data/db/seed/accounts.rb
CHANGED
|
@@ -41,14 +41,14 @@ account = Lesli::Account.find_or_create_by(email: company[:email]) do |account|
|
|
|
41
41
|
account.status = 'active'
|
|
42
42
|
account.save!
|
|
43
43
|
|
|
44
|
-
# account.detail.company_name = company[:name]
|
|
45
|
-
# account.detail.public_email = company[:email]
|
|
46
|
-
# account.detail.company_tagline = company[:tag_line] || ""
|
|
44
|
+
# account.admin.detail.company_name = company[:name]
|
|
45
|
+
# account.admin.detail.public_email = company[:email]
|
|
46
|
+
# account.admin.detail.company_tagline = company[:tag_line] || ""
|
|
47
47
|
# #account.registered!
|
|
48
|
-
# account.detail.save!
|
|
48
|
+
# account.admin.detail.save!
|
|
49
49
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# print some separators so will be easy to find these messages later
|
|
53
|
-
Termline.br(
|
|
53
|
+
Termline.br(2);
|
|
54
54
|
Termline.success("Account #{ account.name } <#{ account.email }> successfully created!")
|
data/db/seed/users.rb
CHANGED
|
@@ -31,17 +31,17 @@ Building a better future, one line of code at a time.
|
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
# get the account information
|
|
36
|
-
account = Lesli::Account.
|
|
35
|
+
account = Lesli::Account.find_by!(email: Lesli.config.company.fetch(:email))
|
|
37
36
|
|
|
38
37
|
|
|
39
|
-
#
|
|
40
|
-
email_domain = account
|
|
38
|
+
# extract the domain name from the main email address
|
|
39
|
+
email_domain = account.email.to_s.split("@", 2).second
|
|
40
|
+
raise ArgumentError, "The account email must include a domain" if email_domain.blank?
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
# get the emails for the initial accounts
|
|
44
|
-
emailowner = account
|
|
44
|
+
emailowner = account.email
|
|
45
45
|
emailadmin = "admin@#{email_domain}"
|
|
46
46
|
emailguest = "guest@#{email_domain}"
|
|
47
47
|
|
|
@@ -64,17 +64,9 @@ end
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
# create the owner user for the account,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# print the owner user credentials, so we can save those credentials
|
|
73
|
-
Termline.success(
|
|
74
|
-
"Owner user created successfully with email: #{emailowner} and password: #{passowner}",
|
|
75
|
-
"Admin user created successfully with email: #{emailadmin} and password: #{passadmin}",
|
|
76
|
-
"Admin user created successfully with email: #{emailguest} and password: #{passguest}"
|
|
77
|
-
)
|
|
67
|
+
create_account_user(account: account, email: emailowner, role_name: "owner", first_name: "Owner", last_name: account.name, password: passowner)
|
|
68
|
+
create_account_user(account: account, email: emailadmin, role_name: "admin", first_name: "Admin", last_name: account.name, password: passadmin)
|
|
69
|
+
create_account_user(account: account, email: emailguest, role_name: "guest", first_name: "Guest", last_name: account.name, password: passguest)
|
|
78
70
|
|
|
79
71
|
|
|
80
72
|
# print some separators so will be easy to find these messages later
|
data/db/seed/xyz.rb
CHANGED
|
@@ -30,27 +30,48 @@ Building a better future, one line of code at a time.
|
|
|
30
30
|
// ·
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
|
-
def create_account_user email
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
user.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
def create_account_user(account:, email:, role_name:, first_name:, last_name:, password: nil)
|
|
34
|
+
user = Lesli::User.find_or_initialize_by(email: email)
|
|
35
|
+
authentication_enabled =
|
|
36
|
+
user.respond_to?(:password=) &&
|
|
37
|
+
user.respond_to?(:password_confirmation=)
|
|
38
|
+
credentials_created = false
|
|
39
|
+
|
|
40
|
+
Lesli::User.transaction do
|
|
41
|
+
user.assign_attributes(
|
|
42
|
+
account: account,
|
|
43
|
+
first_name: first_name,
|
|
44
|
+
last_name: last_name
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# LesliShield installs Devise directly on the Core user model. Checking
|
|
48
|
+
# the model capability keeps this seeder independent from Devise and
|
|
49
|
+
# allows Lesli Core to seed users without an authentication engine.
|
|
50
|
+
if authentication_enabled && user.encrypted_password.blank?
|
|
51
|
+
raise ArgumentError, "A password is required when authentication is enabled" if password.blank?
|
|
52
|
+
|
|
53
|
+
user.password = password
|
|
54
|
+
user.password_confirmation = password
|
|
55
|
+
user.skip_confirmation! if user.respond_to?(:skip_confirmation!)
|
|
56
|
+
credentials_created = true
|
|
57
|
+
end
|
|
45
58
|
|
|
46
|
-
user.first_name = firstname
|
|
47
|
-
user.last_name = lastname
|
|
48
59
|
user.save!
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
# Role assignments are owned by LesliShield and should only be created
|
|
62
|
+
# when its concrete join model is available.
|
|
63
|
+
if authentication_enabled && defined?(LesliShield::User::Role)
|
|
64
|
+
role = account.roles.find_by!(name: role_name)
|
|
65
|
+
user.user_roles.find_or_create_by!(role: role)
|
|
52
66
|
end
|
|
67
|
+
end
|
|
53
68
|
|
|
54
|
-
|
|
69
|
+
if credentials_created
|
|
70
|
+
Termline.success(
|
|
71
|
+
"#{role_name.capitalize} user created successfully with " \
|
|
72
|
+
"email: #{email} and password: #{password}"
|
|
73
|
+
)
|
|
55
74
|
end
|
|
75
|
+
|
|
76
|
+
user
|
|
56
77
|
end
|
data/lib/lesli/engine.rb
CHANGED
|
@@ -38,10 +38,6 @@ require "kaminari"
|
|
|
38
38
|
require "termline"
|
|
39
39
|
require "acts_as_paranoid"
|
|
40
40
|
|
|
41
|
-
# The hole Lesli ecosystem depends on current_user, so we
|
|
42
|
-
# include the dependency in the core
|
|
43
|
-
require "devise"
|
|
44
|
-
|
|
45
41
|
require "lesli_date"
|
|
46
42
|
require "lesli_view"
|
|
47
43
|
require "lesli_assets"
|
data/lib/lesli/router.rb
CHANGED
|
@@ -74,10 +74,13 @@ module Lesli
|
|
|
74
74
|
router.namespace :items do
|
|
75
75
|
|
|
76
76
|
# Load item tasks
|
|
77
|
-
router.resources :tasks, only: %i[
|
|
77
|
+
router.resources :tasks, only: %i[update create]
|
|
78
78
|
|
|
79
79
|
# Load item discussions
|
|
80
|
-
router.resources :discussions, only:
|
|
80
|
+
router.resources :discussions, only: :create
|
|
81
|
+
|
|
82
|
+
# Load attachments
|
|
83
|
+
router.resources :attachments, only: %i[index show create destroy]
|
|
81
84
|
end
|
|
82
85
|
|
|
83
86
|
# Optional: health check inside engine scope (pick a consistent path)
|
data/lib/lesli/version.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
|
|
@@ -35,7 +35,7 @@ module MigrationHelpers
|
|
|
35
35
|
module ActivityStructure
|
|
36
36
|
def create_table_lesli_item_activities_10(engine)
|
|
37
37
|
|
|
38
|
-
table_name,
|
|
38
|
+
table_name, = table_name_for_items(engine, :activities)
|
|
39
39
|
|
|
40
40
|
create_table table_name do |t|
|
|
41
41
|
|
|
@@ -43,13 +43,13 @@ module MigrationHelpers
|
|
|
43
43
|
t.string :description
|
|
44
44
|
|
|
45
45
|
# Tipo principal del registro
|
|
46
|
-
t.string :activity_type, null: false, default:
|
|
46
|
+
t.string :activity_type, null: false, default: "activity"
|
|
47
47
|
|
|
48
48
|
# Subtipo para actividades
|
|
49
|
-
t.string :activity_code
|
|
49
|
+
t.string :activity_code, null: false
|
|
50
50
|
|
|
51
51
|
# Metadatos opcionales (JSON)
|
|
52
|
-
t.json :metadata, default: {}
|
|
52
|
+
t.json :metadata, null: false, default: {}
|
|
53
53
|
|
|
54
54
|
# Polymorphic target
|
|
55
55
|
t.string :subject_type, null: false
|
|
@@ -59,9 +59,9 @@ module MigrationHelpers
|
|
|
59
59
|
t.datetime :deleted_at, index: true
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
63
|
-
add_reference(table_name, :account, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
64
|
-
add_index(table_name, [:
|
|
62
|
+
add_reference(table_name, :user, null: false, foreign_key: { to_table: :lesli_users })
|
|
63
|
+
add_reference(table_name, :account, null: false, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
64
|
+
add_index(table_name, [:subject_type, :subject_id, :deleted_at, :created_at, :id], name: "#{table_name}_timeline")
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
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
|
|
@@ -33,29 +33,24 @@ Building a better future, one line of code at a time.
|
|
|
33
33
|
module MigrationHelpers
|
|
34
34
|
module Items
|
|
35
35
|
module AttachmentStructure
|
|
36
|
-
def create_table_lesli_item_attachments_10(
|
|
36
|
+
def create_table_lesli_item_attachments_10(engine)
|
|
37
37
|
|
|
38
|
-
table_name,
|
|
38
|
+
table_name, = table_name_for_items(engine, :attachments)
|
|
39
39
|
|
|
40
40
|
create_table table_name do |t|
|
|
41
|
-
t.string :
|
|
41
|
+
t.string :label
|
|
42
42
|
t.string :category
|
|
43
|
-
t.decimal :size_mb
|
|
44
43
|
|
|
45
|
-
t.string :
|
|
46
|
-
t.
|
|
47
|
-
t.string :attachment_public
|
|
48
|
-
|
|
49
|
-
t.boolean :public
|
|
50
|
-
t.string :public_url
|
|
51
|
-
t.datetime :public_url_expiration_at
|
|
44
|
+
t.string :attachable_type, null: false
|
|
45
|
+
t.bigint :attachable_id, null: false
|
|
52
46
|
|
|
53
47
|
t.datetime :deleted_at, index: true
|
|
54
48
|
t.timestamps
|
|
55
49
|
end
|
|
56
50
|
|
|
57
|
-
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
58
|
-
add_reference(table_name,
|
|
51
|
+
add_reference(table_name, :user, null: false, foreign_key: { to_table: :lesli_users })
|
|
52
|
+
add_reference(table_name, :account, null: false, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
53
|
+
add_index(table_name, [:account_id, :attachable_type, :attachable_id], name: "#{table_name}_attachable_type_id".to_sym)
|
|
59
54
|
end
|
|
60
55
|
end
|
|
61
56
|
end
|
|
@@ -35,21 +35,21 @@ module MigrationHelpers
|
|
|
35
35
|
module DiscussionStructure
|
|
36
36
|
def create_table_lesli_item_discussions_10(engine)
|
|
37
37
|
|
|
38
|
-
table_name,
|
|
38
|
+
table_name, = table_name_for_items(engine, :discussions)
|
|
39
39
|
|
|
40
40
|
create_table table_name do |t|
|
|
41
|
-
t.text :message
|
|
41
|
+
t.text :message, null: false
|
|
42
42
|
|
|
43
43
|
# Polymorphic target
|
|
44
44
|
t.string :discussable_type, null: false
|
|
45
45
|
t.bigint :discussable_id, null: false
|
|
46
46
|
|
|
47
47
|
t.timestamps
|
|
48
|
-
t.datetime :deleted_at, index: true
|
|
49
48
|
end
|
|
50
49
|
|
|
51
|
-
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
52
|
-
add_reference(table_name, :account, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
50
|
+
add_reference(table_name, :user, null: false, foreign_key: { to_table: :lesli_users })
|
|
51
|
+
add_reference(table_name, :account, null: false, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
52
|
+
add_index(table_name, [:account_id, :discussable_type, :discussable_id], name: "#{table_name}_discussable_type_id".to_sym)
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
end
|
|
@@ -46,11 +46,10 @@ module MigrationHelpers
|
|
|
46
46
|
t.bigint :taskable_id, null: false
|
|
47
47
|
|
|
48
48
|
t.timestamps
|
|
49
|
-
t.datetime :deleted_at, index: true
|
|
50
49
|
end
|
|
51
50
|
|
|
52
|
-
add_reference(table_name, :user, foreign_key: { to_table: :lesli_users })
|
|
53
|
-
add_reference(table_name, :account, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
51
|
+
add_reference(table_name, :user, null: false, foreign_key: { to_table: :lesli_users })
|
|
52
|
+
add_reference(table_name, :account, null: false, foreign_key: { to_table: "#{engine}_accounts".to_sym })
|
|
54
53
|
add_index(table_name, [:account_id, :taskable_type, :taskable_id], name: "#{table_name}_taskable_type_id".to_sym)
|
|
55
54
|
end
|
|
56
55
|
end
|