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
@@ -8370,10 +8370,6 @@ main .login-form ul li {
8370
8370
  font-size: 1.2em;
8371
8371
  }
8372
8372
 
8373
- .login-tab.hidden {
8374
- display: none;
8375
- }
8376
-
8377
8373
  body.modal > .wrapper {
8378
8374
  transition: filter 1000ms linear;
8379
8375
  filter: blur(10px);
@@ -9081,6 +9077,33 @@ textarea.rich {
9081
9077
  box-shadow: 0px 1px 1px #fff;
9082
9078
  }
9083
9079
 
9080
+ .totp-enrollment .qr-code {
9081
+ width: 20rem;
9082
+ height: 20rem;
9083
+ border: 1px solid #ddd;
9084
+ border: 1px solid var(--border-color);
9085
+ padding: 1rem;
9086
+ border-radius: 5px;
9087
+ }
9088
+
9089
+ .totp-enrollment .qr-code svg {
9090
+ width: 100%;
9091
+ height: 100%;
9092
+ }
9093
+
9094
+ ul.recovery-codes {
9095
+ list-style-type: none;
9096
+ padding: 0rem;
9097
+ margin: 2rem 0rem;
9098
+ font-family: monospace;
9099
+ display: flex;
9100
+ flex-direction: column;
9101
+ align-items: flex-start;
9102
+ gap: 1rem;
9103
+ font-size: 1.2em;
9104
+ font-weight: bold;
9105
+ }
9106
+
9084
9107
  .drag-handle {
9085
9108
  cursor: pointer;
9086
9109
  float: left;
@@ -25,9 +25,3 @@ main .login-form {
25
25
  }
26
26
  }
27
27
  }
28
-
29
- .login-tab {
30
- &.hidden {
31
- display: none;
32
- }
33
- }
@@ -0,0 +1,26 @@
1
+ .totp-enrollment {
2
+ .qr-code {
3
+ width: 20rem;
4
+ height: 20rem;
5
+ border: 1px solid var(--border-color);
6
+ padding: 1rem;
7
+ border-radius: 5px;
8
+ svg {
9
+ width: 100%;
10
+ height: 100%;
11
+ }
12
+ }
13
+ }
14
+
15
+ ul.recovery-codes {
16
+ list-style-type: none;
17
+ padding: 0rem;
18
+ margin: 2rem 0rem;
19
+ font-family: monospace;
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: flex-start;
23
+ gap: 1rem;
24
+ font-size: 1.2em;
25
+ font-weight: bold;
26
+ }
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Admin
4
+ class AccountRecoveriesController < Admin::AdminController
5
+ before_action :require_authentication, except: %i[new create show update]
6
+ before_action :find_by_token, only: %i[show update]
7
+ around_action :validate_otp, only: %i[update]
8
+
9
+ def show; end
10
+
11
+ def new; end
12
+
13
+ def create
14
+ @user = User.find_by_email(params[:email])
15
+ if @user
16
+ deliver_account_recovery(@user)
17
+ flash[:notice] = t("pages_core.account_recovery.sent")
18
+ else
19
+ flash[:notice] = t("pages_core.account_recovery.not_found")
20
+ end
21
+ redirect_to admin_login_url
22
+ end
23
+
24
+ def update
25
+ if user_params[:password].present? && @user.update(user_params)
26
+ authenticate!(@user)
27
+ flash[:notice] = t("pages_core.account_recovery.changed")
28
+ redirect_to admin_login_url
29
+ else
30
+ render action: :show
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def deliver_account_recovery(user)
37
+ AdminMailer.account_recovery(
38
+ user,
39
+ admin_account_recovery_with_token_url(recovery_token(user))
40
+ ).deliver_later
41
+ end
42
+
43
+ def fail_recovery(message)
44
+ flash[:notice] = message
45
+ redirect_to new_admin_account_recovery_url
46
+ end
47
+
48
+ def find_by_token
49
+ @token = params[:token]
50
+ @user = User.find(message_verifier.verify(@token)[:id])
51
+ return if @user
52
+
53
+ fail_recovery(t("pages_core.account_recovery.invalid_request"))
54
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
55
+ fail_recovery(t("pages_core.account_recovery.invalid_request"))
56
+ end
57
+
58
+ def message_verifier
59
+ Rails.application.message_verifier(:account_recovery)
60
+ end
61
+
62
+ def recovery_token(user)
63
+ message_verifier.generate({ id: user.id }, expires_in: 24.hours)
64
+ end
65
+
66
+ def user_params
67
+ params.require(:user).permit(:password, :password_confirmation)
68
+ end
69
+
70
+ def validate_otp
71
+ User.transaction do
72
+ if valid_otp(@user, params[:otp])
73
+ yield
74
+ else
75
+ flash.now[:notice] = t("pages_core.otp.invalid_code")
76
+ render action: :show
77
+ end
78
+ end
79
+ end
80
+
81
+ def valid_otp(user, otp)
82
+ return true unless user.otp_enabled?
83
+
84
+ OtpSecret.new(user).validate_otp_or_recovery_code!(otp)
85
+ end
86
+ end
87
+ end
@@ -62,11 +62,12 @@ module Admin
62
62
  return if @invite && secure_compare(@invite.token, params[:token])
