trek 0.1.23 → 0.1.24

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +4 -4
  3. data/app/components/trek/form/actions_component/actions_component.css +2 -2
  4. data/app/controllers/concerns/trek/authentication.rb +1 -1
  5. data/app/controllers/concerns/trek/localization.rb +1 -1
  6. data/app/helpers/trek/theme_helper.rb +2 -2
  7. data/app/models/concerns/trek/users/invitable.rb +2 -3
  8. data/config/locales/trek.en.yml +9 -6
  9. data/config/locales/trek.fr.yml +8 -5
  10. data/docs/.vitepress/config.mjs +5 -0
  11. data/lib/generators/trek/install/admin/user_password_resets_generator.rb +0 -4
  12. data/lib/generators/trek/install/admin/user_sessions_generator.rb +0 -7
  13. data/lib/generators/trek/install/admin/users_generator.rb +5 -1
  14. data/lib/generators/trek/install/authentication_generator.rb +62 -1
  15. data/lib/generators/trek/install/locales_generator.rb +10 -7
  16. data/lib/generators/trek/install/mailer_generator.rb +14 -9
  17. data/lib/generators/trek/install/user_generator.rb +27 -1
  18. data/lib/generators/trek/install_generator.rb +4 -4
  19. data/lib/generators/trek/templates/controllers/admin/base_controller.rb +1 -0
  20. data/lib/generators/trek/templates/controllers/admin/user_password_resets_controller.rb +23 -27
  21. data/lib/generators/trek/templates/controllers/admin/user_sessions_controller.rb +13 -20
  22. data/lib/generators/trek/templates/controllers/admin/users_controller.rb +6 -0
  23. data/lib/generators/trek/templates/controllers/concerns/trek/authentication.rb +62 -0
  24. data/lib/generators/trek/templates/layouts/admin.html.slim +1 -1
  25. data/lib/generators/trek/templates/mailers/admin/passwords_mailer.rb +13 -0
  26. data/lib/generators/trek/templates/mailers/admin_mailer.rb +10 -0
  27. data/lib/generators/trek/templates/migrations/create_users.rb.erb +11 -0
  28. data/lib/generators/trek/templates/migrations/user_sessions.rb.erb +11 -0
  29. data/lib/generators/trek/templates/migrations/users.rb.erb +2 -0
  30. data/lib/generators/trek/templates/models/current.rb +3 -0
  31. data/lib/generators/trek/templates/models/user.rb +2 -0
  32. data/lib/generators/trek/templates/models/user_session.rb +3 -0
  33. data/lib/generators/trek/templates/views/admin/pages/_form.html.slim +0 -14
  34. data/lib/generators/trek/templates/views/admin/passwords_mailer/reset.en.html.slim +10 -0
  35. data/lib/generators/trek/templates/views/{user_mailer/reset_password_email.en.text.erb → admin/passwords_mailer/reset.en.text.erb} +3 -1
  36. data/lib/generators/trek/templates/views/admin/passwords_mailer/reset.fr.html.slim +10 -0
  37. data/lib/generators/trek/templates/views/{user_mailer/reset_password_email.fr.text.erb → admin/passwords_mailer/reset.fr.text.erb} +4 -2
  38. data/lib/generators/trek/templates/views/admin/user_password_resets/edit.html.slim +7 -7
  39. data/lib/generators/trek/templates/views/admin/user_password_resets/new.html.slim +5 -2
  40. data/lib/generators/trek/templates/views/admin/user_sessions/new.html.slim +12 -3
  41. data/lib/generators/trek/templates/views/admin/users/show.html.slim +1 -1
  42. data/lib/generators/trek/templates/views/admin_mailer/invite.en.html.slim +8 -0
  43. data/lib/generators/trek/templates/views/{user_mailer/invite_email.en.text.erb → admin_mailer/invite.en.text.erb} +1 -1
  44. data/lib/generators/trek/templates/views/admin_mailer/invite.fr.html.slim +8 -0
  45. data/lib/generators/trek/templates/views/{user_mailer/invite_email.fr.text.erb → admin_mailer/invite.fr.text.erb} +1 -1
  46. data/lib/trek/version.rb +1 -1
  47. data/package.json +3 -2
  48. data/yarn.lock +1807 -2486
  49. metadata +17 -12
  50. data/app/models/trek/user_password_reset.rb +0 -12
  51. data/lib/generators/trek/templates/mailers/user_mailer.rb +0 -21
  52. data/lib/generators/trek/templates/views/user_mailer/invite_email.en.html.slim +0 -29
  53. data/lib/generators/trek/templates/views/user_mailer/invite_email.fr.html.slim +0 -29
  54. data/lib/generators/trek/templates/views/user_mailer/reset_password_email.en.html.slim +0 -7
  55. data/lib/generators/trek/templates/views/user_mailer/reset_password_email.fr.html.slim +0 -7
