lesli 5.1.12 → 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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -0
  3. data/app/assets/stylesheets/lesli/application.css +43 -3
  4. data/app/controllers/lesli/application_devise_controller.rb +9 -5
  5. data/app/controllers/lesli/application_lesli_controller.rb +4 -0
  6. data/app/controllers/lesli/items/attachments_controller.rb +200 -0
  7. data/app/controllers/lesli/items/discussions_controller.rb +94 -67
  8. data/app/controllers/lesli/items/tasks_controller.rb +132 -62
  9. data/app/helpers/lesli/turbo_helper.rb +0 -18
  10. data/app/interfaces/lesli/responder_interface.rb +58 -38
  11. data/app/mailers/lesli/application_lesli_mailer.rb +34 -8
  12. data/app/models/concerns/lesli/account_initializer.rb +11 -3
  13. data/app/models/concerns/lesli/account_logs.rb +5 -16
  14. data/app/models/concerns/lesli/items/activities.rb +29 -33
  15. data/app/models/concerns/lesli/items/attachments.rb +88 -0
  16. data/app/models/concerns/lesli/items/discussions.rb +25 -11
  17. data/app/models/concerns/lesli/items/ownership.rb +27 -0
  18. data/app/models/concerns/lesli/items/tasks.rb +26 -6
  19. data/app/models/concerns/lesli/user_extensions.rb +5 -9
  20. data/app/models/lesli/account.rb +10 -14
  21. data/app/models/lesli/items/activity.rb +25 -2
  22. data/app/models/lesli/items/attachment.rb +117 -0
  23. data/app/models/lesli/items/discussion.rb +6 -2
  24. data/app/models/lesli/items/task.rb +3 -1
  25. data/app/models/lesli/user.rb +12 -21
  26. data/app/views/lesli/abouts/welcome.html.erb +2 -5
  27. data/app/views/lesli/errors/not_found.html.erb +7 -21
  28. data/app/views/lesli/errors/unauthorized.html.erb +11 -27
  29. data/app/views/lesli/layouts/application-devise.html.erb +10 -9
  30. data/app/views/lesli/layouts/application-lesli.html.erb +1 -1
  31. data/app/views/lesli/partials/_application-lesli-assets.html.erb +3 -3
  32. data/app/views/lesli/partials/_application-lesli-header.html.erb +5 -9
  33. data/config/initializers/lesli.rb +4 -1
  34. data/config/locales/translations.en.yml +34 -0
  35. data/config/locales/translations.es.yml +34 -0
  36. data/db/seed/accounts.rb +5 -5
  37. data/db/seed/users.rb +8 -16
  38. data/db/seed/xyz.rb +38 -17
  39. data/lib/lesli/engine.rb +0 -4
  40. data/lib/lesli/router.rb +5 -2
  41. data/lib/lesli/version.rb +2 -2
  42. data/lib/migrate/items/activity_structure.rb +8 -8
  43. data/lib/migrate/items/attachment_structure.rb +9 -14
  44. data/lib/migrate/items/discussion_structure.rb +5 -5
  45. data/lib/migrate/items/task_structure.rb +2 -3
  46. data/lib/migrate/shared/account_structure.rb +1 -1
  47. data/lib/tasks/lesli_tasks.rake +2 -3
  48. data/readme.md +3 -3
  49. data/test/fixtures/lesli_accounts.yml +18 -0
  50. data/test/fixtures/lesli_users.yml +23 -0
  51. metadata +17 -25
  52. data/app/assets/stylesheets/lesli/application.tailwind.css +0 -33
  53. data/config/brakeman.yml +0 -44
  54. data/config/initializers/devise.rb +0 -27
@@ -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="hero is-medium error-403">
18
- <div class="hero-body has-text-centered">
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="icon">
22
- <span class="material-symbols">
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">403 <%= I18n.t("lesli.shared.message_error_unauthorized") %></h2>
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="box mt-6">
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) 2025, Lesli Technologies, S. A.
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('/')[1] || controller_path %>
33
+ <% public_app_controller = controller_path.split("/")[1] || controller_path %>
34
34
 
35
35
  <!DOCTYPE html>
36
- <html lang="en">
36
+ <html lang="<%= I18n.locale %>">
37
37
  <head>
38
38
  <%= render(partial: "lesli/partials/application-lesli-head") %>