63
63
 
64
64
  flash[:notice] = t("pages_core.invite_expired")
65
- redirect_to(login_admin_users_url) && return
65
+ redirect_to(admin_login_url)
66
66
  end
67
67
 
68
68
  def user_params
69
- params.require(:user).permit(:name, :email, :password, :confirm_password)
69
+ params.require(:user)
70
+ .permit(:name, :email, :password, :password_confirmation)
70
71
  end
71
72
 
72
73
  def invite_params
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Admin
4
+ class OtpSecretsController < Admin::AdminController
5
+ before_action :require_otp_disabled, only: %i[new create]
6
+ before_action :find_otp_secret
7
+
8
+ def new
9
+ @otp_secret.generate
10
+ end
11
+
12
+ def create
13
+ if @otp_secret.verify(otp_secret_params)
14
+ @recovery_codes = @otp_secret.generate_recovery_codes
15
+ @otp_secret.enable!(@recovery_codes)
16
+ else
17
+ flash[:error] = t("pages_core.otp.invalid_code")
18
+ redirect_to new_admin_otp_secret_path
19
+ end
20
+ end
21
+
22
+ def destroy
23
+ @otp_secret.disable!
24
+ flash[:notice] = t("pages_core.otp.disabled")
25
+ redirect_to edit_admin_user_path(current_user)
26
+ end
27
+
28
+ private
29
+
30
+ def find_otp_secret
31
+ @otp_secret = OtpSecret.new(current_user)
32
+ end
33
+
34
+ def otp_secret_params
35
+ params.permit(:signed_message, :otp)
36
+ end
37
+
38
+ def require_otp_disabled
39
+ return unless current_user.otp_enabled?
40
+
41
+ flash[:notice] = t("pages_core.otp.already_enabled")
42
+ redirect_to edit_admin_user_path(current_user)
43
+ end
44
+ end
45
+ end
@@ -64,7 +64,7 @@ module Admin
64
64
 
65
65
  def move
66
66
  parent = params[:parent_id] ? Page.find(params[:parent_id]) : nil
67
- @page.update(parent: parent, position: params[:position])
67
+ @page.update(parent:, position: params[:position])
68
68
  respond_with_page(@page) { redirect_to admin_pages_url(content_locale) }
69
69
  end