@@ -0,0 +1,62 @@
1
+ module Trek::Authentication
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :require_authentication
6
+ after_action :track_last_activity
7
+ helper_method :authenticated?
8
+
9
+ authorize :user, through: -> { Current.user }
10
+ end
11
+
12
+ class_methods do
13
+ def allow_unauthenticated_access(**options)
14
+ skip_before_action :require_authentication, **options
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def authenticated?
21
+ resume_session
22
+ end
23
+
24
+ def require_authentication
25
+ resume_session || request_authentication
26
+ end
27
+
28
+ def resume_session
29
+ Current.session ||= find_session_by_cookie
30
+ end
31
+
32
+ def find_session_by_cookie
33
+ UserSession.find_by(id: cookies.signed[:session_id]) if cookies.signed[:session_id]
34
+ end
35
+
36
+ def request_authentication
37
+ session[:return_to_after_authenticating] = request.url
38
+ redirect_to new_admin_user_session_path, notice: t("notices.authentication_needed")
39
+ end
40
+
41
+ def after_authentication_url
42
+ session.delete(:return_to_after_authenticating) || admin_root_url
43
+ end
44
+
45
+ def start_new_session_for(user)
46
+ user.user_sessions.create!(user_agent: request.user_agent).tap do |session|
47
+ Current.session = session
48
+ cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
49
+ end
50
+ end
51
+
52
+ def terminate_session
53
+ Current.session.destroy
54
+ cookies.delete(:session_id)
55
+ end
56
+
57
+ def track_last_activity
58
+ # rubocop:disable Rails/SkipsModelValidations
59
+ Current.user&.update_columns(last_activity_at: Time.current)
60
+ # rubocop:enable Rails/SkipsModelValidations
61
+ end
62
+ end
@@ -26,7 +26,7 @@ html(lang=I18n.locale class=class_for_theme)
26
26
  ruby:
27
27
  c.with_header(
28
28
  current_object: @object,
29
- current_user:,
29
+ current_user: Current.user,
30
30
  )
31
31
  c.with_menu("") do |m|
32
32
  m.with_section(title: t("admin.dashboard")) do |s|
@@ -0,0 +1,13 @@
1
+ class Admin::PasswordsMailer < ApplicationMailer
2
+ include ActionView::Helpers::DateHelper
3
+
4
+ def reset(user)
5
+ @user = user
6
+ @url = edit_admin_user_password_reset_url(@user.generate_token_for(:password_reset))
7
+ @expiration_delay = distance_of_time_in_words(0, 15.minutes)
8
+
9
+ I18n.with_locale(@user.locale || I18n.default_locale) do
10
+ mail to: @user.email
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ class AdminMailer < ApplicationMailer
2
+ def invite(user)
3
+ @user = user
4
+ @url = edit_admin_user_password_reset_url(@user.generate_token_for(:password_reset))
5
+
6
+ I18n.with_locale(@user.locale || I18n.default_locale) do
7
+ mail to: @user.email
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class TrekCreateUsers < <%= migration_class_name %>
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :email, null: false
5
+
6
+ t.timestamps
7
+ end
8
+
9
+ add_index :users, :email, unique: true
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class TrekUserSessions < <%= migration_class_name %>
2
+ def change
3
+ create_table :user_sessions do |t|
4
+ t.belongs_to :user, null: false, foreign_key: true
5
+ t.string :user_agent
6
+ t.string :ip_address
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -4,5 +4,7 @@ class TrekUsers < <%= migration_class_name %>
4
4
  add_column :<%= tableized_model_class %>, :theme, :integer, default: 0, null: false
