alchemy_cms 8.3.5 → 8.3.6
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.
- checksums.yaml +4 -4
- data/app/components/alchemy/ingredients/richtext_view.rb +4 -0
- data/app/controllers/alchemy/api/nodes_controller.rb +1 -1
- data/app/models/alchemy/ingredients/richtext.rb +4 -4
- data/app/models/alchemy/node.rb +21 -0
- data/app/models/alchemy/permissions.rb +10 -0
- data/app/models/alchemy/storage_adapter/active_storage.rb +22 -0
- data/lib/alchemy/engine.rb +6 -7
- data/lib/alchemy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e13db27417e434306c2ba48c7b3718758690ca49b7cc0ad85aea8921210779e6
|
|
4
|
+
data.tar.gz: 2a13089265941fac886d3523485414f4cf774d0150382926a0a7131d421f0296
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4aa7ac27020b95dea3b8ea39a039a0186c5d62d12461f2a6af14d1ff3122fb74fbf33f6e44313345e2d04c8b5b3c8c668658cc7beacf34cf35cdd0af63539280
|
|
7
|
+
data.tar.gz: b301ea1b3dfc42b213fc6af56f08feabec797d6ffe8354614a8465ec653b436065fd292183593bb71bbccb9225207c64e8608239602cc23929e1d3ba3653280d
|
|
@@ -3,6 +3,8 @@ module Alchemy
|
|
|
3
3
|
class RichtextView < BaseView
|
|
4
4
|
attr_reader :plain_text
|
|
5
5
|
|
|
6
|
+
delegate :sanitizer_settings, to: :ingredient
|
|
7
|
+
|
|
6
8
|
# @param ingredient [Alchemy::Ingredient]
|
|
7
9
|
# @param plain_text [Boolean] (false) Whether to show as plain text or with markup
|
|
8
10
|
def initialize(ingredient, plain_text: nil, html_options: {})
|
|
@@ -13,6 +15,8 @@ module Alchemy
|
|
|
13
15
|
def call
|
|
14
16
|
if plain_text
|
|
15
17
|
ingredient.stripped_body
|
|
18
|
+
elsif sanitizer_settings.present?
|
|
19
|
+
sanitize(value.to_s, **sanitizer_settings)
|
|
16
20
|
else
|
|
17
21
|
value.to_s.html_safe
|
|
18
22
|
end.html_safe
|
|
@@ -6,7 +6,7 @@ module Alchemy
|
|
|
6
6
|
before_action :authorize_access, only: [:move, :toggle_folded]
|
|
7
7
|
|
|
8
8
|
def index
|
|
9
|
-
@nodes = Node.
|
|
9
|
+
@nodes = Node.accessible_by(current_ability, :index)
|
|
10
10
|
@nodes = @nodes.includes(:parent)
|
|
11
11
|
@nodes = @nodes.where(language_id: params[:language_id]) if params[:language_id]
|
|
12
12
|
@nodes = @nodes.ransack(params[:filter]).result.order(:lft)
|
|
@@ -36,6 +36,10 @@ module Alchemy
|
|
|
36
36
|
settings[:tinymce] || {}
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def sanitizer_settings
|
|
40
|
+
settings[:sanitizer] || {}
|
|
41
|
+
end
|
|
42
|
+
|
|
39
43
|
private
|
|
40
44
|
|
|
41
45
|
def strip_content
|
|
@@ -48,10 +52,6 @@ module Alchemy
|
|
|
48
52
|
sanitizer_settings
|
|
49
53
|
)
|
|
50
54
|
end
|
|
51
|
-
|
|
52
|
-
def sanitizer_settings
|
|
53
|
-
settings[:sanitizer] || {}
|
|
54
|
-
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
end
|
data/app/models/alchemy/node.rb
CHANGED
|
@@ -20,6 +20,27 @@ module Alchemy
|
|
|
20
20
|
foreign_key: :related_object_id,
|
|
21
21
|
inverse_of: :related_object
|
|
22
22
|
|
|
23
|
+
# All nodes of the current site whose language is published.
|
|
24
|
+
scope :from_current_public_site, -> {
|
|
25
|
+
joins(:language)
|
|
26
|
+
.where(Alchemy::Language.table_name => {site_id: Alchemy::Current.site})
|
|
27
|
+
.merge(Alchemy::Language.published)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Nodes an anonymous visitor may see: external links or nodes attached to a
|
|
31
|
+
# published, unrestricted page, scoped to the current site.
|
|
32
|
+
scope :available_to_guests, -> {
|
|
33
|
+
from_current_public_site.where(page: nil)
|
|
34
|
+
.or(from_current_public_site.where(page: Alchemy::Page.published.not_restricted))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Like #available_to_guests but including nodes attached to restricted pages,
|
|
38
|
+
# which logged in members are allowed to see.
|
|
39
|
+
scope :available_to_members, -> {
|
|
40
|
+
from_current_public_site.where(page: nil)
|
|
41
|
+
.or(from_current_public_site.where(page: Alchemy::Page.published))
|
|
42
|
+
}
|
|
43
|
+
|
|
23
44
|
before_validation :translate_root_menu_name, if: -> { root? }
|
|
24
45
|
before_validation :set_menu_type_from_root, unless: -> { root? }
|
|
25
46
|
|
|
@@ -44,6 +44,11 @@ module Alchemy
|
|
|
44
44
|
can :read, Alchemy::Page, Alchemy::Page.published.not_restricted.from_current_site do |p|
|
|
45
45
|
p.public? && !p.restricted? && p.site == Alchemy::Current.site
|
|
46
46
|
end
|
|
47
|
+
|
|
48
|
+
can :read, Alchemy::Node, Alchemy::Node.available_to_guests do |node|
|
|
49
|
+
node.language.public? && node.language.site_id == Alchemy::Current.site&.id &&
|
|
50
|
+
(node.page.nil? || (node.page.public? && !node.page.restricted?))
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -67,6 +72,11 @@ module Alchemy
|
|
|
67
72
|
can :read, Alchemy::Page, Alchemy::Page.published.from_current_site do |p|
|
|
68
73
|
p.public? && p.site == Alchemy::Current.site
|
|
69
74
|
end
|
|
75
|
+
|
|
76
|
+
can :read, Alchemy::Node, Alchemy::Node.available_to_members do |node|
|
|
77
|
+
node.language.public? && node.language.site_id == Alchemy::Current.site&.id &&
|
|
78
|
+
(node.page.nil? || node.page.public?)
|
|
79
|
+
end
|
|
70
80
|
end
|
|
71
81
|
end
|
|
72
82
|
|
|
@@ -11,6 +11,17 @@ module Alchemy
|
|
|
11
11
|
base.after_create_commit if: :svg? do
|
|
12
12
|
SanitizeSvgJob.perform_later(self, file_accessor: :image_file)
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
# The image file's dirty state is cleared by the time
|
|
16
|
+
# +after_update_commit+ runs, so capture it here to know whether the
|
|
17
|
+
# blob was actually replaced (rather than only its metadata updated).
|
|
18
|
+
base.before_update do
|
|
19
|
+
@image_file_replaced = image_file.changed?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
base.after_update_commit if: -> { @image_file_replaced && svg? } do
|
|
23
|
+
SanitizeSvgJob.perform_later(self, file_accessor: :image_file)
|
|
24
|
+
end
|
|
14
25
|
end
|
|
15
26
|
end
|
|
16
27
|
|
|
@@ -20,6 +31,17 @@ module Alchemy
|
|
|
20
31
|
base.after_create_commit if: :svg? do
|
|
21
32
|
SanitizeSvgJob.perform_later(self, file_accessor: :file)
|
|
22
33
|
end
|
|
34
|
+
|
|
35
|
+
# The file's dirty state is cleared by the time
|
|
36
|
+
# +after_update_commit+ runs, so capture it here to know whether the
|
|
37
|
+
# blob was actually replaced (rather than only its metadata updated).
|
|
38
|
+
base.before_update do
|
|
39
|
+
@file_replaced = file.changed?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
base.after_update_commit if: -> { @file_replaced && svg? } do
|
|
43
|
+
SanitizeSvgJob.perform_later(self, file_accessor: :file)
|
|
44
|
+
end
|
|
23
45
|
end
|
|
24
46
|
end
|
|
25
47
|
|
data/lib/alchemy/engine.rb
CHANGED
|
@@ -178,13 +178,12 @@ module Alchemy
|
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
if app.config.active_storage
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
#
|
|
187
|
-
# We sanitize SVGs on upload and therefore can serve them as image.
|
|
181
|
+
# Serve SVGs with their real image/svg+xml content type so they render
|
|
182
|
+
# in <img> tags. We deliberately do NOT add svg to
|
|
183
|
+
# +content_types_allowed_inline+: an SVG opened as a top-level document
|
|
184
|
+
# executes its embedded scripts, so it must be served with an
|
|
185
|
+
# attachment (download) disposition rather than inline. <img> ignores
|
|
186
|
+
# Content-Disposition, so image display is unaffected.
|
|
188
187
|
if app.config.active_storage.content_types_to_serve_as_binary.include? svg
|
|
189
188
|
app.config.active_storage.content_types_to_serve_as_binary.delete(svg)
|
|
190
189
|
end
|
data/lib/alchemy/version.rb
CHANGED