summaryrefslogtreecommitdiff
path: root/app/helpers/node_actions_helper.rb
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-16 03:30:01 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-16 03:30:01 +0200
commit190daaa8a0bb79e750894b83e31b9d99f7d900a4 (patch)
tree308a7bdeba7bd22733729408883e548f851a8812 /app/helpers/node_actions_helper.rb
parentc0c9250141c2fa64fed967b8b9ad9bada3694c3d (diff)
Add a reader for the action log at admin/logHEADmaster
NodeActionsController#index lists entries newest-first, filterable by node_id or user_id -- the two zoom shapes the log was designed around. Rendering goes through NodeActionsHelper.action_summary, which builds one sentence per entry from metadata alone, so entries referencing deleted users or nodes render from their snapshots; live associations only upgrade names to links. Unknown verbs degrade to a generic sentence rather than an error, since the log outlives its vocabulary. The helper is the escaping boundary: every metadata value passes through h() before assembly. Actor names link to the log's own user zoom rather than the unused users page -- inspecting a suspicious user's other actions is the intended workflow. Publish entries with a translation_diff expose a collapsed per-locale change table linking out to the revision itself. Sentences live in en.yml/de.yml following the existing widget-string convention. nodes#show links to its node's zoomed log.
Diffstat (limited to 'app/helpers/node_actions_helper.rb')
-rw-r--r--app/helpers/node_actions_helper.rb68
1 files changed, 68 insertions, 0 deletions
diff --git a/app/helpers/node_actions_helper.rb b/app/helpers/node_actions_helper.rb
new file mode 100644
index 0000000..ef42b75
--- /dev/null
+++ b/app/helpers/node_actions_helper.rb
@@ -0,0 +1,68 @@
1module NodeActionsHelper
2 include ERB::Util
3
4 # One sentence per entry, rendered from metadata alone, so entries
5 # stay renderable after the rows they reference are gone. Live
6 # associations only upgrade plain names to links. Every metadata
7 # value passes through h() here -- this helper is the escaping
8 # boundary; the locale sentences are trusted, the data never is.
9 def action_summary action
10 renderer = "summarize_#{action.action}"
11 return send(renderer, action) if respond_to?(renderer, true)
12
13 # Unknown-verb fallback: the log outlives the vocabulary. A renamed
14 # or future verb degrades to an ugly sentence, never to a 500.
15 t("node_actions.unknown", :actor => actor_ref(action),
16 :action => h(action.action), :subject => subject_ref(action)).html_safe
17 end
18
19 private
20
21 def actor_ref action
22 if action.user && respond_to?(:current_user) && action.user == current_user
23 return t("node_actions.actor_self")
24 end
25 action.user ? link_to(h(action.actor_name), admin_log_path(:user_id => action.user_id))
26 : h(action.actor_name)
27 end
28
29 def subject_ref action
30 action.node ? link_to(h(action.subject_name), node_path(action.node))
31 : h(action.subject_name)
32 end
33
34 def summarize_publish action
35 key = if action.metadata["via"] == "revision"
36 "node_actions.publish_rollback"
37 elsif action.metadata.dig("title", "from").nil?
38 "node_actions.publish_first"
39 else
40 "node_actions.publish"
41 end
42
43 t(key, :actor => actor_ref(action), :subject => subject_ref(action),
44 :from => h(action.metadata.dig("title", "from")),
45 :to => h(action.metadata.dig("title", "to"))).html_safe
46 end
47
48 def summarize_move action
49 t("node_actions.move", :actor => actor_ref(action), :subject => subject_ref(action),
50 :from => h(action.metadata.dig("path", "from")),
51 :to => h(action.metadata.dig("path", "to"))).html_safe
52 end
53
54 def summarize_create action
55 t("node_actions.create", :actor => actor_ref(action), :subject => subject_ref(action),
56 :path => h(action.metadata["path"])).html_safe
57 end
58
59 def summarize_discard_autosave action
60 t("node_actions.discard_autosave",
61 :actor => actor_ref(action), :subject => subject_ref(action)).html_safe
62 end
63
64 def summarize_destroy_draft action
65 t("node_actions.destroy_draft",
66 :actor => actor_ref(action), :subject => subject_ref(action)).html_safe
67 end
68end