pages_core 3.12.7 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/builds/pages_core/admin-dist.js +1 -1
  4. data/app/assets/builds/pages_core/admin-dist.js.map +4 -4
  5. data/app/assets/builds/pages_core/admin.css +27 -4
  6. data/app/assets/stylesheets/pages_core/admin/components/login.css +0 -6
  7. data/app/assets/stylesheets/pages_core/admin/components/totp.css +26 -0
  8. data/app/controllers/admin/account_recoveries_controller.rb +87 -0
  9. data/app/controllers/admin/invites_controller.rb +3 -2
  10. data/app/controllers/admin/otp_secrets_controller.rb +45 -0
  11. data/app/controllers/admin/pages_controller.rb +1 -1
  12. data/app/controllers/admin/recovery_codes_controller.rb +32 -0
  13. data/app/controllers/admin/sessions_controller.rb +65 -0
  14. data/app/controllers/admin/users_controller.rb +3 -9
  15. data/app/controllers/concerns/pages_core/authentication.rb +12 -10
  16. data/app/controllers/concerns/pages_core/error_reporting.rb +9 -19
  17. data/app/controllers/concerns/pages_core/static_cache_controller.rb +13 -2
  18. data/app/controllers/pages_core/admin_controller.rb +1 -1
  19. data/app/controllers/pages_core/attachments_controller.rb +1 -1
  20. data/app/controllers/pages_core/frontend/pages_controller.rb +1 -1
  21. data/app/controllers/pages_core/frontend_controller.rb +1 -10
  22. data/app/formatters/pages_core/image_embedder.rb +3 -3
  23. data/app/helpers/admin/pages_helper.rb +2 -2
  24. data/app/helpers/pages_core/admin/admin_helper.rb +12 -1
  25. data/app/helpers/pages_core/admin/content_tabs_helper.rb +3 -3
  26. data/app/helpers/pages_core/admin/form_builder.rb +1 -1
  27. data/app/helpers/pages_core/admin/image_uploads_helper.rb +6 -6
  28. data/app/helpers/pages_core/admin/labelled_field_helper.rb +1 -1
  29. data/app/helpers/pages_core/admin/locales_helper.rb +1 -1
  30. data/app/helpers/pages_core/application_helper.rb +3 -3
  31. data/app/helpers/pages_core/head_tags_helper.rb +8 -9
  32. data/app/helpers/pages_core/images_helper.rb +7 -7
  33. data/app/helpers/pages_core/open_graph_tags_helper.rb +2 -2
  34. data/app/helpers/pages_core/page_path_helper.rb +2 -2
  35. data/app/javascript/index.ts +0 -2
  36. data/app/jobs/pages_core/autopublish_job.rb +2 -0
  37. data/app/mailers/admin_mailer.rb +2 -2
  38. data/app/models/concerns/pages_core/has_otp.rb +27 -0
  39. data/app/models/concerns/pages_core/has_roles.rb +2 -2
  40. data/app/models/concerns/pages_core/page_model/dated_page.rb +1 -1
  41. data/app/models/concerns/pages_core/page_model/searchable.rb +1 -1
  42. data/app/models/concerns/pages_core/page_model/templateable.rb +22 -0
  43. data/app/models/concerns/pages_core/searchable_document.rb +3 -3
  44. data/app/models/otp_secret.rb +101 -0
  45. data/app/models/page.rb +1 -1
  46. data/app/models/page_builder.rb +9 -9
  47. data/app/models/page_exporter.rb +1 -1
  48. data/app/models/page_image.rb +1 -1
  49. data/app/models/page_path.rb +3 -3
  50. data/app/models/search_document.rb +3 -3
  51. data/app/models/tag.rb +1 -1
  52. data/app/models/user.rb +15 -37
  53. data/app/policies/user_policy.rb +4 -0
  54. data/app/services/pages_core/create_user_service.rb +2 -2
  55. data/app/services/pages_core/destroy_invite_service.rb +2 -2
  56. data/app/services/pages_core/invite_service.rb +2 -2
  57. data/app/views/admin/account_recoveries/new.html.erb +22 -0
  58. data/app/views/admin/account_recoveries/show.html.erb +37 -0
  59. data/app/views/admin/invites/show.html.erb +1 -1
  60. data/app/views/admin/otp_secrets/create.html.erb +7 -0
  61. data/app/views/admin/otp_secrets/new.html.erb +60 -0
  62. data/app/views/admin/pages/_edit_content.html.erb +1 -1
  63. data/app/views/admin/pages/_form.html.erb +12 -0
  64. data/app/views/admin/recovery_codes/_codes.html.erb +14 -0
  65. data/app/views/admin/recovery_codes/create.html.erb +7 -0
  66. data/app/views/admin/recovery_codes/new.html.erb +11 -0
  67. data/app/views/admin/sessions/_otp_form.html.erb +13 -0
  68. data/app/views/admin/sessions/new.html.erb +33 -0
  69. data/app/views/admin/sessions/verify_otp.html.erb +19 -0
  70. data/app/views/admin/users/edit.html.erb +31 -1
  71. data/app/views/admin/users/new.html.erb +1 -1
  72. data/app/views/admin_mailer/account_recovery.text.erb +10 -0
  73. data/app/views/layouts/admin/_header.html.erb +1 -1
  74. data/app/views/layouts/admin/_toast.html.erb +12 -0
  75. data/app/views/layouts/admin.html.erb +1 -1
  76. data/config/locales/en.yml +11 -3
  77. data/config/routes.rb +11 -6
  78. data/db/migrate/20111219033112_create_pages_tables.rb +0 -14
  79. data/db/migrate/20240126160700_add_2fa_fields.rb +22 -0
  80. data/db/migrate/20240129201300_remove_password_reset_tokens.rb +13 -0
  81. data/lib/pages_core/cache_sweeper.rb +3 -3
  82. data/lib/pages_core/extensions/string_extensions.rb +1 -1
  83. data/lib/pages_core/templates/configuration.rb +1 -1
  84. data/lib/pages_core/templates/template_configuration.rb +1 -1
  85. data/lib/pages_core.rb +7 -2
  86. data/lib/rails/generators/pages_core/install/install_generator.rb +0 -15
  87. data/lib/rails/generators/pages_core/rspec/templates/page_templates_spec.rb +1 -1
  88. metadata +53 -56
  89. data/app/controllers/admin/password_resets_controller.rb +0 -85
  90. data/app/controllers/sessions_controller.rb +0 -27
  91. data/app/javascript/controllers/LoginController.ts +0 -32
  92. data/app/models/password_reset_token.rb +0 -34
  93. data/app/views/admin/password_resets/show.html.erb +0 -21
  94. data/app/views/admin/users/login.html.erb +0 -65
  95. data/app/views/admin_mailer/password_reset.text.erb +0 -11
  96. data/lib/rails/generators/pages_core/install/templates/active_job_initializer.rb +0 -3
  97. data/lib/rails/generators/pages_core/install/templates/delayed_job +0 -7
  98. data/lib/rails/generators/pages_core/install/templates/delayed_job_initializer.rb +0 -18
