summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-08-08 02:46:06 +0200
committererdgeist <erdgeist@erdgeist.org>2026-08-08 02:46:06 +0200
commit1a037ac6fab34c5f65ed0f37ed603b88e7b02fd1 (patch)
tree48af0eab79ea64c9ca92833d415483773e665305 /app
parent5699572861085bfb0b375f44e2f35ee8eee3f8c6 (diff)
Move the external homepage onto the draft
Diffstat (limited to 'app')
-rw-r--r--app/controllers/nodes_controller.rb3
-rw-r--r--app/helpers/node_actions_helper.rb15
-rw-r--r--app/models/node.rb22
-rw-r--r--app/models/node_action.rb6
-rw-r--r--app/models/page.rb4
-rw-r--r--app/views/custom/page_templates/public/chapter_detail.html.erb4
-rw-r--r--app/views/custom/partials/_chapter.html.erb4
-rw-r--r--app/views/nodes/edit.html.erb3
8 files changed, 25 insertions, 36 deletions
diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb
index 3009e25a..ef47f258 100644
--- a/app/controllers/nodes_controller.rb
+++ b/app/controllers/nodes_controller.rb
@@ -281,7 +281,8 @@ class NodesController < ApplicationController
281 281
282 def page_params 282 def page_params
283 params.fetch(:page, {}).permit(:title, :abstract, :body, :template_name, 283 params.fetch(:page, {}).permit(:title, :abstract, :body, :template_name,
284 :published_at, :user_id, :slug, :parent_node_id) 284 :published_at, :user_id, :slug, :parent_node_id,
285 :external_url)
285 end 286 end
286 287
287 def find_node 288 def find_node
diff --git a/app/helpers/node_actions_helper.rb b/app/helpers/node_actions_helper.rb
index 19385543..f21fee61 100644
--- a/app/helpers/node_actions_helper.rb
+++ b/app/helpers/node_actions_helper.rb
@@ -28,8 +28,7 @@ module NodeActionsHelper
28 "admin_revoke" => "shield-minus", 28 "admin_revoke" => "shield-minus",
29 "event_create" => "calendar-plus", 29 "event_create" => "calendar-plus",
30 "event_update" => "calendar-event", 30 "event_update" => "calendar-event",
31 "event_destroy" => "calendar-x", 31 "event_destroy" => "calendar-x"
32 "node_external_url" => "world"
33 }.freeze 32 }.freeze
34 33
35 def verb_icon action 34 def verb_icon action
@@ -67,7 +66,7 @@ module NodeActionsHelper
67 return true if m["title"].is_a?(Hash) && m.dig("title", "from") != m.dig("title", "to") 66 return true if m["title"].is_a?(Hash) && m.dig("title", "from") != m.dig("title", "to")
68 return true if m["external_url"].present? 67 return true if m["external_url"].present?
69 %w[author tags template_changed assets assets_changed assets_reordered 68 %w[author tags template_changed assets assets_changed assets_reordered
70 abstract_changed body_changed].any? { |key| m[key].present? } 69 abstract_changed body_changed external_url].any? { |key| m[key].present? }
71 end 70 end
72 71
73 def default_locale_changes action 72 def default_locale_changes action
@@ -95,6 +94,11 @@ module NodeActionsHelper
95 :names => linked_asset_names(action, names)).html_safe 94 :names => linked_asset_names(action, names)).html_safe
96 end 95 end
97 end 96 end
97 if m["external_url"]
98 items << t("node_actions.detail_external_url",
99 :from => m.dig("external_url", "from").presence || t("node_actions.event_none"),
100 :to => m.dig("external_url", "to").presence || t("node_actions.event_none"))
101 end
98 items << t("node_actions.assets_reordered") if m["assets_reordered"] 102 items << t("node_actions.assets_reordered") if m["assets_reordered"]
99 items << t("node_actions.assets_changed") if m["assets_changed"] 103 items << t("node_actions.assets_changed") if m["assets_changed"]
100 items << t("node_actions.detail_external_url", 104 items << t("node_actions.detail_external_url",
@@ -405,11 +409,6 @@ module NodeActionsHelper
405 event_sentence(action, "event_destroy") 409 event_sentence(action, "event_destroy")
406 end 410 end
407 411
408 def summarize_node_external_url action
409 t("node_actions.node_external_url", :actor => actor_ref(action),
410 :subject => subject_ref(action)).html_safe
411 end
412
413 def event_sentence action, key 412 def event_sentence action, key
414 if action.node 413 if action.node
415 t("node_actions.#{key}_on", :actor => actor_ref(action), 414 t("node_actions.#{key}_on", :actor => actor_ref(action),
diff --git a/app/models/node.rb b/app/models/node.rb
index 5c28a786..f5b76b45 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -42,9 +42,6 @@ class Node < ApplicationRecord
42 :inclusion => { :in => ->(_) { Page.custom_templates } }, 42 :inclusion => { :in => ->(_) { Page.custom_templates } },
43 :allow_blank => true, 43 :allow_blank => true,
44 :if => :default_template_name_changed? 44 :if => :default_template_name_changed?
45 validates :external_url, :format => { :with => %r{\Ahttps?://}i,
46 :allow_blank => true,
47 :message => :must_be_http }
48 45
49 # Everything outside the Trash subtree, the Trash node included. 46 # Everything outside the Trash subtree, the Trash node included.
50 # Relies on unique_name being authoritative for tree position -- 47 # Relies on unique_name being authoritative for tree position --
@@ -260,6 +257,8 @@ class Node < ApplicationRecord
260 self.slug = self.head.slug 257 self.slug = self.head.slug
261 end 258 end
262 259
260 self.external_url = self.head.external_url
261
263 if self.head.parent_node_id && self.head.parent_node_id != parent_id 262 if self.head.parent_node_id && self.head.parent_node_id != parent_id
264 new_parent = Node.find_by(:id => self.head.parent_node_id) 263 new_parent = Node.find_by(:id => self.head.parent_node_id)
265 264
@@ -604,23 +603,6 @@ class Node < ApplicationRecord
604 self.created_at < new_id_format_date ? unique_path : id 603 self.created_at < new_id_format_date ? unique_path : id
605 end 604 end
606 605
607 def update_external_url!(url, current_user = nil)
608 normalised = url.presence
609 return false if normalised == external_url
610
611 guard_live_change!(current_user)
612 previous = external_url
613
614 transaction do
615 update!(:external_url => normalised)
616 NodeAction.record!(:node => self, :user => current_user,
617 :action => "node_external_url",
618 :path => unique_name,
619 :external_url => { "from" => previous, "to" => normalised })
620 end
621 true
622 end
623
624 # Full-text search across all locale translations using PostgreSQL tsvector. 606 # Full-text search across all locale translations using PostgreSQL tsvector.
625 # Uses 'simple' dictionary (no stemming, no stopwords) so queries work 607 # Uses 'simple' dictionary (no stemming, no stopwords) so queries work
626 # across German and English content without language detection. 608 # across German and English content without language detection.
diff --git a/app/models/node_action.rb b/app/models/node_action.rb
index f1e4eaea..1e64861e 100644
--- a/app/models/node_action.rb
+++ b/app/models/node_action.rb
@@ -35,6 +35,7 @@ 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 # "external_url" -- pair, when a chapter's homepage changed
38 # "assets" -- {"added" => [asset names], "removed" => [asset names]}, 39 # "assets" -- {"added" => [asset names], "removed" => [asset names]},
39 # keys only when any; a delta, not a pair. The event IS 40 # keys only when any; a delta, not a pair. The event IS
40 # the delta, full sets would bloat every entry. Changed 41 # the delta, full sets would bloat every entry. Changed
@@ -134,7 +135,6 @@ class NodeAction < ApplicationRecord
134 # from the node verbs' "tags", which is a pair, 135 # from the node verbs' "tags", which is a pair,
135 # so one renderer cannot mistake the other. 136 # so one renderer cannot mistake the other.
136 # "path" -- the node's unique_name, when it has a node 137 # "path" -- the node's unique_name, when it has a node
137 # "external_url" -- pair
138 # 138 #
139 # On "event_update" only, and only when something changed -- an 139 # On "event_update" only, and only when something changed -- an
140 # update that changes nothing records no entry at all: 140 # update that changes nothing records no entry at all:
@@ -199,12 +199,16 @@ class NodeAction < ApplicationRecord
199 "to" => title_of.call(new_page) } } 199 "to" => title_of.call(new_page) } }
200 unless old_page 200 unless old_page
201 diff[:author] = { "from" => nil, "to" => new_page.user&.login } if new_page.user 201 diff[:author] = { "from" => nil, "to" => new_page.user&.login } if new_page.user
202 diff[:external_url] = { "from" => nil, "to" => new_page.external_url } if new_page.external_url.present?
202 return diff 203 return diff
203 end 204 end
204 205
205 old_author, new_author = old_page.user&.login, new_page.user&.login 206 old_author, new_author = old_page.user&.login, new_page.user&.login
206 diff[:author] = { "from" => old_author, "to" => new_author } if old_author != new_author 207 diff[:author] = { "from" => old_author, "to" => new_author } if old_author != new_author
207 208
209 old_url, new_url = old_page.external_url, new_page.external_url
210 diff[:external_url] = { "from" => old_url, "to" => new_url } if old_url != new_url
211
208 old_tags, new_tags = old_page.tag_list.sort, new_page.tag_list.sort 212 old_tags, new_tags = old_page.tag_list.sort, new_page.tag_list.sort
209 diff[:tags] = { "from" => old_tags, "to" => new_tags } if old_tags != new_tags 213 diff[:tags] = { "from" => old_tags, "to" => new_tags } if old_tags != new_tags
210 214
diff --git a/app/models/page.rb b/app/models/page.rb
index bba7e6bc..3240057f 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -20,6 +20,9 @@ class Page < ApplicationRecord
20 :inclusion => { :in => ->(_) { Page.custom_templates } }, 20 :inclusion => { :in => ->(_) { Page.custom_templates } },
21 :allow_blank => true, 21 :allow_blank => true,
22 :if => :template_name_changed? 22 :if => :template_name_changed?
23 validates :external_url, :format => { :with => %r{\Ahttps?://}i,
24 :allow_blank => true,
25 :message => :must_be_http }
23 validates_format_of :slug, :with => /\A[A-Za-z0-9][A-Za-z0-9_-]*\z/, 26 validates_format_of :slug, :with => /\A[A-Za-z0-9][A-Za-z0-9_-]*\z/,
24 :unless => -> { slug.blank? } 27 :unless => -> { slug.blank? }
25 validate :page_slug_not_reserved 28 validate :page_slug_not_reserved
@@ -208,6 +211,7 @@ class Page < ApplicationRecord
208 # Clone untranslated attributes 211 # Clone untranslated attributes
209 self.slug = page.slug 212 self.slug = page.slug
210 self.parent_node_id = page.parent_node_id 213 self.parent_node_id = page.parent_node_id
214 self.external_url = page.external_url
211 self.tag_list = page.tag_list 215 self.tag_list = page.tag_list
212 self.template_name ||= page.template_name 216 self.template_name ||= page.template_name
213 self.published_at = page.published_at 217 self.published_at = page.published_at
diff --git a/app/views/custom/page_templates/public/chapter_detail.html.erb b/app/views/custom/page_templates/public/chapter_detail.html.erb
index 794be823..105ec21a 100644
--- a/app/views/custom/page_templates/public/chapter_detail.html.erb
+++ b/app/views/custom/page_templates/public/chapter_detail.html.erb
@@ -1,8 +1,8 @@
1<div class="article" lang="<%= @page.effective_lang %>"> 1<div class="article" lang="<%= @page.effective_lang %>">
2 <h1 class="headline"><%= @page.title %></h1> 2 <h1 class="headline"><%= @page.title %></h1>
3 <%= headline_image %> 3 <%= headline_image %>
4 <% if @page.node.external_url.present? %> 4 <% if @page.external_url.present? %>
5 <div class="chapter_url"><%= link_to @page.node.external_url, @page.node.external_url, target: '_blank', rel: 'noopener' %></div> 5 <div class="chapter_url"><%= link_to @page.external_url, @page.external_url, target: '_blank', rel: 'noopener' %></div>
6 <% end %> 6 <% end %>
7 <p><%= sanitize(@page.abstract) %></p> 7 <p><%= sanitize(@page.abstract) %></p>
8 <%= aggregate?(@page.body) %> 8 <%= aggregate?(@page.body) %>
diff --git a/app/views/custom/partials/_chapter.html.erb b/app/views/custom/partials/_chapter.html.erb
index 8a92b46f..2065560a 100644
--- a/app/views/custom/partials/_chapter.html.erb
+++ b/app/views/custom/partials/_chapter.html.erb
@@ -7,8 +7,8 @@
7 <% if page.abstract.present? %> 7 <% if page.abstract.present? %>
8 <div class="chapter_location"><%= page.abstract %></div> 8 <div class="chapter_location"><%= page.abstract %></div>
9 <% end %> 9 <% end %>
10 <% if page.node.external_url.present? %> 10 <% if page.external_url.present? %>
11 <div class="chapter_url"><%= link_to page.node.external_url, page.node.external_url, target: '_blank', rel: 'noopener' %></div> 11 <div class="chapter_url"><%= link_to page.external_url, page.external_url, target: '_blank', rel: 'noopener' %></div>
12 <% end %> 12 <% end %>
13 <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %> 13 <% open_days = page.node.events.tagged_with('open-day').order(:start_time) %>
14 <% if open_days.any? %> 14 <% if open_days.any? %>
diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb
index ae206578..6b5a1234 100644
--- a/app/views/nodes/edit.html.erb
+++ b/app/views/nodes/edit.html.erb
@@ -116,8 +116,7 @@
116 116
117 <div class="layout_row_label"><%= t(".external_url") %></div> 117 <div class="layout_row_label"><%= t(".external_url") %></div>
118 <div class="layout_row_content"> 118 <div class="layout_row_content">
119 <%= f.text_field :external_url %> 119 <%= d.text_field :external_url %>
120 <p class="field_hint"><%= t(".external_url_hint") %></p>
121 </div> 120 </div>
122 121
123 <div class="layout_row_label"><%= t(".tags") %></div> 122 <div class="layout_row_label"><%= t(".tags") %></div>