From ba5b6b0fff0ae77fe28fb0fcd3ea77ff7ac651bd Mon Sep 17 00:00:00 2001 From: Cinder Date: Fri, 26 Jul 2024 12:43:45 -0700 Subject: [PATCH] [WikiPages] Implement basic redirects (#683) --- app/controllers/wiki_pages_controller.rb | 4 ++ app/javascript/src/styles/base.scss | 1 + .../src/styles/specific/wiki_pages.scss | 20 +++++++++ app/models/wiki_page.rb | 42 ++++++++++++++----- app/views/wiki_page_versions/diff.html.erb | 8 ++++ app/views/wiki_page_versions/show.html.erb | 4 ++ app/views/wiki_pages/_form.html.erb | 2 + app/views/wiki_pages/_search.html.erb | 1 + app/views/wiki_pages/show.html.erb | 24 ++++++----- ...0240726170041_add_wiki_page_parent_name.rb | 8 ++++ db/structure.sql | 7 +++- 11 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 app/javascript/src/styles/specific/wiki_pages.scss create mode 100644 db/migrate/20240726170041_add_wiki_page_parent_name.rb diff --git a/app/controllers/wiki_pages_controller.rb b/app/controllers/wiki_pages_controller.rb index 84b18f2c6..80bc8db6f 100644 --- a/app/controllers/wiki_pages_controller.rb +++ b/app/controllers/wiki_pages_controller.rb @@ -55,6 +55,9 @@ class WikiPagesController < ApplicationController end if @wiki_page.present? + if @wiki_page.parent.present? + @wiki_redirect = WikiPage.titled(@wiki_page.parent) + end respond_with(@wiki_page) elsif request.format.html? redirect_to show_or_new_wiki_pages_path(title: params[:id]) @@ -121,6 +124,7 @@ class WikiPagesController < ApplicationController def wiki_page_params(context) permitted_params = %i[body skip_secondary_validations edit_reason] + permitted_params += %i[parent] if CurrentUser.is_privileged? permitted_params += %i[is_locked is_deleted] if CurrentUser.is_janitor? permitted_params += %i[title] if context == :create || CurrentUser.is_janitor? diff --git a/app/javascript/src/styles/base.scss b/app/javascript/src/styles/base.scss index 74b652581..8d116788d 100644 --- a/app/javascript/src/styles/base.scss +++ b/app/javascript/src/styles/base.scss @@ -77,6 +77,7 @@ @import "specific/user_feedback.scss"; @import "specific/user_warned.scss"; @import "specific/users.scss"; +@import "specific/wiki_pages.scss"; @import "specific/wiki_page_versions.scss"; @import "common/z_responsive.scss"; diff --git a/app/javascript/src/styles/specific/wiki_pages.scss b/app/javascript/src/styles/specific/wiki_pages.scss new file mode 100644 index 000000000..2b5e1bd40 --- /dev/null +++ b/app/javascript/src/styles/specific/wiki_pages.scss @@ -0,0 +1,20 @@ +#c-wiki-pages #a-show, +#c-wiki-page-versions { + .wiki-page-redirect { + margin-left: 1em; + color: var(--color-text-muted); + & > i { + display: inline-flex; + margin-right: 0.25em; + } + } + + .wiki-redirect-history { + color: var(--color-text-muted); + margin-bottom: 1em; + } + + #wiki-page-body { + margin-top: 0.25em; + } +} diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index c1d0afecf..6099ac742 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -5,15 +5,17 @@ class WikiPage < ApplicationRecord before_validation :normalize_title before_validation :normalize_other_names + before_validation :normalize_parent after_save :create_version validates :title, uniqueness: { :case_sensitive => false } validates :title, presence: true validates :title, tag_name: true, if: :title_changed? - validates :body, presence: { :unless => -> { is_deleted? || other_names.present? } } + validates :body, presence: { unless: -> { is_deleted? || other_names.present? || parent.present? } } validates :title, length: { minimum: 1, maximum: 100 } validates :body, length: { maximum: Danbooru.config.wiki_page_max_size } validate :user_not_limited validate :validate_rename + validate :validate_redirect validate :validate_not_locked before_destroy :validate_not_used_as_help_page @@ -94,6 +96,8 @@ class WikiPage < ApplicationRecord q = q.where("is_deleted = false") end + q = q.attribute_matches(:parent, params[:parent].try(:tr, " ", "_")) + if params[:other_names_present].to_s.truthy? q = q.where("other_names is not null and other_names != '{}'") elsif params[:other_names_present].to_s.falsy? @@ -169,6 +173,18 @@ class WikiPage < ApplicationRecord end end + def validate_redirect + return unless will_save_change_to_parent? && parent.present? + if WikiPage.find_by(title: parent).blank? + errors.add(:parent, "does not exist") + return + end + + if HelpPage.find_by(wiki_page: title).present? + errors.add(:title, "is used as a help page and cannot be redirected") + end + end + def revert_to(version) if id != version.wiki_page_id raise RevertError.new("You cannot revert to a previous version of another wiki page.") @@ -176,6 +192,7 @@ class WikiPage < ApplicationRecord self.title = version.title self.body = version.body + self.parent = version.parent self.other_names = version.other_names end @@ -192,6 +209,10 @@ class WikiPage < ApplicationRecord self.other_names = other_names.map { |name| WikiPage.normalize_other_name(name) }.uniq end + def normalize_parent + self.parent = nil if parent == "" + end + def self.normalize_other_name(name) name.unicode_normalize(:nfkc).gsub(/[[:space:]]+/, " ").strip.tr(" ", "_") end @@ -214,19 +235,20 @@ class WikiPage < ApplicationRecord end def wiki_page_changed? - saved_change_to_title? || saved_change_to_body? || saved_change_to_is_locked? || saved_change_to_is_deleted? || saved_change_to_other_names? + saved_change_to_title? || saved_change_to_body? || saved_change_to_is_locked? || saved_change_to_is_deleted? || saved_change_to_other_names? || saved_change_to_parent? end def create_new_version versions.create( - :updater_id => CurrentUser.user.id, - :updater_ip_addr => CurrentUser.ip_addr, - :title => title, - :body => body, - :is_locked => is_locked, - :is_deleted => is_deleted, - :other_names => other_names, - reason: edit_reason + updater_id: CurrentUser.user.id, + updater_ip_addr: CurrentUser.ip_addr, + title: title, + body: body, + is_locked: is_locked, + is_deleted: is_deleted, + other_names: other_names, + parent: parent, + reason: edit_reason, ) end diff --git a/app/views/wiki_page_versions/diff.html.erb b/app/views/wiki_page_versions/diff.html.erb index e33515362..0d739e392 100644 --- a/app/views/wiki_page_versions/diff.html.erb +++ b/app/views/wiki_page_versions/diff.html.erb @@ -5,6 +5,14 @@ <% if @thispage.visible? %>

Showing differences between <%= compact_time @thispage.updated_at %> (<%= link_to_user @thispage.updater %>) and <%= compact_time @otherpage.updated_at %> (<%= link_to_user @otherpage.updater %>)

+ <% if @thispage.parent != @otherpage.parent %> +
+ Page redirect changed + from <%= @thispage.parent.blank? ? "none" : link_to(@thispage.parent, show_or_new_wiki_pages_path(title: @thispage.parent)) %> + to <%= @otherpage.parent.blank? ? "none" : link_to(@otherpage.parent, show_or_new_wiki_pages_path(title: @otherpage.parent)) %>. +
+ <% end %> +
<%= text_diff(@thispage.body, @otherpage.body) %>
diff --git a/app/views/wiki_page_versions/show.html.erb b/app/views/wiki_page_versions/show.html.erb index 93eff4753..3e5553358 100644 --- a/app/views/wiki_page_versions/show.html.erb +++ b/app/views/wiki_page_versions/show.html.erb @@ -5,6 +5,10 @@

<%= @wiki_page_version.pretty_title %> (<%= time_ago_in_words_tagged(@wiki_page_version.updated_at) %>)

+ <% if @wiki_page_version.parent.present? %> +
Redirects to <%= link_to @wiki_page_version.parent, show_or_new_wiki_pages_path(title: @wiki_page_version.parent) %>
+ <% end %> +
<% if @wiki_page_version.visible? %> <%= format_text(@wiki_page_version.body) %> diff --git a/app/views/wiki_pages/_form.html.erb b/app/views/wiki_pages/_form.html.erb index b097111fb..4c6cb743d 100644 --- a/app/views/wiki_pages/_form.html.erb +++ b/app/views/wiki_pages/_form.html.erb @@ -12,6 +12,8 @@ <%= f.input :body, as: :dtext, limit: Danbooru.config.wiki_page_max_size, allow_color: true %> + <%= f.input :parent, label: "Redirects to", autocomplete: "wiki-page", input_html: { disabled: !CurrentUser.is_privileged? } %> + <% if CurrentUser.is_janitor? && @wiki_page.is_deleted? %> <%= f.input :is_deleted, :label => "Deleted", :hint => "Uncheck to restore this wiki page" %> <% end %> diff --git a/app/views/wiki_pages/_search.html.erb b/app/views/wiki_pages/_search.html.erb index 661a62838..623634ae6 100644 --- a/app/views/wiki_pages/_search.html.erb +++ b/app/views/wiki_pages/_search.html.erb @@ -2,6 +2,7 @@ <%= f.input :title, label: "Title", hint: "Use * for wildcard searches", autocomplete: "wiki-page" %> <%= f.input :body_matches, label: "Body" %> <%= f.user :creator %> + <%= f.input :parent, label: "Redirects to", autocomplete: "wiki-page" %> <%= f.input :other_names_match, label: "Other names", hint: "Use * for wildcard searches" %> <%= f.input :other_names_present, collection: %w[Yes No], include_blank: true %> <%= f.input :hide_deleted, collection: %w[Yes No] %> diff --git a/app/views/wiki_pages/show.html.erb b/app/views/wiki_pages/show.html.erb index 117de2e74..389451b0f 100644 --- a/app/views/wiki_pages/show.html.erb +++ b/app/views/wiki_pages/show.html.erb @@ -1,3 +1,4 @@ +<% wiki_content = @wiki_redirect.presence || @wiki_page %>
<%= render "sidebar" %> @@ -5,38 +6,41 @@

- <%= link_to @wiki_page.pretty_title_with_category, posts_path(:tags => @wiki_page.title), :class => "tag-type-#{@wiki_page.category_id}" %> + <%= link_to wiki_content.pretty_title_with_category, posts_path(:tags => wiki_content.title), :class => "tag-type-#{wiki_content.category_id}" %> - <% if @wiki_page.is_locked? %> + <% if wiki_content.is_locked? %> (locked) <% end %> - <% if @wiki_page.is_deleted? %> + <% if wiki_content.is_deleted? %> (deleted) <% end %>

+ <% if @wiki_redirect.present? %> +
<%= @wiki_page.title %>
+ <% end %>
- <% if @wiki_page.visible? %> - <%= format_text(@wiki_page.body, allow_color: true, max_thumbs: 75) %> + <% if wiki_content.visible? %> + <%= format_text(wiki_content.body, allow_color: true, max_thumbs: 75) %> - <% if @wiki_page.artist %> -

<%= link_to "View artist", @wiki_page.artist %>

+ <% if wiki_content.artist %> +

<%= link_to "View artist", wiki_content.artist %>

<% end %> - <%= wiki_page_alias_and_implication_list(@wiki_page) %> + <%= wiki_page_alias_and_implication_list(wiki_content) %> <% else %>

This artist has requested removal of their information.

<% end %>
- <%= wiki_page_post_previews(@wiki_page) %> + <%= wiki_page_post_previews(wiki_content) %>
<% content_for(:page_title) do %> - Wiki - <%= @wiki_page.pretty_title %> + Wiki - <%= wiki_content.pretty_title %> <% end %> <%= render "secondary_links" %> diff --git a/db/migrate/20240726170041_add_wiki_page_parent_name.rb b/db/migrate/20240726170041_add_wiki_page_parent_name.rb new file mode 100644 index 000000000..17c92218b --- /dev/null +++ b/db/migrate/20240726170041_add_wiki_page_parent_name.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class AddWikiPageParentName < ActiveRecord::Migration[7.0] + def change + add_column :wiki_pages, :parent, :string + add_column :wiki_page_versions, :parent, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index bc9175fca..87cb2f052 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2316,7 +2316,8 @@ CREATE TABLE public.wiki_page_versions ( updated_at timestamp without time zone NOT NULL, other_names text[] DEFAULT '{}'::text[] NOT NULL, is_deleted boolean DEFAULT false NOT NULL, - reason character varying + reason character varying, + parent character varying ); @@ -2354,7 +2355,8 @@ CREATE TABLE public.wiki_pages ( updated_at timestamp without time zone NOT NULL, updater_id integer, other_names text[] DEFAULT '{}'::text[] NOT NULL, - is_deleted boolean DEFAULT false NOT NULL + is_deleted boolean DEFAULT false NOT NULL, + parent character varying ); @@ -4496,6 +4498,7 @@ ALTER TABLE ONLY public.favorites SET search_path TO "$user", public; INSERT INTO "schema_migrations" (version) VALUES +('20240726170041'), ('20240709134926'), ('20240706061122'), ('20240101042716'),