70
70
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Admin
4
+ class RecoveryCodesController < Admin::AdminController
5
+ before_action :require_otp_enabled
6
+ before_action :find_otp_secret
7
+
8
+ def new; end
9
+
10
+ def create
11
+ if @otp_secret.validate_otp!(params[:otp])
12
+ @recovery_codes = @otp_secret.regenerate_recovery_codes!
13
+ else
14
+ flash[:error] = t("pages_core.otp.invalid_code")
15
+ redirect_to new_admin_recovery_codes_path
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def find_otp_secret
22
+ @otp_secret = OtpSecret.new(current_user)
23
+ end
24
+
25
+ def require_otp_enabled
26
+ return if current_user.otp_enabled?
27
+
28
+ flash[:notice] = t("pages_core.otp.required")
29
+ redirect_to edit_admin_user_path(current_user)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Admin
4
+ class SessionsController < Admin::AdminController
5
+ before_action :require_authentication, only: %i[destroy]
6
+ before_action :find_user, only: %i[create]
7
+ before_action :find_signed_user, only: %i[verify_otp]
8
+ before_action :require_user, only: %i[create verify_otp]
9
+
10
+ def new
11
+ redirect_to admin_default_url if logged_in?
12
+ end
13
+
14
+ def create
15
+ if @user.otp_enabled?
16
+ @signed_user_id = message_verifier.generate(
17
+ @user.id, expires_in: 1.hour
18
+ )
19
+ render template: "admin/sessions/verify_otp"
20
+ else
21
+ authenticate!(@user)
22
+ redirect_to admin_default_url
23
+ end
24
+ end
25
+
26
+ def destroy
27
+ flash[:notice] = t("pages_core.logged_out")
28
+ deauthenticate!
29
+ redirect_to admin_login_url
30
+ end
31
+
32
+ def verify_otp
33
+ @otp_secret = OtpSecret.new(@user)
34
+ if @otp_secret.validate_otp!(params[:otp])
35
+ authenticate!(@user)
36
+ redirect_to admin_default_url
37
+ else
38
+ flash[:notice] = t("pages_core.otp.invalid_code")
39
+ render template: "admin/sessions/verify_otp"
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def find_signed_user
46
+ @signed_user_id = params[:signed_user_id]
47
+ @user = User.find(message_verifier.verify(@signed_user_id))
48
+ end
49
+
50
+ def find_user
51
+ @user = User.authenticate(params[:email], password: params[:password])
52
+ end
53
+
54
+ def message_verifier
55
+ Rails.application.message_verifier(:session)
56
+ end
57
+
58
+ def require_user
59
+ return if @user
60
+
61
+ flash[:notice] = t("pages_core.invalid_login")
62
+ redirect_to admin_login_url
63
+ end
64
+ end
65
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Admin
4
4
  class UsersController < Admin::AdminController
5
- before_action :require_authentication, except: %i[new create login]
5
+ before_action :require_authentication, except: %i[new create]
6
6
  before_action :require_no_users, only: %i[new create]
7
7
  before_action(
8
8
  :find_user,
@@ -11,7 +11,7 @@ module Admin
11
11
 
12
12
  def index
13
13
  @users = User.activated
14
- @invites = Invite.all.order("created_at DESC")
14
+ @invites = Invite.order("created_at DESC")
15
15
  end
16
16
 
17
17
  def deactivated
@@ -19,12 +19,6 @@ module Admin
19
19
  @invites = []
20
20
  end
21
21
 
22
- def login
23
- return unless logged_in?
24
-
25
- redirect_to admin_default_url
26
- end
27
-
28
22
  def show; end
29
23
 
30
24
  def new
@@ -81,7 +75,7 @@ module Admin
81
75
  { role_names: [] }]
82
76
  end
83
77
  if User.none? || (@user && policy(@user).change_password?)
84
- permitted_params += %i[password confirm_password]
78
+ permitted_params += %i[password password_confirmation]
85
79
  end
86
80
  params.require(:user).permit(permitted_params)
87
81
  end
@@ -35,20 +35,22 @@ module PagesCore
35
35
  @current_user = user
36
36
  end
37
37
 
38
- def start_authenticated_session
39
- if session[:current_user_id]
40
- user = User.where(id: session[:current_user_id]).first
41
- end
42
-
43
- return unless user&.can_login?
38
+ def finalize_authenticated_session
39
+ return unless logged_in?
44
40
 
45
- authenticated(user)
41
+ session[:current_user] =
42
+ { id: current_user.id, token: current_user.session_token }
46
43
  end
47
44
 
48
- def finalize_authenticated_session
49
- return unless current_user
45
+ def start_authenticated_session
46
+ user_session = session.fetch(:current_user, nil)&.symbolize_keys
47
+
48
+ return unless user_session
50
49
 
51
- session[:current_user_id] = current_user.id
50
+ user = User.find_by(id: user_session[:id])
51
+ return unless user && user.session_token == user_session[:token]
52
+
53
+ authenticated(user)
52
54
  end
53
55
  end
54
56
  end
@@ -5,34 +5,24 @@ module PagesCore
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- before_action :configure_sentry_context
8
+ before_action :configure_sentry_scope
9
9
  end
10
10
 
11
11
  protected
12
12
 
13
- def configure_sentry_context
14
- return if Rails.env.test?
13
+ def configure_sentry_scope
14
+ return if Rails.env.test? || !Object.const_defined?("Sentry")
15
15
 
