wiki pages: use names instead of ids in urls.

Switching to using wiki names in URLs instead of IDs:

* https://danbooru.donami.us/wiki_pages/vocaloid
* https://danbooru.donami.us/wiki_pages/hatsune_miku

ID numbers can still be used, but they redirect to the name instead:

* https://danbooru.donami.us/wiki_pages/11 (redirects to /wiki_pages/touhou).

Numeric tags are prefixed with '~' to distinguish them from IDs:

* https://danbooru.donami.us/wiki_pages/2019 (the wiki with id 2019)
* https://danbooru.donami.us/wiki_pages/~2019 (the wiki for the tag named 2019)

The tag names 'new' and 'search' are disallowed to prevent conflicts
with existing routes:

* https://danbooru.donami.us/wiki_pages/new
* https://danbooru.donami.us/wiki_pages/search
This commit is contained in:
evazion
2019-10-31 04:07:21 -05:00
parent 0ccfb3f5f6
commit 3a908f84bb
14 changed files with 76 additions and 38 deletions

View File

@@ -11,7 +11,7 @@ class WikiPagesController < ApplicationController
end
def edit
@wiki_page = WikiPage.find(params[:id])
@wiki_page, _ = WikiPage.find_by_id_or_title(params[:id])
respond_with(@wiki_page)
end
@@ -30,18 +30,16 @@ class WikiPagesController < ApplicationController
end
def show
if params[:id] =~ /\A\d+\z/
@wiki_page = WikiPage.find(params[:id])
else
@wiki_page = WikiPage.titled(params[:id]).first
end
@wiki_page, found_by = WikiPage.find_by_id_or_title(params[:id])
if @wiki_page.present?
respond_with(@wiki_page)
elsif request.format.html?
if request.format.html? && @wiki_page.blank? && found_by == :title
redirect_to show_or_new_wiki_pages_path(title: params[:id])
else
elsif request.format.html? && @wiki_page.present? && found_by == :id
redirect_to @wiki_page
elsif @wiki_page.blank?
raise ActiveRecord::RecordNotFound
else
respond_with(@wiki_page)
end
end
@@ -51,19 +49,19 @@ class WikiPagesController < ApplicationController
end
def update
@wiki_page = WikiPage.find(params[:id])
@wiki_page, _ = WikiPage.find_by_id_or_title(params[:id])
@wiki_page.update(wiki_page_params(:update))
respond_with(@wiki_page)
end
def destroy
@wiki_page = WikiPage.find(params[:id])
@wiki_page, _ = WikiPage.find_by_id_or_title(params[:id])
@wiki_page.update(is_deleted: true)
respond_with(@wiki_page)
end
def revert
@wiki_page = WikiPage.find(params[:id])
@wiki_page, _ = WikiPage.find_by_id_or_title(params[:id])
@version = @wiki_page.versions.find(params[:version_id])
@wiki_page.revert_to!(@version)
flash[:notice] = "Page was reverted"

View File

@@ -103,13 +103,14 @@ module ApplicationHelper
link_to search, posts_path(tags: search)
end
def link_to_wiki(text, title)
link_to text, wiki_page_path(title)
def link_to_wiki(text, title = text, **options)
title = "~#{title}" if title =~ /\A\d+\z/
link_to text, wiki_page_path(title), class: "wiki-link", **options
end
def link_to_wikis(*wiki_titles, last_word_connector: ", or", **options)
links = wiki_titles.map do |title|
link_to title.tr("_", " "), wiki_page_path(title)
link_to_wiki title.tr("_", " "), title
end
to_sentence(links, **options)

View File

