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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbbeeb181a57c8aa3b7093ff06d224379e907c822cc904966a60ea9e4fd47a9a
4
- data.tar.gz: 14534974daa1420fa07cd3af38c71ed2a983ef6a0952d4b0457f8805a441dab4
3
+ metadata.gz: e13db27417e434306c2ba48c7b3718758690ca49b7cc0ad85aea8921210779e6
4
+ data.tar.gz: 2a13089265941fac886d3523485414f4cf774d0150382926a0a7131d421f0296
5
5
  SHA512:
6
- metadata.gz: d69c8d862b3301e857ed130f974be1106aef8fca47cf296571596e5121e51c42a5a8e81ae9421b8fe88b5765ddeecbc5ec07a5fe07944a4f1795e11477e0eb27
7
- data.tar.gz: 1aebb4ad39b71937f7168d4659e3f9318579c5e9ba13dde47b16108e8d27ec5e3c5f38302397d7561b6ed5136838f1460ecb54257106839073a817e11581688c
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.all
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
@@ -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
 
@@ -178,13 +178,12 @@ module Alchemy
178
178
  end
179
179
 
180
180
  if app.config.active_storage
181
- # Rails sends svg images as attachment instead of inline.
182
- # We want to display svgs and not download them.
183
- unless app.config.active_storage.content_types_allowed_inline.include? svg
184
- app.config.active_storage.content_types_allowed_inline += [svg]
185
- end
186
- # Rails renders SVG as binary for security reasons.
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
@@ -3,7 +3,7 @@
3
3
  module Alchemy
4
4
  extend self
5
5
 
6
- VERSION = "8.3.5"
6
+ VERSION = "8.3.6"
7
7
 
8
8
  def version
9
9
  VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.3.5
4
+ version: 8.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen