summaryrefslogtreecommitdiff
path: root/app/helpers/node_actions_helper.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/helpers/node_actions_helper.rb')
-rw-r--r--app/helpers/node_actions_helper.rb183
1 files changed, 183 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..fd8cc36
--- /dev/null
+++ b/app/helpers/node_actions_helper.rb
@@ -0,0 +1,183 @@
1module NodeActionsHelper
2 include ERB::Util
3
4 # One glyph per verb, rendered before the sentence in _action_row.
5 # Unknown verbs get the dashed circle -- the unknown-verb principle
6 # extended to iconography: the log outlives its vocabulary.
7 VERB_ICONS = {
8 "create" => "file-plus",
9 "publish" => "send",
10 "move" => "arrows-move",
11 "trash" => "trash",
12 "restore_from_trash" => "arrow-back-up",
13 "destroy" => "trash-x",
14 "discard_autosave" => "eraser",
15 "destroy_draft" => "eraser",
16 }.freeze
17
18 def verb_icon action
19 name = if action.action == "publish" && action.metadata["via"] == "revision"
20 "history"
21 else
22 VERB_ICONS.fetch(action.action, "circle-dashed")
23 end
24 content_tag(:span, icon(name, library: "tabler", "aria-hidden": true),
25 :class => "node_action_icon node_action_icon--#{name}",
26 :title => action.action)
27 end
28
29 # One sentence per entry, rendered from metadata alone, so entries
30 # stay renderable after the rows they reference are gone. Live
31 # associations only upgrade plain names to links. Every metadata
32 # value passes through h() here -- this helper is the escaping
33 # boundary; the locale sentences are trusted, the data never is.
34 def action_summary action
35 renderer = "summarize_#{action.action}"
36 return send(renderer, action) if respond_to?(renderer, true)
37
38 # Unknown-verb fallback: the log outlives the vocabulary. A renamed
39 # or future verb degrades to an ugly sentence, never to a 500.
40 t("node_actions.unknown", :actor => actor_ref(action),
41 :action => h(action.action), :subject => subject_ref(action)).html_safe
42 end
43
44
45 def action_details? action
46 m = action.metadata
47 return true if m["translation_diff"].present?
48 return true if m["title"].is_a?(Hash) && m.dig("title", "from") != m.dig("title", "to")
49 %w[author tags template_changed assets_changed
50 abstract_changed body_changed].any? { |key| m[key].present? }
51 end
52
53 # Plain strings by design -- safe_join in the template escapes them.
54 def default_locale_changes action
55 m = action.metadata
56 items = []
57 if m["title"].is_a?(Hash) && m.dig("title", "from") && m.dig("title", "from") != m.dig("title", "to")
58 items << t("node_actions.detail_title",
59 :from => m.dig("title", "from"), :to => m.dig("title", "to"))
60 end
61 items << t("node_actions.detail_author",
62 :from => m.dig("author", "from"), :to => m.dig("author", "to")) if m["author"]
63 items << t("node_actions.detail_tags",
64 :from => Array(m.dig("tags", "from")).join(", "),
65 :to => Array(m.dig("tags", "to")).join(", ")) if m["tags"]
66 items << t("node_actions.abstract_changed") if m["abstract_changed"]
67 items << t("node_actions.body_changed") if m["body_changed"]
68 items << t("node_actions.template_changed") if m["template_changed"]
69 items << t("node_actions.assets_changed") if m["assets_changed"]
70 items
71 end
72
73 def translation_changes diff
74 case diff["status"]
75 when "added" then [t("node_actions.locale_added", :title => diff.dig("title", "to"))]
76 when "removed" then [t("node_actions.locale_removed", :title => diff.dig("title", "from"))]
77 else
78 items = []
79 items << t("node_actions.detail_title",
80 :from => diff.dig("title", "from"), :to => diff.dig("title", "to")) if diff["title"]
81 items << t("node_actions.abstract_changed") if diff["abstract_changed"]
82 items << t("node_actions.body_changed") if diff["body_changed"]
83 items
84 end
85 end
86
87 def revision_lifecycle_badges actions
88 return "" if actions.blank?
89
90 badges = actions.map do |action|
91 key = case action.action
92 when "create" then "node_actions.revision_created"
93 when "publish" then action.metadata["via"] == "revision" ?
94 "node_actions.revision_restored" :
95 "node_actions.revision_published"
96 end
97 next unless key
98
99 badge = h(t(key, :date => action.occurred_at.strftime("%Y-%m-%d"),
100 :actor => action.actor_name))
101 if action.inferred_from
102 badge = safe_join([badge, content_tag(:span, t("node_actions.backfilled"),
103 :class => "node_action_inferred",
104 :title => action.inferred_from)], " ")
105 end
106 badge
107 end.compact
108
109 return "" if badges.empty?
110 safe_join(["— ", safe_join(badges, " · ")])
111 end
112
113 private
114
115 def revision_ref action, key
116 label = t(key)
117 return label unless action.node && action.page
118 link_to(label, node_revision_path(action.node, action.page))
119 end
120
121 def actor_ref action
122 action.user ? link_to(h(action.actor_name), admin_log_path(:user_id => action.user_id))
123 : h(action.actor_name)
124 end
125
126 def subject_ref action
127 action.node ? link_to(h(action.subject_name), node_path(action.node))
128 : h(action.subject_name)
129 end
130
131 def summarize_publish action
132 if action.metadata["via"] == "revision"
133 t("node_actions.publish_rollback",
134 :actor => actor_ref(action), :subject => subject_ref(action),
135 :revision => revision_ref(action, "node_actions.revision_earlier")).html_safe
136 elsif action.metadata.dig("title", "from").nil?
137 author = action.metadata.dig("author", "to")
138 key = author ? "node_actions.publish_first_with_author" : "node_actions.publish_first"
139 t(key, :actor => actor_ref(action), :subject => subject_ref(action),
140 :author => h(author)).html_safe
141 else
142 t("node_actions.publish",
143 :actor => actor_ref(action), :subject => subject_ref(action),
144 :revision => revision_ref(action, "node_actions.revision_new")).html_safe
145 end
146 end
147
148 def summarize_move action
149 t("node_actions.move", :actor => actor_ref(action), :subject => subject_ref(action),
150 :from => h(action.metadata.dig("path", "from")),
151 :to => h(action.metadata.dig("path", "to"))).html_safe
152 end
153
154 def summarize_create action
155 t("node_actions.create", :actor => actor_ref(action), :subject => subject_ref(action),
156 :path => h(action.metadata["path"])).html_safe
157 end
158
159 def summarize_discard_autosave action
160 t("node_actions.discard_autosave",
161 :actor => actor_ref(action), :subject => subject_ref(action)).html_safe
162 end
163
164 def summarize_destroy_draft action
165 t("node_actions.destroy_draft",
166 :actor => actor_ref(action), :subject => subject_ref(action)).html_safe
167 end
168
169 def summarize_trash action
170 t("node_actions.trash", :actor => actor_ref(action), :subject => subject_ref(action),
171 :from => h(action.metadata.dig("path", "from"))).html_safe
172 end
173
174 def summarize_restore_from_trash action
175 t("node_actions.restore_from_trash", :actor => actor_ref(action), :subject => subject_ref(action),
176 :to => h(action.metadata.dig("path", "to"))).html_safe
177 end
178
179 def summarize_destroy action
180 t("node_actions.destroy", :actor => actor_ref(action), :subject => subject_ref(action),
181 :path => h(action.metadata["path"])).html_safe
182 end
183end