@@ -6,32 +6,32 @@ module TagsHelper
if tag.antecedent_alias
html << "<p class='fineprint'>This tag has been aliased to "
html << link_to(tag.antecedent_alias.consequent_name, show_or_new_wiki_pages_path(:title => tag.antecedent_alias.consequent_name))
html << link_to_wiki(tag.antecedent_alias.consequent_name)
html << " (#{link_to_wiki "learn more", "help:tag_aliases"}).</p>"
end
if tag.consequent_aliases.present?
html << "<p class='fineprint'>The following tags are aliased to this tag: "
html << raw(tag.consequent_aliases.map {|x| link_to(x.antecedent_name, show_or_new_wiki_pages_path(:title => x.antecedent_name))}.join(", "))
html << raw(tag.consequent_aliases.map {|x| link_to_wiki x.antecedent_name }.join(", "))
html << " (#{link_to_wiki "learn more", "help:tag_aliases"}).</p>"
end
automatic_tags = TagImplication.automatic_tags_for([tag.name])
if automatic_tags.present?
html << "<p class='fineprint'>This tag automatically adds "
html << raw(automatic_tags.map {|x| link_to(x, show_or_new_wiki_pages_path(:title => x))}.join(", "))
html << raw(automatic_tags.map {|x| link_to_wiki x, x }.join(", "))
html << " (#{link_to_wiki "learn more", "help:autotags"}).</p>"
end
if tag.antecedent_implications.present?
html << "<p class='fineprint'>This tag implicates "
html << raw(tag.antecedent_implications.map {|x| link_to(x.consequent_name, show_or_new_wiki_pages_path(:title => x.consequent_name))}.join(", "))
html << raw(tag.antecedent_implications.map {|x| link_to_wiki x.consequent_name }.join(", "))
html << " (#{link_to_wiki "learn more", "help:tag_implications"}).</p>"
end
if tag.consequent_implications.present?
html << "<p class='fineprint'>The following tags implicate this tag: "
html << raw(tag.consequent_implications.map {|x| link_to(x.antecedent_name, show_or_new_wiki_pages_path(:title => x.antecedent_name))}.join(", "))
html << raw(tag.consequent_implications.map {|x| link_to_wiki x.antecedent_name }.join(", "))
html << " (#{link_to_wiki "learn more", "help:tag_implications"}).</p>"
end

View File

@@ -22,10 +22,6 @@ a.active {
font-weight: bold;
}
a.wiki-link {
margin-right: 0.3em;
}
a[rel*="external"] {
word-break: break-all;
}

View File

@@ -275,6 +275,10 @@ div#c-posts {
aside#sidebar > section > ul {
margin-bottom: 1em;
a.wiki-link {
margin-right: 0.3em;
}
}
aside#sidebar > section > ul ul li {

View File