5
5
  add_column :<%= tableized_model_class %>, :locale, :string
6
6
  add_column :<%= tableized_model_class %>, :role, :integer, default: 1, null: false
7
+ add_column :<%= tableized_model_class %>, :password_digest, :string, null: false
8
+ add_column :<%= tableized_model_class %>, :last_activity_at, :datetime
7
9
  end
8
10
  end
@@ -1,3 +1,6 @@
1
1
  class Current < ActiveSupport::CurrentAttributes
2
+ attribute :session
2
3
  attribute :icons
4
+
5
+ delegate :user, to: :session, allow_nil: true
3
6
  end
@@ -0,0 +1,2 @@
1
+ class User < ApplicationRecord
2
+ end
@@ -0,0 +1,3 @@
1
+ class UserSession < ApplicationRecord
2
+ belongs_to :user
3
+ end
@@ -54,20 +54,6 @@
54
54
  = ff.group ff.object.title
55
55
  = ff.content_editor :content, blocks: false, floating: false
56
56
 
57
- - if current_user.admin? && !@object.root? && !@object.leaf?
58
- - children_list_id = dom_id(@object, :children_thumbnails_list)
59
- - c.with_item(id: :thumbnails, label: t("admin.thumbnails"))
60
- = f.group :bottom_content
61
- = f.switch_box :children_thumbnails,
62
- conditional_element: "##{children_list_id}"
63
-
64
- div(id=children_list_id hidden=!@object.children_thumbnails?)
65
- - @object.children.each do |child|
66
- = render Trek::List::ItemComponent.new( \
67
- item: child,
68
- link: false,
69
- ).with_content(" ")
70
-
71
57
  - if policy_permitted_attribute?(:description) \
72
58
  || policy_permitted_attribute?(:slug)
73
59
  - c.with_item(id: :seo, label: t("admin.seo"))
@@ -0,0 +1,10 @@
1
+ p Hello #{@user},
2
+ p You have requested to reset your password
3
+ on #{t("application_name")}.
4
+ p = link_to "Choose a new password",
5
+ @url,
6
+ target: "_blank",
7
+ rel: "noopener"
8
+ p This link will expire in #{@expiration_delay}.
9
+ p Have a great day!
10
+ p The #{t("application_name")} team
@@ -1,9 +1,11 @@
1
1
  Hello <%%= @user %>,
2
2
 
3
- You have requested to reset your password on <%%= admin_full_brand %>.
3
+ You have requested to reset your password on <%%= t("application_name") %>.
4
4
 
5
5
  To choose a new password, just follow this link:
6
6
  <%%= @url %>
7
7
 
8
+ This link will expire in <%%= @expiration_delay %>.
9
+
8
10
  Have a great day!
9
11
  The <%%= t("application_name") %> team
@@ -0,0 +1,10 @@
1
+ p Bonjour #{@user},
2
+ p Vous avez demandé à réinitialiser votre mot de passe
3
+ sur #{t("application_name")}.
4
+ p = link_to "Choisir votre nouveau mot de passe",
5
+ @url,
6
+ target: "_blank",
7
+ rel: "noopener"
8
+ p Ce lien expire dans #{@expiration_delay}.
9
+ p Bonne journée !
10
+ p L'équipe #{t("application_name")}
@@ -1,9 +1,11 @@
1
1
  Bonjour <%%= @user %>,
2
2
 
3
- Vous avez demandé à réinitialiser votre mot de passe sur <%%= admin_full_brand %>.
3
+ Vous avez demandé à réinitialiser votre mot de passe sur <%%= t("application_name") %>.
4
4
 
5
- Pour choisir votre mot de passe, suivez ce lien :
5
+ Pour choisir votre nouveau mot de passe, suivez ce lien :
6
6
  <%%= @url %>
7
7
 
8
+ Ce lien expire dans <%%= @expiration_delay %>.
9
+
8
10
  Bonne journée !
9
11
  L'équipe <%%= t("application_name") %>
@@ -1,11 +1,11 @@
1
1
  = render Trek::GateComponent.new
