Fixes bug described in d3e4ac7c17 (commitcomment-39049351)
When dealing with searches, there are several variables we have to keep
in mind:
* Whether tag aliases should be applied.
* Whether search terms should be sorted.
* Whether the rating:s and -status:deleted metatags should be added by
safe mode and the hide deleted posts setting.
Which of these things we need to do depends on the context:
* We want to apply aliases when actually doing the search, calculating
the count, looking up the wiki excerpt, recording missed/popular
searches in Reportbooru, and calculating related tags for the sidebar,
but not when displaying the raw search as typed by the user (for
example, in the page title or in the tag search box).
* We want to sort the search when calculating cache keys for fast_count
or related tags, and when recording missed/popular searches, but not
in the page title or when displaying the raw search.
* We want to add rating:s and -status:deleted when performing the
search, calculating the count, or recording missed/popular searches,
but not when calculating related tags for the sidebar, or when
displaying the page title or raw search.
Here we introduce normalized_query and try to use it in contexts where
query normalization is necessary. When to use the normalized query
versus the raw unnormalized query is still subtle and prone to error.
586 lines
20 KiB
Ruby
586 lines
20 KiB
Ruby
require "test_helper"
|
|
|
|
class PostsControllerTest < ActionDispatch::IntegrationTest
|
|
context "The posts controller" do
|
|
setup do
|
|
PopularSearchService.stubs(:enabled?).returns(false)
|
|
|
|
@user = travel_to(1.month.ago) {create(:user)}
|
|
as_user do
|
|
@post = create(:post, :tag_string => "aaaa")
|
|
end
|
|
end
|
|
|
|
context "index action" do
|
|
should "render" do
|
|
get posts_path
|
|
assert_response :success
|
|
end
|
|
|
|
context "with a single tag search" do
|
|
should "render for an empty tag" do
|
|
get posts_path, params: { tags: "does_not_exist" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 0
|
|
end
|
|
|
|
should "render for an artist tag" do
|
|
create(:post, tag_string: "artist:bkub", rating: "s")
|
|
get posts_path, params: { tags: "bkub" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
|
|
artist = create(:artist, name: "bkub")
|
|
get posts_path, params: { tags: "bkub" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Artist"
|
|
|
|
artist.update(is_banned: true)
|
|
get posts_path, params: { tags: "bkub" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Artist"
|
|
|
|
artist.update(is_banned: false, is_deleted: true)
|
|
get posts_path, params: { tags: "bkub" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
|
|
as_user { create(:wiki_page, title: "bkub") }
|
|
get posts_path, params: { tags: "bkub" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
end
|
|
|
|
should "render for a tag with a wiki page" do
|
|
create(:post, tag_string: "char:fumimi", rating: "s")
|
|
get posts_path, params: { tags: "fumimi" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
|
|
as_user { @wiki = create(:wiki_page, title: "fumimi") }
|
|
get posts_path, params: { tags: "fumimi" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
|
|
as_user { @wiki.update(is_deleted: true) }
|
|
get posts_path, params: { tags: "bkub" }
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 0
|
|
end
|
|
|
|
should "render for an aliased tag" do
|
|
create(:tag_alias, antecedent_name: "/lav", consequent_name: "looking_at_viewer")
|
|
as(@user) { create(:wiki_page, title: "looking_at_viewer") }
|
|
@post = create(:post, tag_string: "looking_at_viewer", rating: "s")
|
|
|
|
get posts_path, params: { tags: "/lav" }
|
|
assert_response :success
|
|
assert_select "#post_#{@post.id}", count: 1
|
|
assert_select "#excerpt .wiki-link[href='/wiki_pages/looking_at_viewer']", count: 1
|
|
end
|
|
|
|
should "render for a wildcard tag search" do
|
|
create(:post, tag_string: "1girl solo")
|
|
get posts_path(tags: "*girl*")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 0
|
|
end
|
|
|
|
should "render for a search:all search" do
|
|
create(:saved_search, user: @user)
|
|
get posts_path(tags: "search:all")
|
|
assert_response :success
|
|
end
|
|
|
|
should "show a notice for a single tag search with a pending BUR" do
|
|
create(:bulk_update_request, script: "create alias foo -> bar")
|
|
get_auth posts_path(tags: "foo"), @user
|
|
assert_select ".tag-change-notice"
|
|
end
|
|
end
|
|
|
|
context "with a multi-tag search" do
|
|
should "render" do
|
|
as(create(:user)) do
|
|
create(:post, tag_string: "1girl solo", rating: "s")
|
|
create(:wiki_page, title: "1girl")
|
|
end
|
|
|
|
get posts_path, params: {:tags => "1girl solo"}
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 0
|
|
end
|
|
|
|
should "show the wiki excerpt if the search has a tag with a wiki" do
|
|
as(@user) { create(:wiki_page, title: "1girl") }
|
|
create(:post, tag_string: "1girl rating:s")
|
|
get posts_path, params: { tags: "1girl rating:s" }
|
|
|
|
assert_response :success
|
|
assert_select "li.wiki-excerpt-link", count: 1
|
|
end
|
|
|
|
should "show the blank wiki excerpt if the search has tag without a wiki" do
|
|
create(:post, tag_string: "1girl rating:s")
|
|
get posts_path, params: { tags: "1girl rating:s" }
|
|
|
|
assert_response :success
|
|
assert_select "li.blank-wiki-excerpt-link", count: 1
|
|
end
|
|
|
|
should "render an error when searching for too many tags" do
|
|
get posts_path, params: { tags: "1 2 3" }
|
|
|
|
assert_response 422
|
|
assert_select "h1", "Search Error"
|
|
end
|
|
|
|
should "render an error when exceeding the page limit" do
|
|
get posts_path, params: { page: 1001 }
|
|
|
|
assert_response 410
|
|
assert_select "h1", "Search Error"
|
|
end
|
|
end
|
|
|
|
context "with a pool: search" do
|
|
setup do
|
|
CurrentUser.user = create(:user)
|
|
CurrentUser.ip_addr = "127.0.0.1"
|
|
end
|
|
|
|
teardown do
|
|
CurrentUser.user = nil
|
|
CurrentUser.ip_addr = nil
|
|
end
|
|
|
|
should "render for a pool: search" do
|
|
pool1 = create(:pool)
|
|
pool2 = create(:pool)
|
|
create(:post, tag_string: "solo pool:#{pool1.id}", rating: "s")
|
|
create(:wiki_page, title: "solo")
|
|
|
|
get posts_path(tags: "pool:#{pool1.id}")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Pool"
|
|
|
|
get posts_path(tags: "pool:#{pool1.id} rating:s")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Pool"
|
|
|
|
get posts_path(tags: "pool:#{pool1.id} solo")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
|
|
get posts_path(tags: "pool:#{pool1.id} -pool:#{pool2.id}")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 0
|
|
end
|
|
end
|
|
|
|
context "with a favgroup: search" do
|
|
setup do
|
|
CurrentUser.user = create(:user)
|
|
CurrentUser.ip_addr = "127.0.0.1"
|
|
end
|
|
|
|
teardown do
|
|
CurrentUser.user = nil
|
|
CurrentUser.ip_addr = nil
|
|
end
|
|
|
|
should "render for a favgroup: search" do
|
|
wiki = create(:wiki_page, title: "solo")
|
|
post1 = create(:post, tag_string: "solo", rating: "s")
|
|
favgroup1 = create(:favorite_group, post_ids: [post1.id])
|
|
favgroup2 = create(:favorite_group)
|
|
|
|
get posts_path(tags: "favgroup:#{favgroup1.id}")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Favorite Group"
|
|
|
|
get posts_path(tags: "favgroup:#{favgroup1.id} rating:s")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Favorite Group"
|
|
|
|
get posts_path(tags: "favgroup:#{favgroup1.id} solo")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 1, text: "Wiki"
|
|
|
|
get posts_path(tags: "favgroup:#{favgroup1.id} -favgroup:#{favgroup2.id}")
|
|
assert_response :success
|
|
assert_select "#show-excerpt-link", count: 0
|
|
end
|
|
end
|
|
|
|
context "with an md5 param" do
|
|
should "render" do
|
|
get posts_path, params: { md5: @post.md5 }
|
|
assert_redirected_to(@post)
|
|
end
|
|
|
|
should "return error on nonexistent md5" do
|
|
get posts_path(md5: "foo")
|
|
assert_response 404
|
|
end
|
|
end
|
|
|
|
context "with a random search" do
|
|
should "render" do
|
|
get posts_path, params: { tags: "order:random" }
|
|
assert_response :success
|
|
|
|
get posts_path, params: { random: "1" }
|
|
assert_response :success
|
|
|
|
get posts_path(format: :json), params: { random: "1" }
|
|
assert_response :success
|
|
end
|
|
|
|
should "render with multiple posts" do
|
|
@posts = create_list(:post, 2)
|
|
|
|
get posts_path, params: { random: "1" }
|
|
assert_response :success
|
|
end
|
|
end
|
|
|
|
context "with the .atom format" do
|
|
should "render without tags" do
|
|
get posts_path(format: :atom)
|
|
|
|
assert_response :success
|
|
assert_select "entry", 1
|
|
end
|
|
|
|
should "render with tags" do
|
|
get posts_path(format: :atom), params: { tags: "aaaa" }
|
|
|
|
assert_response :success
|
|
assert_select "entry", 1
|
|
end
|
|
|
|
should "hide restricted posts" do
|
|
@post.update(is_banned: true)
|
|
get posts_path(format: :atom)
|
|
|
|
assert_response :success
|
|
assert_select "entry", 0
|
|
end
|
|
end
|
|
|
|
context "with deleted posts" do
|
|
setup do
|
|
@post.update!(is_deleted: true)
|
|
end
|
|
|
|
should "not show deleted posts normally" do
|
|
get posts_path
|
|
assert_response :success
|
|
assert_select "#post_#{@post.id}", 0
|
|
end
|
|
|
|
should "show deleted posts when searching for status:deleted" do
|
|
get posts_path(tags: "status:deleted")
|
|
assert_response :success
|
|
assert_select "#post_#{@post.id}", 1
|
|
end
|
|
end
|
|
|
|
context "with restricted posts" do
|
|
setup do
|
|
Danbooru.config.stubs(:restricted_tags).returns(["tagme"])
|
|
as(@user) { @post.update!(tag_string: "tagme") }
|
|
end
|
|
|
|
should "not show restricted posts if user doesn't have permission" do
|
|
get posts_path
|
|
assert_response :success
|
|
assert_select "#post_#{@post.id}", 0
|
|
end
|
|
|
|
should "show restricted posts if user has permission" do
|
|
get_auth posts_path, create(:gold_user)
|
|
assert_response :success
|
|
assert_select "#post_#{@post.id}", 1
|
|
end
|
|
end
|
|
|
|
context "in safe mode" do
|
|
should "not include the rating:s tag in the page title" do
|
|
get posts_path(tags: "1girl", safe_mode: true)
|
|
assert_select "title", text: "1girl Art | Safebooru"
|
|
end
|
|
end
|
|
end
|
|
|
|
context "show_seq action" do
|
|
should "render" do
|
|
posts = FactoryBot.create_list(:post, 3)
|
|
|
|
get show_seq_post_path(posts[1].id), params: { seq: "prev" }
|
|
assert_redirected_to(posts[2])
|
|
|
|
get show_seq_post_path(posts[1].id), params: { seq: "next" }
|
|
assert_redirected_to(posts[0])
|
|
end
|
|
end
|
|
|
|
context "random action" do
|
|
should "render" do
|
|
get random_posts_path, params: { tags: "aaaa" }
|
|
assert_redirected_to(post_path(@post, tags: "aaaa"))
|
|
end
|
|
|
|
should "return a 404 when no random posts can be found" do
|
|
get random_posts_path, params: { tags: "qoigjegoi" }
|
|
assert_response 404
|
|
end
|
|
end
|
|
|
|
context "show action" do
|
|
should "render" do
|
|
get post_path(@post), params: {:id => @post.id}
|
|
assert_response :success
|
|
end
|
|
|
|
context "with everything" do
|
|
setup do
|
|
@admin = create(:admin_user, can_approve_posts: true)
|
|
@builder = create(:builder_user, can_approve_posts: true)
|
|
|
|
as(@user) do
|
|
@post.update!(tag_string: "1girl solo highres blah 2001")
|
|
Tag.find_by_name("1girl").update(post_count: 20_000)
|
|
Tag.find_by_name("solo").update(post_count: 2_000)
|
|
Tag.find_by_name("blah").update(post_count: 1)
|
|
|
|
@pool = create(:pool)
|
|
@pool.add!(@post)
|
|
|
|
@favgroup = create(:favorite_group)
|
|
@favgroup.add!(@post)
|
|
|
|
@comment = create(:comment, post: @post, creator: @admin)
|
|
create(:comment_vote, comment: @comment, user: @user)
|
|
|
|
create(:note, post: @post)
|
|
create(:artist_commentary, post: @post)
|
|
create(:post_flag, post: @post, creator: @user)
|
|
create(:post_appeal, post: @post, creator: @user)
|
|
create(:post_vote, post: @post, user: @user)
|
|
create(:favorite, post: @post, user: @user)
|
|
create(:moderation_report, model: @comment, creator: @builder)
|
|
end
|
|
end
|
|
|
|
should "render for an anonymous user" do
|
|
get post_path(@post)
|
|
assert_response :success
|
|
end
|
|
|
|
should "render for a member" do
|
|
get_auth post_path(@post), @user
|
|
assert_response :success
|
|
end
|
|
|
|
should "render for a builder" do
|
|
get_auth post_path(@post), @builder
|
|
assert_response :success
|
|
end
|
|
|
|
should "render for an admin" do
|
|
get_auth post_path(@post), @admin
|
|
assert_response :success
|
|
end
|
|
|
|
should "render for a builder with a search query" do
|
|
get_auth post_path(@post, q: "tagme"), @builder
|
|
assert_response :success
|
|
end
|
|
end
|
|
|
|
context "with pools" do
|
|
should "render the pool list" do
|
|
as(@user) { @post.update(tag_string: "newpool:comic") }
|
|
get post_path(@post)
|
|
|
|
assert_response :success
|
|
assert_select "#pool-nav .pool-name", /Pool: comic/
|
|
end
|
|
end
|
|
|
|
context "with only deleted comments" do
|
|
setup do
|
|
as(@user) { create(:comment, creator: @user, post: @post, is_deleted: true) }
|
|
end
|
|
|
|
should "not show deleted comments to regular members" do
|
|
get_auth post_path(@post), @user, params: { id: @post.id }
|
|
|
|
assert_response :success
|
|
assert_select "article.comment", 0
|
|
assert_select "a#show-all-comments-link", 0
|
|
assert_select "div.list-of-comments p", /There are no comments/
|
|
end
|
|
|
|
should "not show deleted comments to moderators by default, but allow them to be unhidden" do
|
|
mod = create(:mod_user)
|
|
get_auth post_path(@post), mod, params: { id: @post.id }
|
|
|
|
assert_response :success
|
|
assert_select "article.comment", 0
|
|
assert_select "a#show-all-comments-link", 1
|
|
assert_select "div.list-of-comments p", /There are no comments/
|
|
end
|
|
end
|
|
|
|
context "with only downvoted comments" do
|
|
should "not show thresholded comments" do
|
|
comment = as(@user) { create(:comment, creator: @user, post: @post, score: -10) }
|
|
get_auth post_path(@post), @user, params: { id: @post.id }
|
|
|
|
assert_response :success
|
|
assert_select "article.comment", 0
|
|
assert_select "a#show-all-comments-link", 1
|
|
assert_select "div.list-of-comments p", /There are no visible comments/
|
|
end
|
|
end
|
|
|
|
context "with a mix of comments" do
|
|
should "not show deleted or thresholded comments " do
|
|
as(@user) { create(:comment, creator: @user, post: @post, do_not_bump_post: true, body: "good") }
|
|
as(@user) { create(:comment, creator: @user, post: @post, do_not_bump_post: true, body: "bad", score: -10) }
|
|
as(@user) { create(:comment, creator: @user, post: @post, do_not_bump_post: true, body: "ugly", is_deleted: true) }
|
|
|
|
get_auth post_path(@post), @user, params: { id: @post.id }
|
|
|
|
assert_response :success
|
|
assert_select "article.comment", 1
|
|
assert_select "article.comment", /good/
|
|
assert_select "a#show-all-comments-link", 1
|
|
end
|
|
end
|
|
|
|
context "when the recommend service is enabled" do
|
|
setup do
|
|
@post2 = create(:post)
|
|
RecommenderService.stubs(:enabled?).returns(true)
|
|
RecommenderService.stubs(:available_for_post?).returns(true)
|
|
end
|
|
|
|
should "not error out" do
|
|
get_auth post_path(@post), @user
|
|
assert_response :success
|
|
end
|
|
end
|
|
|
|
context "in api responses" do
|
|
should "not include restricted attributes" do
|
|
Post.any_instance.stubs(:visible?).returns(false)
|
|
get_auth post_path(@post), @user, as: :json
|
|
|
|
assert_response :success
|
|
assert_nil(response.parsed_body["md5"])
|
|
assert_nil(response.parsed_body["file_url"])
|
|
assert_nil(response.parsed_body["fav_string"])
|
|
end
|
|
end
|
|
end
|
|
|
|
context "update action" do
|
|
should "work" do
|
|
put_auth post_path(@post), @user, params: {:post => {:tag_string => "bbb"}}
|
|
assert_redirected_to post_path(@post)
|
|
|
|
@post.reload
|
|
assert_equal("bbb", @post.tag_string)
|
|
end
|
|
|
|
should "ignore restricted params" do
|
|
put_auth post_path(@post), @user, params: {:post => {:last_noted_at => 1.minute.ago}}
|
|
assert_nil(@post.reload.last_noted_at)
|
|
end
|
|
|
|
should "not allow unprivileged users to update restricted posts" do
|
|
as(@user) { @post.update!(is_banned: true) }
|
|
put_auth post_path(@post), @user, params: { post: { tag_string: "blah" }}
|
|
assert_response 403
|
|
assert_not_equal("blah", @post.reload.tag_string)
|
|
end
|
|
|
|
should "not allow unverified users to update posts" do
|
|
@user.update!(requires_verification: true, is_verified: false)
|
|
put_auth post_path(@post), @user, params: { post: { tag_string: "blah" }}
|
|
assert_response 403
|
|
assert_not_equal("blah", @post.reload.tag_string)
|
|
end
|
|
end
|
|
|
|
context "revert action" do
|
|
setup do
|
|
PostVersion.sqs_service.stubs(:merge?).returns(false)
|
|
as_user do
|
|
@post.update(tag_string: "zzz")
|
|
end
|
|
end
|
|
|
|
should "work" do
|
|
@version = @post.versions.first
|
|
assert_equal("aaaa", @version.tags)
|
|
put_auth revert_post_path(@post), @user, params: {:version_id => @version.id}
|
|
assert_redirected_to post_path(@post)
|
|
@post.reload
|
|
assert_equal("aaaa", @post.tag_string)
|
|
end
|
|
|
|
should "not allow reverting to a previous version of another post" do
|
|
as_user do
|
|
@post2 = create(:post, :uploader_id => @user.id, :tag_string => "herp")
|
|
end
|
|
|
|
put_auth revert_post_path(@post), @user, params: { :version_id => @post2.versions.first.id }
|
|
@post.reload
|
|
assert_not_equal(@post.tag_string, @post2.tag_string)
|
|
assert_response :missing
|
|
end
|
|
end
|
|
|
|
context "copy_notes action" do
|
|
setup do
|
|
as(@user) do
|
|
@src = create(:post, image_width: 100, image_height: 100, tag_string: "translated partially_translated", has_embedded_notes: true)
|
|
@dst = create(:post, image_width: 200, image_height: 200, tag_string: "translation_request")
|
|
create(:note, post: @src, x: 10, y: 10, width: 10, height: 10, body: "test")
|
|
create(:note, post: @src, x: 10, y: 10, width: 10, height: 10, body: "deleted", is_active: false)
|
|
end
|
|
end
|
|
|
|
should "copy notes and tags" do
|
|
put_auth copy_notes_post_path(@src), @user, params: { other_post_id: @dst.id }
|
|
assert_response :success
|
|
|
|
assert_equal(1, @dst.reload.notes.active.length)
|
|
assert_equal(true, @dst.has_embedded_notes)
|
|
assert_equal("lowres partially_translated translated", @dst.tag_string)
|
|
end
|
|
|
|
should "rescale notes" do
|
|
put_auth copy_notes_post_path(@src), @user, params: { other_post_id: @dst.id }
|
|
assert_response :success
|
|
|
|
note = @dst.notes.active.first
|
|
assert_equal([20, 20, 20, 20], [note.x, note.y, note.width, note.height])
|
|
end
|
|
end
|
|
|
|
context "mark_as_translated action" do
|
|
should "mark the post as translated" do
|
|
put_auth mark_as_translated_post_path(@post), @user, params: { post: { check_translation: false, partially_translated: false }}
|
|
assert_redirected_to @post
|
|
assert(@post.reload.has_tag?("translated"))
|
|
end
|
|
end
|
|
end
|
|
end
|