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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/assets/builds/pages_core/admin-dist.js +1 -1
- data/app/assets/builds/pages_core/admin-dist.js.map +4 -4
- data/app/assets/builds/pages_core/admin.css +27 -4
- data/app/assets/stylesheets/pages_core/admin/components/login.css +0 -6
- data/app/assets/stylesheets/pages_core/admin/components/totp.css +26 -0
- data/app/controllers/admin/account_recoveries_controller.rb +87 -0
- data/app/controllers/admin/invites_controller.rb +3 -2
- data/app/controllers/admin/otp_secrets_controller.rb +45 -0
- data/app/controllers/admin/pages_controller.rb +1 -1
- data/app/controllers/admin/recovery_codes_controller.rb +32 -0
- data/app/controllers/admin/sessions_controller.rb +65 -0
- data/app/controllers/admin/users_controller.rb +3 -9
- data/app/controllers/concerns/pages_core/authentication.rb +12 -10
- data/app/controllers/concerns/pages_core/error_reporting.rb +9 -19
- data/app/controllers/concerns/pages_core/static_cache_controller.rb +13 -2
- data/app/controllers/pages_core/admin_controller.rb +1 -1
- data/app/controllers/pages_core/attachments_controller.rb +1 -1
- data/app/controllers/pages_core/frontend/pages_controller.rb +1 -1
- data/app/controllers/pages_core/frontend_controller.rb +1 -10
- data/app/formatters/pages_core/image_embedder.rb +3 -3
- data/app/helpers/admin/pages_helper.rb +2 -2
- data/app/helpers/pages_core/admin/admin_helper.rb +12 -1
- data/app/helpers/pages_core/admin/content_tabs_helper.rb +3 -3
- data/app/helpers/pages_core/admin/form_builder.rb +1 -1
- data/app/helpers/pages_core/admin/image_uploads_helper.rb +6 -6
- data/app/helpers/pages_core/admin/labelled_field_helper.rb +1 -1
- data/app/helpers/pages_core/admin/locales_helper.rb +1 -1
- data/app/helpers/pages_core/application_helper.rb +3 -3
- data/app/helpers/pages_core/head_tags_helper.rb +8 -9
- data/app/helpers/pages_core/images_helper.rb +7 -7
- data/app/helpers/pages_core/open_graph_tags_helper.rb +2 -2
- data/app/helpers/pages_core/page_path_helper.rb +2 -2
- data/app/javascript/index.ts +0 -2
- data/app/jobs/pages_core/autopublish_job.rb +2 -0
- data/app/mailers/admin_mailer.rb +2 -2
- data/app/models/concerns/pages_core/has_otp.rb +27 -0
- data/app/models/concerns/pages_core/has_roles.rb +2 -2
- data/app/models/concerns/pages_core/page_model/dated_page.rb +1 -1
- data/app/models/concerns/pages_core/page_model/searchable.rb +1 -1
- data/app/models/concerns/pages_core/page_model/templateable.rb +22 -0
- data/app/models/concerns/pages_core/searchable_document.rb +3 -3
- data/app/models/otp_secret.rb +101 -0
- data/app/models/page.rb +1 -1
- data/app/models/page_builder.rb +9 -9
- data/app/models/page_exporter.rb +1 -1
- data/app/models/page_image.rb +1 -1
- data/app/models/page_path.rb +3 -3
- data/app/models/search_document.rb +3 -3
- data/app/models/tag.rb +1 -1
- data/app/models/user.rb +15 -37
- data/app/policies/user_policy.rb +4 -0
- data/app/services/pages_core/create_user_service.rb +2 -2
- data/app/services/pages_core/destroy_invite_service.rb +2 -2
- data/app/services/pages_core/invite_service.rb +2 -2
- data/app/views/admin/account_recoveries/new.html.erb +22 -0
- data/app/views/admin/account_recoveries/show.html.erb +37 -0
- data/app/views/admin/invites/show.html.erb +1 -1
- data/app/views/admin/otp_secrets/create.html.erb +7 -0
- data/app/views/admin/otp_secrets/new.html.erb +60 -0
- data/app/views/admin/pages/_edit_content.html.erb +1 -1
- data/app/views/admin/pages/_form.html.erb +12 -0
- data/app/views/admin/recovery_codes/_codes.html.erb +14 -0
- data/app/views/admin/recovery_codes/create.html.erb +7 -0
- data/app/views/admin/recovery_codes/new.html.erb +11 -0
- data/app/views/admin/sessions/_otp_form.html.erb +13 -0
- data/app/views/admin/sessions/new.html.erb +33 -0
- data/app/views/admin/sessions/verify_otp.html.erb +19 -0
- data/app/views/admin/users/edit.html.erb +31 -1
- data/app/views/admin/users/new.html.erb +1 -1
- data/app/views/admin_mailer/account_recovery.text.erb +10 -0
- data/app/views/layouts/admin/_header.html.erb +1 -1
- data/app/views/layouts/admin/_toast.html.erb +12 -0
- data/app/views/layouts/admin.html.erb +1 -1
- data/config/locales/en.yml +11 -3
- data/config/routes.rb +11 -6
- data/db/migrate/20111219033112_create_pages_tables.rb +0 -14
- data/db/migrate/20240126160700_add_2fa_fields.rb +22 -0
- data/db/migrate/20240129201300_remove_password_reset_tokens.rb +13 -0
- data/lib/pages_core/cache_sweeper.rb +3 -3
- data/lib/pages_core/extensions/string_extensions.rb +1 -1
- data/lib/pages_core/templates/configuration.rb +1 -1
- data/lib/pages_core/templates/template_configuration.rb +1 -1
- data/lib/pages_core.rb +7 -2
- data/lib/rails/generators/pages_core/install/install_generator.rb +0 -15
- data/lib/rails/generators/pages_core/rspec/templates/page_templates_spec.rb +1 -1
- metadata +53 -56
- data/app/controllers/admin/password_resets_controller.rb +0 -85
- data/app/controllers/sessions_controller.rb +0 -27
- data/app/javascript/controllers/LoginController.ts +0 -32
- data/app/models/password_reset_token.rb +0 -34
- data/app/views/admin/password_resets/show.html.erb +0 -21
- data/app/views/admin/users/login.html.erb +0 -65
- data/app/views/admin_mailer/password_reset.text.erb +0 -11
- data/lib/rails/generators/pages_core/install/templates/active_job_initializer.rb +0 -3
- data/lib/rails/generators/pages_core/install/templates/delayed_job +0 -7
- 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;
|
@@ -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(
|
65
|
+
redirect_to(admin_login_url)
|
66
66
|
end
|
67
67
|
|
68
68
|
def user_params
|
69
|
-
params.require(:user)
|
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
|
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
|
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.
|
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
|
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
|
39
|
-
|
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
|
-
|
41
|
+
session[:current_user] =
|
42
|
+
{ id: current_user.id, token: current_user.session_token }
|
46
43
|
end
|
47
44
|
|
48
|
-
def
|
49
|
-
|
45
|
+
def start_authenticated_session
|
46
|
+
user_session = session.fetch(:current_user, nil)&.symbolize_keys
|
47
|
+
|
48
|
+
return unless user_session
|
50
49
|
|
51
|
-
|
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 :
|
8
|
+
before_action :configure_sentry_scope
|
9
9
|
end
|
10
10
|
|
11
11
|
protected
|
12
12
|
|
13
|
-
def
|
14
|
-
return if Rails.env.test?
|
13
|
+
def configure_sentry_scope
|
14
|
+
return if Rails.env.test? || !Object.const_defined?("Sentry")
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
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 {
|
22
|
+
return {} unless logged_in?
|
33
23
|
|
34
|
-
{
|
35
|
-
|
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
|
-
|
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
|
@@ -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:
|
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
|
-
|
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
|
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
|
48
|
-
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, &
|
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(&
|
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
|
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 = {}, &
|
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
|
21
|
-
content: capture(&
|
20
|
+
options:,
|
21
|
+
content: capture(&)
|
22
22
|
}
|
23
23
|
content_tabs.push(tab)
|
24
24
|
content_tab_tag(tab[:key], tab[:content])
|
@@ -9,10 +9,10 @@ module PagesCore
|
|
9
9
|
react_component("EditableImage",
|
10
10
|
editable_image_options(
|
11
11
|
image,
|
12
|
-
width
|
13
|
-
caption
|
14
|
-
locale:
|
15
|
-
).merge(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
|
40
|
-
caption
|
39
|
+
width:,
|
40
|
+
caption:,
|
41
41
|
locale: locale || I18n.default_locale,
|
42
42
|
locales: locales_with_dir
|
43
43
|
)
|