summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-23 17:49:18 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-23 17:49:18 +0200
commitf993853db3e233f05a55de5ba2a87b77acf041aa (patch)
tree0a28289ff471ab5853b22c2a68ed21ce4e0eb4ac /app
parent932d4a4be40587fa6d489eca16a1ef6d6f2936d1 (diff)
Record asset deltas at publish, with changed assets as participants
Diffstat (limited to 'app')
-rw-r--r--app/helpers/node_actions_helper.rb9
-rw-r--r--app/models/node.rb8
-rw-r--r--app/models/node_action.rb34
3 files changed, 45 insertions, 6 deletions
diff --git a/app/helpers/node_actions_helper.rb b/app/helpers/node_actions_helper.rb
index ed8d0407..4041ffa9 100644
--- a/app/helpers/node_actions_helper.rb
+++ b/app/helpers/node_actions_helper.rb
@@ -49,7 +49,7 @@ module NodeActionsHelper
49 m = action.metadata 49 m = action.metadata
50 return true if m["translation_diff"].present? 50 return true if m["translation_diff"].present?
51 return true if m["title"].is_a?(Hash) && m.dig("title", "from") != m.dig("title", "to") 51 return true if m["title"].is_a?(Hash) && m.dig("title", "from") != m.dig("title", "to")
52 %w[author tags template_changed assets_changed 52 %w[author tags template_changed assets assets_changed assets_reordered
53 abstract_changed body_changed].any? { |key| m[key].present? } 53 abstract_changed body_changed].any? { |key| m[key].present? }
54 end 54 end
55 55
@@ -69,6 +69,13 @@ module NodeActionsHelper
69 items << t("node_actions.abstract_changed") if m["abstract_changed"] 69 items << t("node_actions.abstract_changed") if m["abstract_changed"]
70 items << t("node_actions.body_changed") if m["body_changed"] 70 items << t("node_actions.body_changed") if m["body_changed"]
71 items << t("node_actions.template_changed") if m["template_changed"] 71 items << t("node_actions.template_changed") if m["template_changed"]
72 if m["assets"]
73 items << t("node_actions.detail_assets_added",
74 :names => Array(m.dig("assets", "added")).join(", ")) if m.dig("assets", "added")
75 items << t("node_actions.detail_assets_removed",
76 :names => Array(m.dig("assets", "removed")).join(", ")) if m.dig("assets", "removed")
77 end
78 items << t("node_actions.assets_reordered") if m["assets_reordered"]
72 items << t("node_actions.assets_changed") if m["assets_changed"] 79 items << t("node_actions.assets_changed") if m["assets_changed"]
73 items 80 items
74 end 81 end
diff --git a/app/models/node.rb b/app/models/node.rb
index 0a9cd2d1..274b2f94 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -249,7 +249,9 @@ class Node < ApplicationRecord
249 self.head.save! 249 self.head.save!
250 self.draft = nil 250 self.draft = nil
251 251
252 NodeAction.record!(:node => self, :page => self.head, :user => current_user, 252 NodeAction.record!(:node => self,
253 :participants => [self] + NodeAction.changed_assets(outgoing_head, self.head),
254 :page => self.head, :user => current_user,
253 :action => "publish", :via => "draft", 255 :action => "publish", :via => "draft",
254 **NodeAction.head_diff(outgoing_head, self.head)) 256 **NodeAction.head_diff(outgoing_head, self.head))
255 end 257 end
@@ -296,7 +298,9 @@ class Node < ApplicationRecord
296 self.head = page 298 self.head = page
297 self.save! 299 self.save!
298 300
299 NodeAction.record!(:node => self, :page => page, :user => current_user, 301 NodeAction.record!(:node => self,
302 :participants => [self] + NodeAction.changed_assets(outgoing_head, page),
303 :page => page, :user => current_user,
300 :action => "publish", :via => "revision", 304 :action => "publish", :via => "revision",
301 **NodeAction.head_diff(outgoing_head, page)) 305 **NodeAction.head_diff(outgoing_head, page))
302 self 306 self
diff --git a/app/models/node_action.rb b/app/models/node_action.rb
index aa52f489..afa2195c 100644
--- a/app/models/node_action.rb
+++ b/app/models/node_action.rb
@@ -35,8 +35,16 @@ class NodeAction < ApplicationRecord
35 # "title" -- pair, always; "from" null on first publish 35 # "title" -- pair, always; "from" null on first publish
36 # "author" -- pair, when the byline changed (incl. first publish) 36 # "author" -- pair, when the byline changed (incl. first publish)
37 # "tags" -- pair of arrays, when changed 37 # "tags" -- pair of arrays, when changed
38 # "assets_changed", "template_changed", 38 # "assets" -- {"added" => [asset names], "removed" => [asset names]},
39 # "abstract_changed", "body_changed" 39 # keys only when any; a delta, not a pair. The event IS
40 # the delta, full sets would bloat every entry. Changed
41 # assets are participants of the entry. Replaces the
42 # legacy "assets_changed" boolean, which witnessed
43 # pre-contract entries still carry and the renderer keeps
44 # understanding. Assets destroyed since leave no trace in
45 # regenerated deltas, their joins died with them.
46 # "assets_reordered" -- boolean, set unchanged but gallery order not
47 # "template_changed", "abstract_changed", "body_changed"
40 # -- the last two for the default locale; page_id links 48 # -- the last two for the default locale; page_id links
41 # to the revision for the real diff (never stored) 49 # to the revision for the real diff (never stored)
42 # "translation_diff" -- only when a non-default locale differs: 50 # "translation_diff" -- only when a non-default locale differs:
@@ -155,7 +163,17 @@ class NodeAction < ApplicationRecord
155 diff[:tags] = { "from" => old_tags, "to" => new_tags } if old_tags != new_tags 163 diff[:tags] = { "from" => old_tags, "to" => new_tags } if old_tags != new_tags
156 164
157 diff[:template_changed] = true if old_page.template_name != new_page.template_name 165 diff[:template_changed] = true if old_page.template_name != new_page.template_name
158 diff[:assets_changed] = true if old_page.assets.map(&:id) != new_page.assets.map(&:id) 166
167 old_assets, new_assets = old_page.assets.to_a, new_page.assets.to_a
168 added, removed = new_assets - old_assets, old_assets - new_assets
169 if added.any? || removed.any?
170 assets = {}
171 assets["added"] = added.map { |a| a.name.presence || a.upload_file_name } if added.any?
172 assets["removed"] = removed.map { |a| a.name.presence || a.upload_file_name } if removed.any?
173 diff[:assets] = assets
174 elsif old_assets.map(&:id) != new_assets.map(&:id)
175 diff[:assets_reordered] = true
176 end
159 177
160 old_t = old_page.translations.find_by(:locale => default) 178 old_t = old_page.translations.find_by(:locale => default)
161 new_t = new_page.translations.find_by(:locale => default) 179 new_t = new_page.translations.find_by(:locale => default)
@@ -188,6 +206,16 @@ class NodeAction < ApplicationRecord
188 diff 206 diff
189 end 207 end
190 208
209 # The asset records added or removed between an outgoing head and its
210 # replacement -- the participant complement to head_diff's "assets"
211 # names. Empty on first publish, mirroring head_diff, which records
212 # no asset delta when everything is new.
213 def self.changed_assets old_page, new_page
214 return [] unless old_page
215 old_a, new_a = old_page.assets.to_a, new_page.assets.to_a
216 (new_a - old_a) | (old_a - new_a)
217 end
218
191 def actor_name 219 def actor_name
192 metadata["username"] || "unknown" 220 metadata["username"] || "unknown"
193 end 221 end