diff options
| -rw-r--r-- | app/controllers/node_actions_controller.rb | 5 | ||||
| -rw-r--r-- | app/helpers/node_actions_helper.rb | 54 | ||||
| -rw-r--r-- | app/views/assets/show.html.erb | 3 | ||||
| -rw-r--r-- | app/views/node_actions/_change_details.html.erb | 2 | ||||
| -rw-r--r-- | config/locales/de.yml | 3 | ||||
| -rw-r--r-- | config/locales/en.yml | 3 | ||||
| -rw-r--r-- | test/controllers/node_actions_controller_test.rb | 15 |
7 files changed, 74 insertions, 11 deletions
diff --git a/app/controllers/node_actions_controller.rb b/app/controllers/node_actions_controller.rb index 9b97b450..0f547732 100644 --- a/app/controllers/node_actions_controller.rb +++ b/app/controllers/node_actions_controller.rb | |||
| @@ -11,6 +11,11 @@ class NodeActionsController < ApplicationController | |||
| 11 | .where(:action_participants => { :subject_type => "Node", | 11 | .where(:action_participants => { :subject_type => "Node", |
| 12 | :subject_id => params[:node_id] }) | 12 | :subject_id => params[:node_id] }) |
| 13 | end | 13 | end |
| 14 | if params[:asset_id].present? | ||
| 15 | @actions = @actions.joins(:action_participants) | ||
| 16 | .where(:action_participants => { :subject_type => "Asset", | ||
| 17 | :subject_id => params[:asset_id] }) | ||
| 18 | end | ||
| 14 | @actions = @actions.where(:user_id => params[:user_id]) if params[:user_id].present? | 19 | @actions = @actions.where(:user_id => params[:user_id]) if params[:user_id].present? |
| 15 | @actions = @actions.includes(:node, :user) | 20 | @actions = @actions.includes(:node, :user) |
| 16 | .paginate(:page => params[:page], :per_page => 50) | 21 | .paginate(:page => params[:page], :per_page => 50) |
diff --git a/app/helpers/node_actions_helper.rb b/app/helpers/node_actions_helper.rb index 4041ffa9..a4d13d22 100644 --- a/app/helpers/node_actions_helper.rb +++ b/app/helpers/node_actions_helper.rb | |||
| @@ -44,7 +44,8 @@ module NodeActionsHelper | |||
| 44 | :action => h(action.action), :subject => subject_ref(action)).html_safe | 44 | :action => h(action.action), :subject => subject_ref(action)).html_safe |
| 45 | end | 45 | end |
| 46 | 46 | ||
| 47 | 47 | # Plain strings by design, safe_join in the template escapes them. | |
| 48 | # Exception: the asset items carry zoom links and arrive pre-escaped. | ||
| 48 | def action_details? action | 49 | def action_details? action |
| 49 | m = action.metadata | 50 | m = action.metadata |
| 50 | return true if m["translation_diff"].present? | 51 | return true if m["translation_diff"].present? |
| @@ -53,7 +54,6 @@ module NodeActionsHelper | |||
| 53 | abstract_changed body_changed].any? { |key| m[key].present? } | 54 | abstract_changed body_changed].any? { |key| m[key].present? } |
| 54 | end | 55 | end |
| 55 | 56 | ||
| 56 | # Plain strings by design -- safe_join in the template escapes them. | ||
| 57 | def default_locale_changes action | 57 | def default_locale_changes action |
| 58 | m = action.metadata | 58 | m = action.metadata |
| 59 | items = [] | 59 | items = [] |
| @@ -70,10 +70,14 @@ module NodeActionsHelper | |||
| 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"] | 72 | if m["assets"] |
| 73 | items << t("node_actions.detail_assets_added", | 73 | if (names = m.dig("assets", "added")) |
| 74 | :names => Array(m.dig("assets", "added")).join(", ")) if m.dig("assets", "added") | 74 | items << t("node_actions.detail_assets_added", |
| 75 | items << t("node_actions.detail_assets_removed", | 75 | :names => linked_asset_names(action, names)).html_safe |
| 76 | :names => Array(m.dig("assets", "removed")).join(", ")) if m.dig("assets", "removed") | 76 | end |
| 77 | if (names = m.dig("assets", "removed")) | ||
| 78 | items << t("node_actions.detail_assets_removed", | ||
| 79 | :names => linked_asset_names(action, names)).html_safe | ||
| 80 | end | ||
| 77 | end | 81 | end |
| 78 | items << t("node_actions.assets_reordered") if m["assets_reordered"] | 82 | items << t("node_actions.assets_reordered") if m["assets_reordered"] |
| 79 | items << t("node_actions.assets_changed") if m["assets_changed"] | 83 | items << t("node_actions.assets_changed") if m["assets_changed"] |
| @@ -138,6 +142,38 @@ module NodeActionsHelper | |||
| 138 | : h(action.subject_name) | 142 | : h(action.subject_name) |
| 139 | end | 143 | end |
| 140 | 144 | ||
| 145 | def asset_ref action | ||
| 146 | asset = action.action_participants.detect { |p| p.subject_type == "Asset" }&.subject | ||
| 147 | name = action.metadata["asset_name"].presence || action.metadata["path"] | ||
| 148 | return h(name) unless asset | ||
| 149 | |||
| 150 | parts = [link_to(h(name), asset_path(asset))] | ||
| 151 | unless params[:asset_id].to_s == asset.id.to_s | ||
| 152 | parts << link_to(t("node_actions.asset_history"), | ||
| 153 | admin_log_path(:asset_id => asset.id), | ||
| 154 | :class => "node_action_zoom") | ||
| 155 | end | ||
| 156 | safe_join(parts, " ") | ||
| 157 | end | ||
| 158 | |||
| 159 | def linked_asset_names action, names | ||
| 160 | by_name = action.action_participants.includes(:subject) | ||
| 161 | .select { |p| p.subject_type == "Asset" } | ||
| 162 | .filter_map(&:subject).index_by(&:name) | ||
| 163 | safe_join(names.map { |n| | ||
| 164 | asset = by_name[n] | ||
| 165 | next h(n) unless asset | ||
| 166 | |||
| 167 | parts = [link_to(h(n), asset_path(asset))] | ||
| 168 | unless params[:asset_id].to_s == asset.id.to_s | ||
| 169 | parts << link_to(t("node_actions.asset_history"), | ||
| 170 | admin_log_path(:asset_id => asset.id), | ||
| 171 | :class => "node_action_zoom") | ||
| 172 | end | ||
| 173 | safe_join(parts, " ") | ||
| 174 | }, ", ") | ||
| 175 | end | ||
| 176 | |||
| 141 | def summarize_publish action | 177 | def summarize_publish action |
| 142 | if action.metadata["via"] == "revision" | 178 | if action.metadata["via"] == "revision" |
| 143 | t("node_actions.publish_rollback", | 179 | t("node_actions.publish_rollback", |
| @@ -193,20 +229,20 @@ module NodeActionsHelper | |||
| 193 | 229 | ||
| 194 | def summarize_asset_create action | 230 | def summarize_asset_create action |
| 195 | t("node_actions.asset_create", :actor => actor_ref(action), | 231 | t("node_actions.asset_create", :actor => actor_ref(action), |
| 196 | :asset => h(action.metadata["asset_name"].presence || action.metadata["path"])).html_safe | 232 | :asset => asset_ref(action)).html_safe |
| 197 | end | 233 | end |
| 198 | 234 | ||
| 199 | def summarize_asset_attach action | 235 | def summarize_asset_attach action |
| 200 | m = action.metadata | 236 | m = action.metadata |
| 201 | key = m["headline"] ? "node_actions.asset_attach_headline" : "node_actions.asset_attach" | 237 | key = m["headline"] ? "node_actions.asset_attach_headline" : "node_actions.asset_attach" |
| 202 | t(key, :actor => actor_ref(action), :subject => subject_ref(action), | 238 | t(key, :actor => actor_ref(action), :subject => subject_ref(action), |
| 203 | :asset => h(m["asset_name"].presence || m["path"])).html_safe | 239 | :asset => asset_ref(action)).html_safe |
| 204 | end | 240 | end |
| 205 | 241 | ||
| 206 | def summarize_asset_destroy action | 242 | def summarize_asset_destroy action |
| 207 | m = action.metadata | 243 | m = action.metadata |
| 208 | parts = [t("node_actions.asset_destroy", :actor => actor_ref(action), | 244 | parts = [t("node_actions.asset_destroy", :actor => actor_ref(action), |
| 209 | :asset => h(m["asset_name"].presence || m["path"]))] | 245 | :asset => asset_ref(action))] |
| 210 | parts << t("node_actions.asset_destroy_detached", | 246 | parts << t("node_actions.asset_destroy_detached", |
| 211 | :paths => h(Array(m["detached_from"]).join(", "))) if m["detached_from"].present? | 247 | :paths => h(Array(m["detached_from"]).join(", "))) if m["detached_from"].present? |
| 212 | parts << t("node_actions.asset_destroy_headlines", | 248 | parts << t("node_actions.asset_destroy_headlines", |
diff --git a/app/views/assets/show.html.erb b/app/views/assets/show.html.erb index 27238211..122b44e4 100644 --- a/app/views/assets/show.html.erb +++ b/app/views/assets/show.html.erb | |||
| @@ -13,6 +13,9 @@ | |||
| 13 | <div class="node_info_item"> | 13 | <div class="node_info_item"> |
| 14 | <%= link_to 'Back', assets_path %> | 14 | <%= link_to 'Back', assets_path %> |
| 15 | </div> | 15 | </div> |
| 16 | <%= link_to admin_log_path(:asset_id => @asset.id), :class => "action_button" do %> | ||
| 17 | <%= icon("history", library: "tabler", "aria-hidden": true) %> <%= t("node_actions.asset_history") %> | ||
| 18 | <% end %> | ||
| 16 | </div> | 19 | </div> |
| 17 | </div> | 20 | </div> |
| 18 | 21 | ||
diff --git a/app/views/node_actions/_change_details.html.erb b/app/views/node_actions/_change_details.html.erb index 066d0f30..19e2fe29 100644 --- a/app/views/node_actions/_change_details.html.erb +++ b/app/views/node_actions/_change_details.html.erb | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | <th><%= I18n.default_locale.to_s.upcase %></th> | 6 | <th><%= I18n.default_locale.to_s.upcase %></th> |
| 7 | <td> | 7 | <td> |
| 8 | <%= safe_join(default_items, tag.br) %> | 8 | <%= safe_join(default_items, tag.br) %> |
| 9 | <br/> | ||
| 9 | <% if action_entry.page && action_entry.node %> | 10 | <% if action_entry.page && action_entry.node %> |
| 10 | <% if (diff_params = action_entry.diff_link_params) %> | 11 | <% if (diff_params = action_entry.diff_link_params) %> |
| 11 | <%= link_to t("node_actions.view_diff"), diff_node_revisions_path(action_entry.node, diff_params) %> | 12 | <%= link_to t("node_actions.view_diff"), diff_node_revisions_path(action_entry.node, diff_params) %> |
| @@ -21,6 +22,7 @@ | |||
| 21 | <th><%= locale.upcase %></th> | 22 | <th><%= locale.upcase %></th> |
| 22 | <td> | 23 | <td> |
| 23 | <%= safe_join(translation_changes(diff), tag.br) %> | 24 | <%= safe_join(translation_changes(diff), tag.br) %> |
| 25 | <br/> | ||
| 24 | <% if action_entry.page && action_entry.node %> | 26 | <% if action_entry.page && action_entry.node %> |
| 25 | <% if (diff_params = action_entry.diff_link_params) %> | 27 | <% if (diff_params = action_entry.diff_link_params) %> |
| 26 | <%= link_to t("node_actions.view_diff"), diff_node_revisions_path(action_entry.node, diff_params.merge(:locale => locale)) %> | 28 | <%= link_to t("node_actions.view_diff"), diff_node_revisions_path(action_entry.node, diff_params.merge(:locale => locale)) %> |
diff --git a/config/locales/de.yml b/config/locales/de.yml index b1594f19..d5ba0706 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml | |||
| @@ -87,7 +87,7 @@ de: | |||
| 87 | heading: "Letzte Änderungen" | 87 | heading: "Letzte Änderungen" |
| 88 | show_all: "Alle Einträge zeigen" | 88 | show_all: "Alle Einträge zeigen" |
| 89 | backfilled: "rekonstruiert" | 89 | backfilled: "rekonstruiert" |
| 90 | show_changes: "Änderungen an Übersetzungen" | 90 | show_changes: "Änderungen im Detail" |
| 91 | view_revision: "Diese Revision ansehen" | 91 | view_revision: "Diese Revision ansehen" |
| 92 | unknown: "%{actor} hat %{action} auf %{subject} ausgeführt" | 92 | unknown: "%{actor} hat %{action} auf %{subject} ausgeführt" |
| 93 | publish: "%{actor} hat %{revision} von %{subject} veröffentlicht" | 93 | publish: "%{actor} hat %{revision} von %{subject} veröffentlicht" |
| @@ -116,6 +116,7 @@ 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_history: "Chronik" | ||
| 119 | asset_create: "%{actor} hat das Asset „%{asset}“ hochgeladen" | 120 | asset_create: "%{actor} hat das Asset „%{asset}“ hochgeladen" |
| 120 | asset_attach: "%{actor} hat „%{asset}“ an %{subject} angehängt" | 121 | asset_attach: "%{actor} hat „%{asset}“ an %{subject} angehängt" |
| 121 | asset_attach_headline: "%{actor} hat „%{asset}“ als Aufmacher an %{subject} angehängt" | 122 | asset_attach_headline: "%{actor} hat „%{asset}“ als Aufmacher an %{subject} angehängt" |
diff --git a/config/locales/en.yml b/config/locales/en.yml index 649c8812..8b4e5db4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml | |||
| @@ -39,7 +39,7 @@ en: | |||
| 39 | heading: "Action log" | 39 | heading: "Action log" |
| 40 | show_all: "Show all entries" | 40 | show_all: "Show all entries" |
| 41 | backfilled: "backfilled" | 41 | backfilled: "backfilled" |
| 42 | show_changes: "translation changes" | 42 | show_changes: "Change details" |
| 43 | view_revision: "view this revision" | 43 | view_revision: "view this revision" |
| 44 | unknown: "%{actor} did %{action} on %{subject}" | 44 | unknown: "%{actor} did %{action} on %{subject}" |
| 45 | publish: "%{actor} published %{revision} of %{subject}" | 45 | publish: "%{actor} published %{revision} of %{subject}" |
| @@ -68,6 +68,7 @@ en: | |||
| 68 | revision_created: "created %{date} by %{actor}" | 68 | revision_created: "created %{date} by %{actor}" |
| 69 | revision_published: "published %{date} by %{actor}" | 69 | revision_published: "published %{date} by %{actor}" |
| 70 | revision_restored: "restored %{date} by %{actor}" | 70 | revision_restored: "restored %{date} by %{actor}" |
| 71 | asset_history: "History" | ||
| 71 | asset_destroy: "%{actor} destroyed asset “%{asset}”" | 72 | asset_destroy: "%{actor} destroyed asset “%{asset}”" |
| 72 | asset_destroy_detached: "— detached from %{paths}" | 73 | asset_destroy_detached: "— detached from %{paths}" |
| 73 | asset_destroy_headlines: "(was the headline of %{paths})" | 74 | asset_destroy_headlines: "(was the headline of %{paths})" |
diff --git a/test/controllers/node_actions_controller_test.rb b/test/controllers/node_actions_controller_test.rb index cfc5a31b..8f0104d3 100644 --- a/test/controllers/node_actions_controller_test.rb +++ b/test/controllers/node_actions_controller_test.rb | |||
| @@ -58,4 +58,19 @@ class NodeActionsControllerTest < ActionController::TestCase | |||
| 58 | assert_response :success | 58 | assert_response :success |
| 59 | assert_includes assigns(:actions).map(&:action), "trash" | 59 | assert_includes assigns(:actions).map(&:action), "trash" |
| 60 | end | 60 | end |
| 61 | |||
| 62 | test "zooming on an asset finds the publishes that changed it" do | ||
| 63 | node = Node.root.children.create!(:slug => "asset_zoom_node") | ||
| 64 | asset = Asset.create!(:name => "Zoomable", :upload_content_type => "image/png") | ||
| 65 | node.publish_draft!(users(:quentin)) | ||
| 66 | node.lock_for_editing!(users(:quentin)) | ||
| 67 | node.create_new_draft(users(:quentin)) | ||
| 68 | node.draft.related_assets.create!(:asset => asset) | ||
| 69 | node.publish_draft!(users(:quentin)) | ||
| 70 | |||
| 71 | get :index, params: { :asset_id => asset.id } | ||
| 72 | assert_response :success | ||
| 73 | assert_equal 1, assigns(:actions).count | ||
| 74 | assert_equal "publish", assigns(:actions).first.action | ||
| 75 | end | ||
| 61 | end | 76 | end |
