diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-09 15:29:40 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-09 15:29:40 +0200 |
| commit | 9c3217df50d462d6be4399e3e654d591bf704df7 (patch) | |
| tree | 627e474b273789667bca9eadffa0e7f626d002bb /app/controllers | |
| parent | 8310751d4db2854597d6379b24e346c65622972d (diff) | |
Fix malformed-HTML fallout across RSS, link rewriting, and flash messaging
Editors' TinyMCE output can contain unclosed void elements like <br>,
which is valid HTML5 but invalid XML -- three different places assumed
the stricter rule and broke or silently misbehaved on the looser one.
The Atom feed's <content type="xhtml"> block required real, well-formed
XML structure but was handed a raw, unescaped body string; switched to
type="html" with CGI.escapeHTML, matching how title/summary already
handle the same content. rewrite_links_in_body used libxml's strict XML
parser to rewrite internal links to be locale-prefixed, which raised on
exactly this class of malformed markup -- silently, since the whole
method was wrapped in rescue; nil, meaning the link rewrite (not the
save) quietly failed with no error anywhere. Replaced with Nokogiri's
lenient HTML parser, which repairs malformed void elements rather than
rejecting them; also drops the bare rescue now that the actual failure
mode it was guarding against shouldn't occur, and fixes two adjacent
bugs found while in this method: a typo'd /sytem/uploads/ regex that
could never match, and a missing https:// exclusion alongside the
existing http:// one.
Also addresses stale flash messaging surfaced while testing the above:
update's save confirmation was being clobbered by edit's own "locked
and ready" notice on the very next request, since nothing distinguished
a fresh lock acquisition from a redirect back after saving. The save
confirmation now names the next step (publish from Status) and flags a
stale translation if one exists, using Page#outdated_translations?,
already present but previously unused by any controller.
Diffstat (limited to 'app/controllers')
| -rw-r--r-- | app/controllers/nodes_controller.rb | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb index 72d4a3e..38d42d9 100644 --- a/app/controllers/nodes_controller.rb +++ b/app/controllers/nodes_controller.rb | |||
| @@ -65,15 +65,16 @@ class NodesController < ApplicationController | |||
| 65 | end | 65 | end |
| 66 | 66 | ||
| 67 | def edit | 67 | def edit |
| 68 | freshly_locked = @node.lock_owner != current_user | ||
| 68 | @node.lock_for_editing!( current_user ) | 69 | @node.lock_for_editing!( current_user ) |
| 69 | @page = @node.autosave || @node.draft || @node.head | 70 | @page = @node.autosave || @node.draft || @node.head |
| 70 | 71 | ||
| 71 | flash.now[:notice] = "Node locked and ready to edit" unless @node.autosave | ||
| 72 | |||
| 73 | if @node.autosave | 72 | if @node.autosave |
| 74 | flash.now[:notice] = | 73 | flash.now[:notice] = |
| 75 | "This page has unsaved changes from a previous session, shown below. " \ | 74 | "This page has unsaved changes from a previous session, shown below. " \ |
| 76 | "Save to keep them, or use \"Discard changes\" below to go back to the last saved version." | 75 | "Save to keep them, or use \"Discard changes\" below to go back to the last saved version." |
| 76 | elsif freshly_locked | ||
| 77 | flash.now[:notice] = "Node locked and ready to edit" | ||
| 77 | end | 78 | end |
| 78 | rescue LockedByAnotherUser => e | 79 | rescue LockedByAnotherUser => e |
| 79 | flash[:error] = e.message | 80 | flash[:error] = e.message |
| @@ -85,7 +86,18 @@ class NodesController < ApplicationController | |||
| 85 | @node.autosave!( page_params.merge(:tag_list => params[:tag_list]), current_user ) | 86 | @node.autosave!( page_params.merge(:tag_list => params[:tag_list]), current_user ) |
| 86 | @node.save_draft!(current_user) | 87 | @node.save_draft!(current_user) |
| 87 | 88 | ||
| 88 | flash[:notice] = "Draft has been saved: #{Time.now}" | 89 | flash[:notice] = "Draft saved. Publish your changes in the Status section once you're done." |
| 90 | flash[:status_path] = node_path(@node) | ||
| 91 | |||
| 92 | if @node.draft.translated_locales.size > 1 | ||
| 93 | stale_locale = @node.draft.translated_locales.find do |locale| | ||
| 94 | @node.draft.outdated_translations?(locale: locale) | ||
| 95 | end | ||
| 96 | if stale_locale | ||
| 97 | flash[:stale_locale] = stale_locale | ||
| 98 | flash[:stale_locale_path] = edit_node_path(@node, locale: stale_locale) | ||
| 99 | end | ||
| 100 | end | ||
| 89 | 101 | ||
| 90 | if params[:commit] == "Save + Unlock + Exit" | 102 | if params[:commit] == "Save + Unlock + Exit" |
| 91 | @node.unlock! | 103 | @node.unlock! |