16
- if Object.const_defined?("Sentry")
17
- Sentry.set_user(current_user_context)
18
- Sentry.set_tags(locale: params[:locale] || I18n.default_locale.to_s)
19
- Sentry.set_extras(params: params.to_unsafe_h)
20
- elsif Object.const_defined?("Raven")
21
- configure_legacy_sentry_context
22
- end
23
- end
24
-
25
- def configure_legacy_sentry_context
26
- Raven.user_context(current_user_context)
27
- Raven.tags_context(locale: params[:locale] || I18n.default_locale.to_s)
28
- Raven.extra_context(params: params.to_unsafe_h)
16
+ Sentry.set_context("params", params.to_unsafe_h)
17
+ Sentry.set_tags(locale: params[:locale] || I18n.default_locale.to_s)
18
+ Sentry.set_user(current_user_context)
29
19
  end
30
20
 
31
21
  def current_user_context
32
- return { user_id: :guest } unless logged_in?
22
+ return {} unless logged_in?
33
23
 
34
- { user_id: current_user.id,
35
- user_email: current_user.email }
24
+ { id: current_user.id,
25
+ email: current_user.email }
36
26
  end
37
27
  end
38
28
  end
@@ -4,10 +4,13 @@ module PagesCore
4
4
  module StaticCacheController
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ included do
8
+ helper_method :static_cached?
9
+ end
10
+
7
11
  module ClassMethods
8
12
  def static_cache(*actions, permanent: false)
9
- return unless perform_caching
10
-
13
+ before_action :prepare_static_cache
11
14
  if permanent
12
15
  after_action :cache_static_page_permanently, only: actions
13
16
  else
@@ -22,6 +25,10 @@ module PagesCore
22
25
  @static_cache_disabled = true
23
26
  end
24
27
 
28
+ def static_cached?
29
+ !@static_cache_disabled && @static_cached ? true : false
30
+ end
31
+
25
32
  private
26
33
 
27
34
  def cache_static_page
@@ -40,6 +47,10 @@ module PagesCore
40
47
  )
41
48
  end
42
49
 
50
+ def prepare_static_cache
51
+ @static_cached = true
52
+ end
53
+
43
54
  def static_cache_allowed?
44
55
  (request.get? || request.head?) && response.status == 200 &&
45
56
  perform_caching && !@static_cache_disabled
@@ -48,7 +48,7 @@ module PagesCore
48
48
  if User.count < 1
49
49
  redirect_to(new_admin_user_url)
50
50
  else
51
- redirect_to(login_admin_users_url)
51
+ redirect_to(admin_login_url)
52
52
  end
53
53
  end
54
54
 
@@ -31,7 +31,7 @@ module PagesCore
31
31
  send_ranged_data(@attachment.data,
32
32
  filename: @attachment.filename,
33
33
  type: @attachment.content_type,
34
- disposition: disposition)
34
+ disposition:)
35
35
  end
36
36
 
37
37
  def verify_signed_params
@@ -121,7 +121,7 @@ module PagesCore
121
121
  def redirect_page(page)
122
122
  return false unless page.redirects?
123
123
 
124
- redirect_to(page.redirect_path(locale: locale), allow_other_host: true)
124
+ redirect_to(page.redirect_path(locale:), allow_other_host: true)
125
125
  end
126
126
 
127
127
  def require_page
@@ -22,21 +22,12 @@ module PagesCore
22
22
 
23
23
  private
24
24
 
25
- def legacy_locales
26
- { "nor" => "nb",
27
- "eng" => "en" }
28
- end
29
-
30
25
  def page_param
31
26
  params[:page].is_a?(String) ? params[:page] : 1
32
27
  end
33
28
 
34
29
  def set_i18n_locale
35
- locale_param = content_locale
36
- if legacy_locales[locale_param]
37
- locale_param = legacy_locales[locale_param]
38
- end
39
- I18n.locale = locale_param
30
+ I18n.locale = content_locale
40
31
  rescue I18n::InvalidLocale
41
32
  raise if Rails.application.config.consider_all_requests_local
42
33
 
@@ -23,7 +23,7 @@ module PagesCore
23
23
  def embed_image(id, size:, class_name:, link:)