@@ -11,7 +11,7 @@ module PagesCore
11
11
 
12
12
  class << self
13
13
  def call(attrs, invite: nil)
14
- new(attrs, invite: invite).call
14
+ new(attrs, invite:).call
15
15
  end
16
16
  end
17
17
 
@@ -19,7 +19,7 @@ module PagesCore
19
19
  User.transaction do
20
20
  user = User.create(attributes.merge(invite_attributes))
21
21
  if user.valid?
22
- PagesCore::PubSub.publish(:create_user, user: user, invite: invite)
22
+ PagesCore::PubSub.publish(:create_user, user:, invite:)
23
23
  invite&.destroy
24
24
  end
25
25
  user
@@ -10,14 +10,14 @@ module PagesCore
10
10
 
11
11
  class << self
12
12
  def call(invite:)
13
- new(invite: invite).call
13
+ new(invite:).call
14
14
  end
15
15
  end
16
16
 
17
17
  def call
18
18
  Invite.transaction do
19
19
  invite.destroy
20
- PagesCore::PubSub.publish(:destroy_invite, invite: invite)
20
+ PagesCore::PubSub.publish(:destroy_invite, invite:)
21
21
  invite
22
22
  end
23
23
  end
@@ -15,7 +15,7 @@ module PagesCore
15
15
 
16
16
  class << self
17
17
  def call(attrs, user:, host:, protocol: "http")