2
- = form_for [:admin, @user],
3
- url: [:admin, :user_password_reset, { id: @token }] do |f|
4
- = f.group :email
5
- = f.email_field :email
6
-
7
- = f.group :new_password
8
- = f.password_field :new_password
2
+ = form_with url: admin_user_password_reset_path(@token), method: :put do |f|
3
+ = f.group :password
4
+ = f.password_field :password,
5
+ required: true,
6
+ autocomplete: "new-password",
7
+ maxlength: 72,
8
+ minlength: 8
9
9
 
10
10
  = render Trek::Form::ActionsComponent.new do |c|
11
11
  ruby:
@@ -1,7 +1,10 @@
1
1
  = render Trek::GateComponent.new
2
- = form_for [:admin, @user_password_reset] do |f|
2
+ = form_with url: admin_user_password_resets_path do |f|
3
3
  = f.group :email
4
- = f.email_field :email
4
+ = f.email_field :email,
5
+ required: true,
6
+ autofocus: true,
7
+ autocomplete: "username"
5
8
 
6
9
  = render Trek::Form::ActionsComponent.new do |c|
7
10
  ruby:
@@ -1,10 +1,19 @@
1
1
  = render Trek::GateComponent.new
2
- = form_for [:admin, @user_session] do |f|
2
+ = form_with url: admin_user_session_path do |f|
3
3
  = f.group :email
4
- = f.email_field :email
4
+ = f.email_field :email,
5
+ required: true,
6
+ autofocus: @email.nil?,
7
+ autocomplete: "username",
8
+ value: @email
5
9
 
6
10
  = f.group :password
7
- = f.password_field :password
11
+ = f.password_field :password,
12
+ required: true,
13
+ autofocus: @email.present?,
14
+ autocomplete: "current-password",
15
+ maxlength: 72,
16
+ minlength: 8
8
17
 
9
18
  = render Trek::Form::ActionsComponent.new do |c|
10
19
  ruby:
@@ -8,7 +8,7 @@
8
8
  text: t("admin.actions.edit"),
9
9
  )
10
10
 
11
- if @object == current_user
11
+ if @object == Current.user
12
12
  c.with_button(
13
13
  href: %i[admin logout],
14
14
  text: t("admin.actions.logout"),
@@ -0,0 +1,8 @@
1
+ p Hello #{@user},
2
+ p You have been invited to #{t("application_name")}.
3
+ p = link_to "Choose your password",
4
+ @url,
5
+ target: "_blank",
6
+ rel: "noopener"
7
+ p Have a great day!
8
+ p The #{t("application_name")} team
@@ -1,6 +1,6 @@
1
1
  Hello <%%= @user %>,
2
2
 
3
- You have been invited to <%%= admin_full_brand %>.
3
+ You have been invited to <%%= t("application_name") %>.
4
4
 
5
5
  To choose your password, just follow this link:
6
6
  <%%= @url %>
@@ -0,0 +1,8 @@
1
+ p Bonjour #{@user},
2
+ p Vous avez été invité·e sur #{t("application_name")}.
3
+ p = link_to "Choisir votre mot de passe",
4
+ @url,
5
+ target: "_blank",
6
+ rel: "noopener"
7
+ p Bonne journée !
8
+ p L'équipe #{t("application_name")}
@@ -1,6 +1,6 @@
1
1
  Bonjour <%%= @user %>,
2
2
 
3
- Vous avez été invité sur <%%= admin_full_brand %>.
3
+ Vous avez été invité·e sur <%%= t("application_name") %>.
4
4
 
5
5
  Pour choisir votre mot de passe, suivez ce lien :
6
6
  <%%= @url %>
data/lib/trek/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Trek
4
- VERSION = "0.1.23"
4
+ VERSION = "0.1.24"
5
5
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etaminstudio/trek",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "A modern CMS for Ruby on Rails",
5
5
  "main": "app/javascript/trek.js",
6
6
  "repository": {
@@ -48,7 +48,8 @@
48
48
  "stylelint": "^15.11.0",
49
49
  "stylelint-config-standard": "^31.0.0",
50
50
  "stylelint-order": "^6.0.4",
51
- "vitepress": "^1.6.4"
51
+ "vitepress": "^1.6.4",
52
+ "vitepress-plugin-llms": "^1.13.1"
52
53
  },
53
54
  "packageManager": "yarn@3.8.0",
54
55
  "scripts": {