diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/controllers/nodes_controller.rb | 3 | ||||
| -rw-r--r-- | app/helpers/node_actions_helper.rb | 15 | ||||
| -rw-r--r-- | app/models/node.rb | 22 | ||||
| -rw-r--r-- | app/models/node_action.rb | 6 | ||||
| -rw-r--r-- | app/models/page.rb | 4 | ||||
| -rw-r--r-- | app/views/custom/page_templates/public/chapter_detail.html.erb | 4 | ||||
| -rw-r--r-- | app/views/custom/partials/_chapter.html.erb | 4 | ||||
| -rw-r--r-- | app/views/nodes/edit.html.erb | 3 |
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> |