18
- new(attrs, user: user, host: host, protocol: protocol).call
18
+ new(attrs, user:, host:, protocol:).call
19
19
  end
20
20
  end
21
21
 
@@ -36,7 +36,7 @@ module PagesCore
36
36
  AdminMailer.invite(
37
37
  invite,
38
38
  admin_invite_with_token_url(invite, invite.token,
39
- host: host, protocol: protocol)
39
+ host:, protocol:)
40
40
  ).deliver_later
41
41
  end
42
42
  end
@@ -0,0 +1,22 @@
1
+ <% content_for :page_title, "Account recovery" %>
2
+ <% content_for :page_description, "Account recovery" %>
3
+
4
+ <%= form_tag admin_account_recovery_path do %>
5
+ <h2>
6
+ Forgot your password or lost your authenticator?
7
+ </h2>
8
+ <p>
9
+ Don't worry, it happens.
10
+ Enter your email address below, and we'll send you a link where you
11
+ can recover your account.
12
+ </p>
13
+ <div class="field">
14
+ <label for="email">Email address</label>
15
+ <%= text_field_tag(:email, "", autocomplete: "email", autofocus: true) %>
16
+ </div>
17
+ <p>
18
+ <button type="submit">
19
+ Send
20
+ </button>
21
+ </p>
22
+ <% end %>
@@ -0,0 +1,37 @@
1
+ <% content_for :page_title, "Account recovery" %>
2
+ <% content_for :page_description, "Please choose a new password to proceed" %>
3
+ <% content_for :body_class, "login" %>
4
+
5
+ <div class="login-form">
6
+ <%= form_for(@user,
7
+ url: admin_account_recovery_path,
8
+ builder: PagesCore::Admin::FormBuilder,
9
+ class: 'form') do |f| %>
10
+ <%= hidden_field_tag :token, @token %>
11
+ <%= f.labelled_password_field(:password,
12
+ autofocus: true,
13
+ autocomplete: "new-password") %>
14
+ <%= f.labelled_password_field(:password_confirmation,
15
+ autocomplete: "new-password") %>
16
+
17
+ <% if @user.otp_enabled? %>
18
+ <div class="field">
19
+ <label for="otp">6 digit code or recovery code</label>
20
+ <%= text_field_tag(:otp, "",
21
+ autocomplete: "one-time-code",
22
+ size: 6) %>
23
+ </div>
24
+ <p>
25
+ Lost your authenticator device? You can use one of your
26
+ emergency recovery codes instead.
27
+ </p>
28
+ <% end %>
29
+
30
+ <p>
31
+ <button type="submit">
32
+ Change password
33
+ </button>
34
+ or <%= link_to "Return to login screen", admin_login_path %>
35
+ </p>
36
+ <% end %>
37
+ </div>
@@ -14,7 +14,7 @@
14
14
  <%= f.labelled_text_field :email, autocomplete: "email" %>
15
15
  <%= f.labelled_password_field(:password,
16
16
  autocomplete: "new-password") %>