@@ -25,6 +25,8 @@ class TagNameValidator < ActiveModel::EachValidator
record.errors[attribute] << "'#{value}' cannot begin with '#{$1}:'"
when /\A(#{Tag.categories.regexp}):(.+)\z/i
record.errors[attribute] << "'#{value}' cannot begin with '#{$1}:'"
when "new", "search"
record.errors[attribute] << "'#{value}' is a reserved name and cannot be used"
when /\A(.+)_\(cosplay\)\z/i
tag_name = TagAlias.to_aliased([$1]).first
tag = Tag.find_by_name(tag_name)

View File

@@ -23,6 +23,14 @@ class WikiPage < ApplicationRecord
api_attributes including: [:category_name]
module SearchMethods
def find_by_id_or_title(id)
if id =~ /\A\d+\z/
[find_by_id(id), :id]
else
[find_by_title(normalize_title(id)), :title]
end
end
def titled(title)
where(title: normalize_title(title))
end
@@ -138,7 +146,7 @@ class WikiPage < ApplicationRecord
end
def self.normalize_title(title)
title.downcase.gsub(/[[:space:]]+/, "_").gsub(/__/, "_").gsub(/\A_|_\z/, "")
title.downcase.delete_prefix("~").gsub(/[[:space:]]+/, "_").gsub(/__/, "_").gsub(/\A_|_\z/, "")
end
def normalize_title
@@ -235,4 +243,12 @@ class WikiPage < ApplicationRecord
def visible?
artist.blank? || !artist.is_banned? || CurrentUser.is_builder?
end
def to_param
if title =~ /\A\d+\z/
"~#{title}"
else
title
end
end
end

View File

@@ -113,8 +113,10 @@ class TagSetPresenter < Presenter
unless name_only
if category == Tag.categories.artist
html << %{<a class="wiki-link" href="/artists/show_or_new?name=#{u(name)}">?</a> }
elsif name =~ /\A\d+\z/
html << %{<a class="wiki-link" href="/wiki_pages/~#{u(name)}">?</a> }
else
html << %{<a class="wiki-link" href="/wiki_pages/show_or_new?title=#{u(name)}">?</a> }
html << %{<a class="wiki-link" href="/wiki_pages/#{u(name)}">?</a> }
end
if show_extra_links && current_query.present?

View File

@@ -35,7 +35,7 @@
<% if dtext_link.external_link? %>
<%= external_link_to(dtext_link.link_target) %>
<% elsif dtext_link.wiki_link? %>
<%= link_to(dtext_link.link_target, show_or_new_wiki_pages_path(title: dtext_link.link_target), class: "tag-type-#{Tag.category_for(dtext_link.link_target)}") %>
<%= link_to_wiki dtext_link.link_target, class: "tag-type-#{Tag.category_for(dtext_link.link_target)}" %>
<% end %>
<%= link_to("»", dtext_links_path(search: { link_target: dtext_link.link_target })) %>

View File

@@ -1,10 +1,10 @@
<div class="current-related-tags-columns">
<% if related_tags.present? %>
<%= render "related_tags/tag_column", tags: related_tags.tags, class: "general-related-tags-column", title: related_tags.pretty_name %>
<%= render "related_tags/tag_column", tags: related_tags.wiki_page_tags, class: "wiki-related-tags-column", title: link_to("wiki:#{related_tags.pretty_name}", show_or_new_wiki_pages_path(title: related_tags.query)) %>
<%= render "related_tags/tag_column", tags: related_tags.wiki_page_tags, class: "wiki-related-tags-column", title: link_to_wiki("wiki:#{related_tags.pretty_name}", related_tags.query) %>
<% related_tags.other_wiki_pages.each do |wiki| %>
<%= render "related_tags/tag_column", tags: wiki.tags, class: "other-wiki-related-tags-column", title: link_to("wiki:#{wiki.pretty_title}", show_or_new_wiki_pages_path(title: wiki.title)) %>
<%= render "related_tags/tag_column", tags: wiki.tags, class: "other-wiki-related-tags-column", title: link_to_wiki("wiki:#{wiki.pretty_title}", wiki.title) %>
<% end %>
<% end %>
</div>

View File

@@ -20,7 +20,7 @@
<% @query.tags_for_html.each do |tag, category| %>
<tr>
<td class="category-<%= category %>">
<%= link_to("?", show_or_new_wiki_pages_path(:title => tag)) %>
<%= link_to_wiki "?", tag %>
<%= link_to(tag, posts_path(:tags => tag)) %>
</td>
</tr>

View File

@@ -14,7 +14,7 @@
<tr>
<td><%= tag.post_count %></td>
<td class="category-<%= tag.category %> col-expand">
<%= link_to("?", show_or_new_wiki_pages_path(:title => tag.name)) %>
<%= link_to_wiki "?", tag.name %>
<%= link_to(tag.name, posts_path(:tags => tag.name)) %>
</td>
<td>

View File

@@ -40,13 +40,29 @@ class WikiPagesControllerTest < ActionDispatch::IntegrationTest
end
end
should "render" do
get wiki_page_path(@wiki_page)
should "redirect to the title for an id" do
get wiki_page_path(@wiki_page.id)
assert_redirected_to wiki_page_path(@wiki_page.title)
get wiki_page_path(@wiki_page.id), as: :json
assert_response :success
end
should "distinguish between an id and a title" do
as(@user) { @wiki_page.update(title: "2019") }
get wiki_page_path("~2019")
assert_response :success
get wiki_page_path(@wiki_page.id)
assert_redirected_to wiki_page_path("~2019")
get wiki_page_path("2019")
assert_response 404
end
should "render for a title" do
get wiki_page_path(:id => @wiki_page.title)
get wiki_page_path(@wiki_page.title)
assert_response :success
end
@@ -64,8 +80,9 @@ class WikiPagesControllerTest < ActionDispatch::IntegrationTest
as_user do
@wiki_page.update(title: "-aaa")
end
get wiki_page_path(:id => @wiki_page.id)
assert_response :success
get wiki_page_path(@wiki_page.id)
assert_redirected_to wiki_page_path(@wiki_page.title)
end
end

View File

@@ -695,7 +695,7 @@ class PostTest < ActiveSupport::TestCase
context "that already exists" do
setup do
%W(___ ~foo _foo foo_ foo__bar foo*bar foo,bar foo\abar café 東方).each do |tag|
%W(___ ~foo _foo foo_ foo__bar foo*bar foo,bar foo\abar café 東方 new search).each do |tag|
build(:tag, name: tag).save(validate: false)
end
end
@@ -710,6 +710,8 @@ class PostTest < ActiveSupport::TestCase
assert_invalid_tag("foo\abar")
assert_invalid_tag("café")
assert_invalid_tag("東方")
assert_invalid_tag("new")
assert_invalid_tag("search")
end
end