24
24
  image_figure(
25
25
  Image.find(id).localize(I18n.locale),
26
- size: size, class_name: class_name, link: link
26
+ size:, class_name:, link:
27
27
  )
28
28
  rescue ActiveRecord::RecordNotFound
29
29
  nil
@@ -44,8 +44,8 @@ module PagesCore
44
44
  link = (Regexp.last_match(1) if options =~ /link="([^"]+)"/)
45
45
  embed_image(id,
46
46
  size: embed_image_size(options),
47
- class_name: class_name,
48
- link: link)
47
+ class_name:,
48
+ link:)
49
49
  end
50
50
 
51
51
  def parse_images(string)
@@ -39,12 +39,12 @@ module Admin
39
39
  ([page.author] + User.activated).uniq
40
40
  end
41
41
 
42
- def page_list_row(page, &block)
42
+ def page_list_row(page, &)
43
43
  classes = [page.status_label.downcase]
44
44
  classes << "autopublish" if page.autopublish?
45
45
  classes << "pinned" if page.pinned?
46
46
 
47
- tag.tr(capture(&block), class: classes.join(" "))
47
+ tag.tr(capture(&), class: classes.join(" "))
48
48
  end
49
49
 
50
50
  def page_name(page, options = {})
@@ -14,7 +14,7 @@ module PagesCore
14
14
  def rich_text_area_tag(name, content = nil, options = {})
15
15
  react_component("RichTextArea",
16
16
  options.merge(id: sanitize_to_id(name),
17
- name: name,
17
+ name:,
18
18
  value: content))
19
19
  end
20
20
 
@@ -33,6 +33,17 @@ module PagesCore
33
33
  %w[January February March April May June July August September October
34
34
  November December][month - 1]
35
35
  end
36
+
37
+ def qr_code(url)
38
+ ActiveSupport::SafeBuffer.new(
39
+ RQRCode::QRCode.new(url)
40
+ .as_svg({ color: "000",
41
+ shape_rendering: "crispEdges",
42
+ module_size: 10,
43
+ use_path: true,
44
+ viewbox: true })
45
+ )
46
+ end
36
47
  end
37
48
  end
38
49
  end
@@ -11,14 +11,14 @@ module PagesCore
11
11
  content_tabs.any?
12
12
  end
13
13
 
14
- def content_tab(name, options = {}, &block)
14
+ def content_tab(name, options = {}, &)
15
15
  return unless block_given?
16
16
 
17
17
  tab = {
18
18
  name: name.to_s.humanize,
19
19
  key: options[:key] || name.to_s.underscore.gsub(/\s+/, "_"),
20
- options: options,
21
- content: capture(&block)
20
+ options:,
21
+ content: capture(&)
22
22
  }
23
23
  content_tabs.push(tab)
24
24
  content_tab_tag(tab[:key], tab[:content])
@@ -38,7 +38,7 @@ module PagesCore
38
38
 
39
39
  def foreign_key(attr)
40
40
  object.class.reflections[attr.to_s].options[:foreign_key] ||
41
- "#{attr}_id".to_sym
41
+ :"#{attr}_id"
42
42
  end
43
43
  end
44
44
  end
@@ -9,10 +9,10 @@ module PagesCore
9
9
  react_component("EditableImage",
10
10
  editable_image_options(
11
11
  image,
12
- width: width,
13
- caption: caption,
14
- locale: locale
15
- ).merge(width: width))
12
+ width:,
13
+ caption:,
14
+ locale:
15
+ ).merge(width:))
16
16
  end
17
17
 
18
18
  def image_uploader_tag(name, image, options = {})
@@ -36,8 +36,8 @@ module PagesCore
36
36
 
37
37
  def editable_image_options(image, width: 250, caption: false, locale: nil)
38
38
  editable_image_src_options(image, width).merge(
39
- width: width,
40
- caption: caption,
39
+ width:,
40
+ caption:,
41
41
  locale: locale || I18n.default_locale,
42
42
  locales: locales_with_dir
43
43
  )
@@ -24,7 +24,7 @@ module PagesCore
24
24
  [labelled_field_label(label, options),
25
25
  labelled_field_description(options[:description]),
26
26
  field,
27
- (options[:check_box_description] || "")]
27
+ options[:check_box_description] || ""]
28
28
  )
29
29
  end
30
30
  end