17
- <%= f.labelled_password_field(:confirm_password,
17
+ <%= f.labelled_password_field(:password_confirmation,
18
18
  autocomplete: "new-password") %>
19
19
  <p>
20
20
  <button type="submit">
@@ -0,0 +1,7 @@
1
+ <% content_for :page_title, "2FA enabled" %>
2
+ <% content_for :page_description, "Two-factor authentication enabled" %>
3
+
4
+ <div class="content">
5
+ <%= render(partial: "admin/recovery_codes/codes",
6
+ locals: { recovery_codes: @recovery_codes }) %>
7
+ </div>
@@ -0,0 +1,60 @@
1
+ <% content_for :page_title, "Enable 2FA" %>
2
+ <% content_for :page_description, "Enable two-factor authentication" %>
3
+
4
+ <%= form_tag(admin_otp_secret_path, method: :post, class: "totp-enrollment") do |f| %>
5
+ <h2>
6
+ Scan the QR-code
7
+ </h2>
8
+ <p>
9
+ Use an authenticator app or browser extension to scan the QR code below.<br>
10
+ Don't have one? Some options are
11
+ <%= link_to("1Password", "https://1password.com/") %>,
12
+ <%= link_to("LastPass Authenticator", "https://www.lastpass.com/") %>,
13
+ <%= link_to("Microsoft Authenticator",
14
+ "https://www.microsoft.com/en-us/security/mobile-authenticator-app") %>
15
+ or
16
+ <%= link_to("Google Authenticator",
17
+ "https://support.google.com/accounts/answer/1066447") %>.
18
+ </p>
19
+
20
+
21
+ <div class="qr-code">
22
+ <%= qr_code(@otp_secret.provisioning_uri) %>
23
+ </div>
24
+
25
+ <p>
26
+ If you are unable to scan the code, you can enter the following
27
+ info instead:
28
+ </p>
29
+
30
+ <p>
31
+ <b>Account name:</b><br>
32
+ <%= @otp_secret.account_name %>
33
+ </p>
34
+ <p>
35
+ <b>Secret:</b><br>
36
+ <span class="otp-secret">
37
+ <%= @otp_secret.secret %>
38
+ </span>
39
+ </p>
40
+
41
+ <h2>
42
+ Enter the code from the app
43
+ </h2>
44
+
45
+ <div class="field">
46
+ <label for="otp">6 digit code</label>
47
+ <%= text_field_tag(:otp, "",
48
+ autofocus: true,
49
+ autocomplete: "one-time-code",
50
+ size: 6) %>
51
+ </div>
52
+
53
+ <%= hidden_field_tag :signed_message, @otp_secret.signed_message %>
54
+
55
+ <p>
56
+ <button type="submit">
57
+ Verify
58
+ </button>
59
+ </p>
60
+ <% end %>
@@ -1,4 +1,4 @@
1
- <% @page.template_config.enabled_blocks do |block_name, block_options| %>
1
+ <% @page.enabled_blocks do |block_name, block_options| %>
2
2
  <%= page_block_field(f, block_name, block_options) %>
3
3
  <% end %>
4
4
 
@@ -2,6 +2,18 @@
2
2
  <%= render partial: "edit_content", locals: { f: f } %>
3
3
  <% end %>
4
4
 
5
+ <% if @page.unconfigured_blocks.any? %>
6
+ <%= content_tab "Unconfigured content" do %>
7
+ <p>
8
+ This page has additional content fields not enabled by the
9
+ selected template.
10
+ </p>
11
+ <% @page.unconfigured_blocks do |block_name, block_options| %>
12
+ <%= page_block_field(f, block_name, block_options) %>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
16
+
5
17
  <% if @page.template_config.value(:images) || @page.template_config.value(:image) %>
6
18
  <%= content_tab "Images" do %>
7
19
  <%= render partial: "edit_images", locals: { f: f } %>
@@ -0,0 +1,14 @@
1
+ <h2>
2
+ Recovery codes
3
+ </h2>
4
+ <p>
5
+ Please save the recovery codes below in a safe place, ideally
6
+ using a secure password manager.<br>
7
+ Without them, you will lose access to your account if you lose your device.
8
+ </p>
9
+
10
+ <ul class="recovery-codes">
11
+ <% recovery_codes.each do |c| %>
12
+ <li><%= c %></li>
13
+ <% end %>
14
+ </ul>
@@ -0,0 +1,7 @@
1
+ <% content_for :page_title, "New recovery codes" %>
2
+ <% content_for :page_description, "Recovery codes updated" %>
3
+
4
+ <div class="content">
5
+ <%= render(partial: "admin/recovery_codes/codes",
6
+ locals: { recovery_codes: @recovery_codes }) %>
7
+ </div>
@@ -0,0 +1,11 @@
1
+ <% content_for :page_title, "New recovery codes" %>
2
+ <% content_for :page_description, "Generate new recovery codes" %>
3
+
4
+ <%= form_tag(admin_recovery_codes_path, method: :post) do |f| %>
5
+ <%= render(partial: "admin/sessions/otp_form") %>
6
+ <p>
7
+ <button type="submit">
8
+ Verify
9
+ </button>
10
+ </p>
11
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <h2>
2
+ Two-factor authentication
3
+ </h2>
4
+ <p>
5
+ Enter a one-time code from your authenticator app to proceed.
6
+ </p>
7
+ <div class="field">
8
+ <label for="otp">6 digit code</label>
9
+ <%= text_field_tag(:otp, "",
10
+ autofocus: true,
11
+ autocomplete: "one-time-code",
12
+ size: 6) %>
13
+ </div>
@@ -0,0 +1,33 @@
1
+ <% content_for :page_title, "Sign in" %>
2
+ <% content_for(:page_description,
3
+ "Please enter your email address and password to sign in") %>
4
+ <% content_for :body_class, "login" %>
5
+
6
+ <% content_for :sidebar do %>
7
+ <h2>Please note</h2>
8
+ <p>
9
+ Please contact support if you experience problems logging in or using Pages.
10
+ </p>
11
+ <% end %>
12
+
13
+ <div class="login-form">
14
+ <%= form_tag admin_session_path do %>
15
+ <p>
16
+ <label>Email address</label>
17
+ <%= text_field_tag(:email, "", autocomplete: "email") %>
18
+ </p>
19
+ <p>
20
+ <label>Password</label>
21
+ <%= password_field_tag(:password, "", autocomplete: "current-password") %>
22
+ </p>
23
+ <p>
24
+ <button type="submit">Sign in</button>
25
+ </p>
26
+ <ul>
27
+ <li>
28
+ <%= link_to("<b>Help!</b> I forgot my password!".html_safe,
29
+ new_admin_account_recovery_path) %>
30
+ </li>
31
+ </ul>
32
+ <% end %>
33
+ </div>
@@ -0,0 +1,19 @@
1
+ <% content_for :page_title, "Two-factor authentication" %>
2
+ <% content_for :page_description, "Two-factor authentication" %>
3
+
4
+ <%= form_tag(verify_otp_admin_session_path, method: :post) do |f| %>
5
+ <%= hidden_field_tag :signed_user_id, @signed_user_id %>
6
+ <%= render(partial: "admin/sessions/otp_form") %>
7
+
8
+ <p>
9
+ <button type="submit">
10
+ Verify
11
+ </button>
12
+ </p>
13
+
14
+ <p>
15
+ Lost your authenticator device?
16
+ <%= link_to("Recover your account here",
17
+ new_admin_account_recovery_path) %>.
18
+ </p>
19
+ <% end %>
@@ -31,12 +31,42 @@
31
31
  <% if policy(@user).change_password? %>
32
32
  <h2>Password</h2>
33
33
  <%= f.labelled_password_field :password, 'Change password' %>
34
- <%= f.labelled_password_field :confirm_password, 'Confirm password' %>
34
+ <%= f.labelled_password_field :password_confirmation, 'Confirm password' %>
35
35
  <p>
36
36
  Leave the password blank if you do not wish to change the password.
37
37
  </p>
38
38
  <% end %>
39
39
 
40
+ <% if policy(@user).otp? %>
41
+ <h2>Two-factor authentication</h2>
42
+ <% if @user.otp_enabled? %>
43
+ <p>
44
+ Two-factor authentication has been enabled.
45
+ <%= link_to("Disable",
46
+ admin_otp_secret_path,
47
+ class: :delete,
48
+ method: :delete,
49
+ data: { confirm: "Are you sure you want to disable 2FA?" }) %>
50
+ </p>
51
+ <p>
52
+
53
+ You have
54
+ <%= t("pages_core.recovery_codes",
55
+ count: @user.hashed_recovery_codes.length) %>
56
+ remaining.
57
+ <%= link_to("Generate new codes", new_admin_recovery_codes_path) %>
58
+ </p>
59
+ <% else %>
60
+ <p>
61
+ Protect your account with an additional layer of security by
62
+ requiring an authentication app to sign in.
63
+ </p>
64
+ <p>
65
+ <%= link_to("Enable 2FA", new_admin_otp_secret_path) %>
66
+ </p>
67
+ <% end %>
68
+ <% end %>
69
+
40
70
  <%= render partial: "access_control", locals: { user: @user, f: f } %>
41
71
 
42
72
  <p>
@@ -11,7 +11,7 @@
11
11
  <%= f.labelled_text_field(:email, autocomplete: "email") %>
12
12
  <%= f.labelled_password_field(:password,
13
13
  autocomplete: "new-password") %>
14
- <%= f.labelled_password_field(:confirm_password,
14
+ <%= f.labelled_password_field(:password_confirmation,
15
15
  autocomplete: "new-password") %>
16
16
 
17
17
  <p>
@@ -0,0 +1,10 @@
1
+ Hi, <%= @user.name %>!
2
+
3
+ We've received a request to recover your account on <%= PagesCore.config(:site_name) %>.
4
+
5
+ Please click the following link to continue:
6
+ <%= @url %>
7
+
8
+ The link will expire in 24 hours.
9
+
10
+ If you do not want to recover your password, please ignore this email.
@@ -10,7 +10,7 @@
10
10
  <% if logged_in? %>
11
11
  <div class="user">
12
12
  Hello, <%= link_to(current_user.name, admin_user_url(current_user)) %>
13
- <%= link_to("Log out", session_path, method: "delete") %>
13
+ <%= link_to("Log out", admin_session_path, method: "delete") %>
14
14
  </div>
15
15
  <% end %>
16
16
  <nav class="tabs">
@@ -0,0 +1,12 @@
1
+ <%= react_component "Toast", { notice: flash[:notice], error: flash[:error] } %>
2
+ <% if Rails.env.test? && flash.any? %>
3
+ <div class="flash-test-helper">
4
+ <% %i[notice error].each do |type| %>
5
+ <% if flash[type] || true %>
6
+ <div class="<%= type %>">
7
+ <%= flash[type] %>
8
+ </div>
9
+ <% end %>
10
+ <% end %>
11
+ </div>
12
+ <% end %>
@@ -58,6 +58,6 @@
58
58
  <% end %>
59
59
  </div>
60
60
  <%= react_component "Modal", {} %>
61
- <%= react_component "Toast", { notice: flash[:notice], error: flash[:error] } %>
61
+ <%= render(partial: "layouts/admin/toast") %>
62
62
  </body>
63
63
  </html>
@@ -28,13 +28,21 @@ en:
28
28
  The provided email address and password combination was not valid
29
29
  invite_expired: This invite is no longer valid.
30
30
  logged_out: You have been logged out
31
- password_reset:
31
+ otp:
32
+ already_enabled: 2FA has already been enabled
33
+ disabled: 2FA has been disabled
34
+ invalid_code: Invalid 2FA code
35
+ required: 2FA is required for this
36
+ account_recovery:
32
37
  changed: Your password has been changed
33
- expired: Your password reset link has expired
34
- invalid_request: Invalid password reset request
38
+ invalid_request: This link is no longer valid
35
39
  not_found: Couldn't find a user with that email address
36
40
  sent: An email with further instructions has been sent
37
41
  problems_saving: There were problems saving your changes
42
+ recovery_codes:
43
+ zero: "no recovery codes"
44
+ one: "one recovery code"
45
+ other: "%{count} recovery codes"
38
46
  templates:
39
47
  default:
40
48
  blocks:
data/config/routes.rb CHANGED
@@ -33,9 +33,6 @@ Rails.application.routes.draw do
33
33
  get "pages/:locale/*glob" => redirect("/%{locale}/pages/%{glob}"),
34
34
  locale: /\w\w\w/
35
35
 
36
- # Authentication
37
- resource :session, only: %i[create destroy]
38
-
39
36
  # Sitemap
40
37
  resource :sitemap, only: [:show]
41
38
 
@@ -51,9 +48,9 @@ Rails.application.routes.draw do
51
48
  end
52
49
 
53
50
  # Password resets
54
- resources :password_resets, only: %i[create show update]
55
- controller :password_resets do
56
- get "/password_resets/:id/:token" => :show, as: :password_reset_with_token
51
+ resource :account_recovery
52
+ controller :account_recoveries do
53
+ get "/account_recovery/:token" => :show, as: :account_recovery_with_token
57
54
  end
58
55
 
59
56
  # Attachments
@@ -76,6 +73,14 @@ Rails.application.routes.draw do
76
73
  # Categories
77
74
  resources :categories
78
75
 
76
+ # Authentication
77
+ resource :session, only: %i[create destroy] do
78
+ member { post :verify_otp }
79
+ end
80
+ resource :otp_secret, only: %i[new create destroy]
81
+ resource :recovery_codes, only: %i[new create]
82
+ get "login" => "sessions#new", as: "login"
83
+
79
84
  # Pages
80
85
  scope ":locale" do
81
86
  resources :news,
@@ -21,20 +21,6 @@ class CreatePagesTables < ActiveRecord::Migration[5.0]
21
21
  t.index :slug
22
22
  end
23
23
 
24
- create_table :delayed_jobs do |t|
25
- t.integer :priority, default: 0
26
- t.integer :attempts, default: 0
27
- t.text :handler
28
- t.text :last_error
29
- t.datetime :run_at
30
- t.datetime :locked_at
31
- t.datetime :failed_at
32
- t.string :locked_by
33
- t.datetime :created_at, null: false
34
- t.datetime :updated_at, null: false
35
- t.string :queue
36
- end
37
-
38
24
  create_table :images do |t|
39
25
  t.string :filename, null: false
40
26
  t.string :content_type, null: false
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Add2faFields < ActiveRecord::Migration[7.0]
4
+ def change
5
+ change_table :users do |t|
6
+ t.boolean :otp_enabled, null: false, default: false
7
+ t.string :otp_secret
8
+ t.datetime :last_otp_at
9
+ t.jsonb :hashed_recovery_codes, null: false, default: []
10
+ t.string :session_token
11
+ end
12
+
13
+ rename_column :users, :hashed_password, :password_digest
14
+
15
+ reversible do |dir|
16
+ dir.up do
17
+ User.find_each { |u| u.update(session_token: SecureRandom.hex(32)) }
18
+ change_column_null :users, :session_token, false
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RemovePasswordResetTokens < ActiveRecord::Migration[7.0]
4
+ def change
5
+ drop_table :password_reset_tokens do |t|
6
+ t.integer :user_id
7
+ t.string :token
8
+ t.datetime :expires_at
9
+ t.datetime :created_at
10
+ t.datetime :updated_at
11
+ end
12
+ end
13
+ end
@@ -5,15 +5,15 @@ module PagesCore
5
5
  class << self
6
6
  attr_accessor :enabled
7
7
 
8
- def disable(&_block)
8
+ def disable(&)
9
9
  old_value = enabled
10
10
  self.enabled = false
11
11
  yield if block_given?
12
12
  self.enabled = old_value
13
13
  end
14
14
 
15
- def once(&block)
16
- disable(&block)
15
+ def once(&)
16
+ disable(&)
17
17
  PagesCore::StaticCache.handler.sweep!
18
18
  end
19
19
  end
@@ -4,7 +4,7 @@ module PagesCore
4
4
  module Extensions
5
5
  module StringExtensions
6
6
  def to_html_with(append, options = {})
7
- to_html(options.merge(append: append))
7
+ to_html(options.merge(append:))
8
8
  end
9
9
 
10
10
  def to_html(options = {})
@@ -149,7 +149,7 @@ module PagesCore
149
149
  def template_config(setting, value, options)
150
150
  value = true if value == :enabled
151
151
  value = false if value == :disabled
152
- { setting => { value: value, options: options } }
152
+ { setting => { value:, options: } }
153
153
  end
154
154
 
155
155
  def template_path(name)
@@ -106,7 +106,7 @@ module PagesCore
106
106
  end
107
107
 
108
108
  class << self
109
- def configure(options = {}, &_block)
109
+ def configure(options = {}, &)
110
110
  case options[:reset]
111
111
  when :defaults
112
112
  load_default_configuration
data/lib/pages_core.rb CHANGED
@@ -21,7 +21,6 @@ require "acts_as_list"
21
21
  require "alba"
22
22
  require "bcrypt"
23
23
  require "country_select"
24
- require "delayed_job_active_record"
25
24
  require "dis"
26
25
  require "dynamic_image"
27
26
  require "healthcheck"
@@ -33,6 +32,8 @@ require "pg_search"
33
32
  require "progress_bar"
34
33
  require "rails_i18n"
35
34
  require "RedCloth"
35
+ require "rotp"
36
+ require "rqrcode"
36
37
  require "sass-rails"
37
38
  require "typhoeus"
38
39
  require "will_paginate"
@@ -71,7 +72,7 @@ module PagesCore
71
72
  Pathname.new(File.dirname(__FILE__)).join("..").expand_path
72
73
  end
73
74
 
74
- def configure(_options = {}, &_block)
75
+ def configure(_options = {}, &)
75
76
  yield configuration if block_given?
76
77
  end
77
78
 
@@ -84,5 +85,9 @@ module PagesCore
84
85
  end
85
86
  end
86
87
  alias config configuration
88
+
89
+ def reset_configuration!
90
+ @configuration = PagesCore::Configuration::Pages.new
91
+ end
87
92
  end
88
93
  end