39
- <%= stylesheet_link_tag(lesli_asset_path(:lesli_assets, 'public.tailwind'), media: "all") %>
40
- <%= stylesheet_link_tag(lesli_asset_path(:lesli_shield, public_app_controller.concat(".tailwind")), media: "all") %>
41
- <%# Disable back button in browser after Logout using JavaScript %>
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('popstate', function () {
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="flex">
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.tailwind'), media: "all") %>
54
- <%= stylesheet_link_tag(lesli_asset_path(:lesli_assets, 'view.tailwind'), media: "all") %>
55
- <%= stylesheet_link_tag(lesli_asset_path(nil,'application.tailwind'), media: "all") %>
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?(LesliAdmin) %>
111
- <%= link_to lesli_admin.profile_path,
112
- class: action_class.call(lesli_admin.profile_path),
113
- aria: {
114
- label: profile_label,
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 },
@@ -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(3);
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.first
35
+ account = Lesli::Account.find_by!(email: Lesli.config.company.fetch(:email))
37
36
 
38
37
 
39
- # try to extract the domain name from the main email address
40
- email_domain = account[:email].scan(/.*@(\S+)/)&.first&.first
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[:email]
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
- userowner = create_account_user(emailowner, "owner", "Owner", account[:company_name], passowner)
68
- useradmin = create_account_user(emailadmin, "admin", "Admin", account[:company_name], passadmin)
69
- userguest = create_account_user(emailguest, "guest", "Guest", account[:company_name], passguest)
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, rolename, firstname, lastname, password
34
-
35
- account = Lesli::Account.find_by(email: Lesli.config.company.dig(:email))
36
-
37
- # create development users if email is not registered yet
38
- Lesli::User.find_or_create_by(email: email) do |user|
39
- user.account = account
40
- user.password = password
41
- user.password_confirmation = password
42
-
43
- # confirm user through device
44
- user.confirm unless user.confirmed?
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
- if(defined?(LesliShield))
51
- user.user_roles.create!({ role: Lesli::Role.find_by(:name => rolename) })
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
- user
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[index update create]
77
+ router.resources :tasks, only: %i[update create]
78
78
 
79
79
  # Load item discussions
80
- router.resources :discussions, only: %i[index update create]
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
@@ -1,4 +1,4 @@
1
1
  module Lesli
2
- VERSION = "5.1.12"
3
- BUILD = "1791607001"
2
+ VERSION = "5.1.13"
3
+ BUILD = "1792716699"
4
4
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lesli
4
4
 
5
- Copyright (c) 2025, Lesli Technologies, S. A.
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, foreign_key = table_name_for_items(engine, :activities)
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: :activity
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, [:account_id, :subject_type, :subject_id], name: "#{table_name}_activities_type_id")
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) 2025, Lesli Technologies, S. A.
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(resources)
36
+ def create_table_lesli_item_attachments_10(engine)
37
37
 
38
- table_name, foreign_key = table_name_for_items(resources, :attachments)
38
+ table_name, = table_name_for_items(engine, :attachments)
39
39
 
40
40
  create_table table_name do |t|
41
- t.string :name
41
+ t.string :label
42
42
  t.string :category
43
- t.decimal :size_mb
44
43
 
45
- t.string :attachment
46
- t.string :attachment_remote # like S3
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, foreign_key, foreign_key: { to_table: resources })
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, foreign_key = table_name_for_items(engine, :discussions)
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
@@ -14,7 +14,7 @@ module MigrationHelpers
14
14
  t.timestamps
15
15
  end
16
16
 
17
- add_reference(table_name, :account, null: false, foreign_key: { to_table: :lesli_accounts }, index: true)
17
+ add_reference(table_name, :account, null: false, index: { unique: true }, foreign_key: { to_table: :lesli_accounts })
18
18
  end
19
19
  end
20
20
  end
@@ -66,9 +66,8 @@ namespace :lesli do
66
66
  Termline.br(2)
67
67
 
68
68
  # core information
69
- Termline.info(instance, tag:'Instance:', time:false)
70
- Termline.info(Rails.env, tag:'Environment:', time:false)
71
- Termline.br()
69
+ Termline.details(Instance: instance, Environment: Rails.env, icon: :info)
70
+ Termline.br(2)
72
71
 
73
72
  # print list of engines
74
73
  Termline.table(engines)
data/readme.md CHANGED
@@ -11,10 +11,10 @@
11
11
  <br />
12
12
 
13
13
  <div align="center">
14
- <a target="_blank" href="https://github.com/LesliTech/Lesli/actions/workflows/lesli-ci-tests.yaml">
14
+ <a target="_blank" href="https://github.com/LesliTech/Lesli/actions/workflows/lesli-ci-engine.yaml">
15
15
  <img
16
16
  alt="Lesli test status"
17
- src="https://img.shields.io/github/actions/workflow/status/LesliTech/Lesli/lesli-ci-tests.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
17
+ src="https://img.shields.io/github/actions/workflow/status/LesliTech/Lesli/lesli-ci-engine.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
18
18
  </a>
19
19
  <a target="_blank" href="https://rubygems.org/gems/lesli">
20
20
  <img alt="Gem Version" src="https://img.shields.io/gem/v/lesli?style=for-the-badge&logo=ruby">
@@ -75,7 +75,7 @@ Lesli core and its official engines provide:
75
75
 
76
76
  ### Requirements
77
77
 
78
- - Ruby 3.2 or newer
78
+ - Ruby 3.3 or newer (the release workflow uses Ruby 3.3.5)
79
79
  - Rails 8.1
80
80
  - SQLite, included in the default Rails application
81
81
 
@@ -0,0 +1,18 @@
1
+
2
+ # test/fixtures/lesli_accounts.yml
3
+
4
+ one:
5
+ status: "active"
6
+ name: "Lesli Demo Account"
7
+ email: "account-one@example.com"
8
+ region: "america"
9
+ created_at: <%= Time.current %>
10
+ updated_at: <%= Time.current %>
11
+
12
+ two:
13
+ status: "active"
14
+ name: "Second Account"
15
+ email: "account-two@example.com"
16
+ region: "america"
17
+ created_at: <%= Time.current %>
18
+ updated_at: <%= Time.current %>
@@ -0,0 +1,23 @@
1
+ # test/fixtures/lesli_users.yml
2
+
3
+ one:
4
+ uid: "USR-0001"
5
+ active: true
6
+ email: "one@example.com"
7
+ encrypted_password: "provided-by-authentication-engine"
8
+ first_name: "Luis"
9
+ last_name: "Donis"
10
+ sign_in_count: 0
11
+ account: one
12
+ created_at: <%= Time.current %>
13
+ updated_at: <%= Time.current %>
14
+
15
+ two:
16
+ uid: "USR-0002"
17
+ active: true
18
+ email: "two@example.com"
19
+ encrypted_password: "provided-by-authentication-engine"
20
+ sign_in_count: 0
21
+ account: two
22
+ created_at: <%= Time.current %>
23
+ updated_at: <%= Time.current %>