summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/assets_controller.rb5
-rw-r--r--app/helpers/node_actions_helper.rb15
-rw-r--r--app/models/node.rb8
-rw-r--r--app/models/node_action.rb11
-rw-r--r--config/locales/de.yml3
-rw-r--r--config/locales/en.yml3
-rw-r--r--test/controllers/assets_controller_test.rb10
-rw-r--r--test/models/node_attach_asset_test.rb19
8 files changed, 74 insertions, 0 deletions
diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb
index 8df4c94d..7edd9c05 100644
--- a/app/controllers/assets_controller.rb
+++ b/app/controllers/assets_controller.rb
@@ -50,6 +50,11 @@ class AssetsController < ApplicationController
50 respond_to do |format| 50 respond_to do |format|
51 if @asset.save 51 if @asset.save
52 flash[:notice] = 'Asset was successfully created.' 52 flash[:notice] = 'Asset was successfully created.'
53 NodeAction.record!(:participants => [@asset], :user => current_user,
54 :action => "asset_create",
55 :asset_name => @asset.name,
56 :content_type => @asset.upload_content_type,
57 :path => @asset.upload.url.sub(/\?\d+$/, ""))
53 attach_to(attach_node) if attach_node 58 attach_to(attach_node) if attach_node
54 format.html { redirect_to(@asset) } 59 format.html { redirect_to(@asset) }
55 format.xml { render :xml => @asset, :status => :created, :location => @asset } 60 format.xml { render :xml => @asset, :status => :created, :location => @asset }
diff --git a/app/helpers/node_actions_helper.rb b/app/helpers/node_actions_helper.rb
index 02d1ba83..ed8d0407 100644
--- a/app/helpers/node_actions_helper.rb
+++ b/app/helpers/node_actions_helper.rb
@@ -13,6 +13,9 @@ module NodeActionsHelper
13 "destroy" => "trash-x", 13 "destroy" => "trash-x",
14 "discard_autosave" => "eraser", 14 "discard_autosave" => "eraser",
15 "destroy_draft" => "eraser", 15 "destroy_draft" => "eraser",
16 "asset_create" => "upload",
17 "asset_attach" => "paperclip",
18 "asset_destroy" => "file-x"
16 }.freeze 19 }.freeze
17 20
18 def verb_icon action 21 def verb_icon action
@@ -181,6 +184,18 @@ module NodeActionsHelper
181 :path => h(action.metadata["path"])).html_safe 184 :path => h(action.metadata["path"])).html_safe
182 end 185 end
183 186
187 def summarize_asset_create action
188 t("node_actions.asset_create", :actor => actor_ref(action),
189 :asset => h(action.metadata["asset_name"].presence || action.metadata["path"])).html_safe
190 end
191
192 def summarize_asset_attach action
193 m = action.metadata
194 key = m["headline"] ? "node_actions.asset_attach_headline" : "node_actions.asset_attach"
195 t(key, :actor => actor_ref(action), :subject => subject_ref(action),
196 :asset => h(m["asset_name"].presence || m["path"])).html_safe
197 end
198
184 def summarize_asset_destroy action 199 def summarize_asset_destroy action
185 m = action.metadata 200 m = action.metadata
186 parts = [t("node_actions.asset_destroy", :actor => actor_ref(action), 201 parts = [t("node_actions.asset_destroy", :actor => actor_ref(action),
diff --git a/app/models/node.rb b/app/models/node.rb
index 7a93e799..0a9cd2d1 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -501,6 +501,14 @@ class Node < ApplicationRecord
501 to_attach.each do |row| 501 to_attach.each do |row|
502 row.related_assets.create!(:asset => asset, :headline => headline_state == :set) 502 row.related_assets.create!(:asset => asset, :headline => headline_state == :set)
503 end 503 end
504
505 if to_attach.any?
506 metadata = { :asset_name => asset.name,
507 :path => asset.upload.url.sub(/\?\d+$/, "") }
508 metadata[:headline] = true if headline_state == :set
509 NodeAction.record!(:node => self, :participants => [self, asset],
510 :user => user, :action => "asset_attach", **metadata)
511 end
504 end 512 end
505 513
506 { :attached => to_attach.size, 514 { :attached => to_attach.size,
diff --git a/app/models/node_action.rb b/app/models/node_action.rb
index 9ed0b628..aa52f489 100644
--- a/app/models/node_action.rb
+++ b/app/models/node_action.rb
@@ -69,6 +69,17 @@ class NodeAction < ApplicationRecord
69 # "path" -- final path, flat string (create-symmetric) 69 # "path" -- final path, flat string (create-symmetric)
70 # "destroyed_descendants" -- integer, only when positive; one entry 70 # "destroyed_descendants" -- integer, only when positive; one entry
71 # at the root, per the subtree rule. 71 # at the root, per the subtree rule.
72 #
73 # "asset_create" (witnessed upload; participants: the asset alone):
74 # "asset_name", "content_type", "path" -- flat strings
75 #
76 # "asset_attach" (out-of-band attach via Node#attach_asset!; written
77 # only when at least one new join was created, per the tandem rule --
78 # in-editor curation stays draft-scoped and surfaces at publish.
79 # participants: the node (primary) and the asset):
80 # "asset_name", "path" -- flat strings
81 # "headline" -- boolean, only when set by this attach
82 #
72 # "asset_destroy" (witnessed asset deletion; always written, even for 83 # "asset_destroy" (witnessed asset deletion; always written, even for
73 # unattached assets -- the files were publicly reachable; node column 84 # unattached assets -- the files were publicly reachable; node column
74 # nil, subjects via participants: the asset plus every then-attached 85 # nil, subjects via participants: the asset plus every then-attached
diff --git a/config/locales/de.yml b/config/locales/de.yml
index d6241d51..fff74799 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -116,6 +116,9 @@ de:
116 revision_created: "angelegt am %{date} von %{actor}" 116 revision_created: "angelegt am %{date} von %{actor}"
117 revision_published: "veröffentlicht am %{date} von %{actor}" 117 revision_published: "veröffentlicht am %{date} von %{actor}"
118 revision_restored: "wiederhergestellt am %{date} von %{actor}" 118 revision_restored: "wiederhergestellt am %{date} von %{actor}"
119 asset_create: "%{actor} hat das Asset „%{asset}“ hochgeladen"
120 asset_attach: "%{actor} hat „%{asset}“ an %{subject} angehängt"
121 asset_attach_headline: "%{actor} hat „%{asset}“ als Aufmacher an %{subject} angehängt"
119 asset_destroy: "%{actor} hat das Asset „%{asset}“ gelöscht" 122 asset_destroy: "%{actor} hat das Asset „%{asset}“ gelöscht"
120 asset_destroy_detached: "— entfernt von %{paths}" 123 asset_destroy_detached: "— entfernt von %{paths}"
121 asset_destroy_headlines: "(war Aufmacher von %{paths})" 124 asset_destroy_headlines: "(war Aufmacher von %{paths})"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index bd59915b..fc9f5d13 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -71,6 +71,9 @@ en:
71 asset_destroy: "%{actor} destroyed asset “%{asset}”" 71 asset_destroy: "%{actor} destroyed asset “%{asset}”"
72 asset_destroy_detached: "— detached from %{paths}" 72 asset_destroy_detached: "— detached from %{paths}"
73 asset_destroy_headlines: "(was the headline of %{paths})" 73 asset_destroy_headlines: "(was the headline of %{paths})"
74 asset_create: "%{actor} uploaded asset “%{asset}”"
75 asset_attach: "%{actor} attached “%{asset}” to %{subject}"
76 asset_attach_headline: "%{actor} attached “%{asset}” to %{subject} as its headline"
74 77
75 open_gallery: "Open gallery" 78 open_gallery: "Open gallery"
76 asset_licenses: 79 asset_licenses:
diff --git a/test/controllers/assets_controller_test.rb b/test/controllers/assets_controller_test.rb
index 0e251aad..4be2e8a1 100644
--- a/test/controllers/assets_controller_test.rb
+++ b/test/controllers/assets_controller_test.rb
@@ -133,6 +133,16 @@ class AssetsControllerTest < ActionController::TestCase
133 assert_equal node_path(node), flash[:headline_kept_path] 133 assert_equal node_path(node), flash[:headline_kept_path]
134 end 134 end
135 135
136 test "create with node_id writes an asset_create and an asset_attach entry" do
137 node = Node.root.children.create!(:slug => "asset_log_pair")
138 assert_difference 'NodeAction.where(:action => "asset_create").count' do
139 assert_difference 'NodeAction.where(:action => "asset_attach").count' do
140 post :create, params: { asset: { name: 'Logged twice' }, node_id: node.id }
141 end
142 end
143 assert_equal users(:quentin), NodeAction.last.user
144 end
145
136 # --- edit --- 146 # --- edit ---
137 147
138 test "get edit" do 148 test "get edit" do
diff --git a/test/models/node_attach_asset_test.rb b/test/models/node_attach_asset_test.rb
index cb5b60f5..2df2cfbb 100644
--- a/test/models/node_attach_asset_test.rb
+++ b/test/models/node_attach_asset_test.rb
@@ -95,6 +95,25 @@ class NodeAttachAssetTest < ActiveSupport::TestCase
95 assert_raises(ActiveRecord::RecordInvalid) { @node.attach_asset!(@image, :user => @user) } 95 assert_raises(ActiveRecord::RecordInvalid) { @node.attach_asset!(@image, :user => @user) }
96 end 96 end
97 97
98 test "attaching writes an asset_attach entry with node and asset participants" do
99 result = @node.attach_asset!(@image, :user => @user, :headline => true)
100 assert_equal :set, result[:headline]
101
102 action = NodeAction.where(:action => "asset_attach").last
103 assert_equal @node, action.node
104 subjects = action.action_participants.map { |p| [p.subject_type, p.subject_id] }
105 assert_includes subjects, ["Node", @node.id]
106 assert_includes subjects, ["Asset", @image.id]
107 assert action.metadata["headline"]
108 end
109
110 test "a fully redundant attach writes no entry" do
111 @node.attach_asset!(@image, :user => @user)
112 assert_no_difference 'NodeAction.count' do
113 @node.attach_asset!(@image, :user => @user)
114 end
115 end
116
98 private 117 private
99 118
100 def create_image_asset 119 def create_image_asset