search: allow all metatags to be negated.
Fix not being able to negate the following metatags: * id (didn't support ranges) * md5 * width * height * mpixels * ratio * score * favcount * filesize * date * age * tagcount * pixiv
This commit is contained in:
@@ -19,49 +19,11 @@ class PostQueryBuilder
|
|||||||
CATEGORY_COUNT_METATAGS = TagCategory.short_name_list.map { |category| "#{category}tags" }
|
CATEGORY_COUNT_METATAGS = TagCategory.short_name_list.map { |category| "#{category}tags" }
|
||||||
|
|
||||||
METATAGS = %w[
|
METATAGS = %w[
|
||||||
-user user
|
user approver commenter comm noter noteupdater artcomm commentaryupdater
|
||||||
-approver approver
|
flagger appealer upvote downvote fav ordfav favgroup ordfavgroup pool
|
||||||
-commenter commenter comm
|
ordpool note comment commentary id rating locked source status filetype
|
||||||
-noter noter
|
disapproved parent child search embedded md5 width height mpixels ratio
|
||||||
-noteupdater noteupdater
|
score favcount filesize date age order limit tagcount pixiv_id pixiv
|
||||||
-artcomm artcomm
|
|
||||||
-commentaryupdater commentaryupdater
|
|
||||||
-flagger flagger
|
|
||||||
-appealer appealer
|
|
||||||
-upvote upvote
|
|
||||||
-downvote downvote
|
|
||||||
-fav fav
|
|
||||||
-ordfav ordfav
|
|
||||||
-favgroup favgroup ordfavgroup
|
|
||||||
-pool pool ordpool
|
|
||||||
-note note
|
|
||||||
-comment comment
|
|
||||||
-commentary commentary
|
|
||||||
-id id
|
|
||||||
-rating rating
|
|
||||||
-locked locked
|
|
||||||
-source source
|
|
||||||
-status status
|
|
||||||
-filetype filetype
|
|
||||||
-disapproved disapproved
|
|
||||||
-parent parent
|
|
||||||
-child child
|
|
||||||
-search search
|
|
||||||
-embedded embedded
|
|
||||||
md5
|
|
||||||
width
|
|
||||||
height
|
|
||||||
mpixels
|
|
||||||
ratio
|
|
||||||
score
|
|
||||||
favcount
|
|
||||||
filesize
|
|
||||||
date
|
|
||||||
age
|
|
||||||
order
|
|
||||||
limit
|
|
||||||
tagcount
|
|
||||||
pixiv_id pixiv
|
|
||||||
] + COUNT_METATAGS + COUNT_METATAG_SYNONYMS + CATEGORY_COUNT_METATAGS
|
] + COUNT_METATAGS + COUNT_METATAG_SYNONYMS + CATEGORY_COUNT_METATAGS
|
||||||
|
|
||||||
ORDER_METATAGS = %w[
|
ORDER_METATAGS = %w[
|
||||||
@@ -121,7 +83,9 @@ class PostQueryBuilder
|
|||||||
|
|
||||||
def metatags_match(metatags, relation)
|
def metatags_match(metatags, relation)
|
||||||
metatags.each do |metatag|
|
metatags.each do |metatag|
|
||||||
relation = relation.and(metatag_matches(metatag.name, metatag.value, quoted: metatag.quoted))
|
clause = metatag_matches(metatag.name, metatag.value, quoted: metatag.quoted)
|
||||||
|
clause = clause.negate if metatag.negated
|
||||||
|
relation = relation.and(clause)
|
||||||
end
|
end
|
||||||
|
|
||||||
relation
|
relation
|
||||||
@@ -131,8 +95,6 @@ class PostQueryBuilder
|
|||||||
case name
|
case name
|
||||||
when "id"
|
when "id"
|
||||||
attribute_matches(value, :id)
|
attribute_matches(value, :id)
|
||||||
when "-id"
|
|
||||||
Post.where.not(id: value.to_i)
|
|
||||||
when "md5"
|
when "md5"
|
||||||
attribute_matches(value, :md5, :md5)
|
attribute_matches(value, :md5, :md5)
|
||||||
when "width"
|
when "width"
|
||||||
@@ -151,8 +113,6 @@ class PostQueryBuilder
|
|||||||
attribute_matches(value, :file_size, :filesize)
|
attribute_matches(value, :file_size, :filesize)
|
||||||
when "filetype"
|
when "filetype"
|
||||||
attribute_matches(value, :file_ext, :enum)
|
attribute_matches(value, :file_ext, :enum)
|
||||||
when "-filetype"
|
|
||||||
attribute_matches(value, :file_ext, :enum).negate(:nor)
|
|
||||||
when "date"
|
when "date"
|
||||||
attribute_matches(value, :created_at, :date)
|
attribute_matches(value, :created_at, :date)
|
||||||
when "age"
|
when "age"
|
||||||
@@ -163,110 +123,60 @@ class PostQueryBuilder
|
|||||||
attribute_matches(value, :tag_count)
|
attribute_matches(value, :tag_count)
|
||||||
when "status"
|
when "status"
|
||||||
status_matches(value)
|
status_matches(value)
|
||||||
when "-status"
|
|
||||||
status_matches(value).negate
|
|
||||||
when "parent"
|
when "parent"
|
||||||
parent_matches(value)
|
parent_matches(value)
|
||||||
when "-parent"
|
|
||||||
parent_matches(value).negate
|
|
||||||
when "child"
|
when "child"
|
||||||
child_matches(value)
|
child_matches(value)
|
||||||
when "-child"
|
|
||||||
child_matches(value).negate
|
|
||||||
when "rating"
|
when "rating"
|
||||||
Post.where(rating: value.first.downcase)
|
Post.where(rating: value.first.downcase)
|
||||||
when "-rating"
|
|
||||||
Post.where(rating: value.first.downcase).negate
|
|
||||||
when "locked"
|
when "locked"
|
||||||
locked_matches(value)
|
locked_matches(value)
|
||||||
when "-locked"
|
|
||||||
locked_matches(value).negate
|
|
||||||
when "embedded"
|
when "embedded"
|
||||||
embedded_matches(value)
|
embedded_matches(value)
|
||||||
when "-embedded"
|
|
||||||
embedded_matches(value).negate
|
|
||||||
when "source"
|
when "source"
|
||||||
source_matches(value, quoted)
|
source_matches(value, quoted)
|
||||||
when "-source"
|
|
||||||
source_matches(value, quoted).negate
|
|
||||||
when "disapproved"
|
when "disapproved"
|
||||||
disapproved_matches(value)
|
disapproved_matches(value)
|
||||||
when "-disapproved"
|
|
||||||
disapproved_matches(value).negate
|
|
||||||
when "commentary"
|
when "commentary"
|
||||||
commentary_matches(value, quoted)
|
commentary_matches(value, quoted)
|
||||||
when "-commentary"
|
|
||||||
commentary_matches(value, quoted).negate
|
|
||||||
when "note"
|
when "note"
|
||||||
note_matches(value)
|
note_matches(value)
|
||||||
when "-note"
|
|
||||||
note_matches(value).negate
|
|
||||||
when "comment"
|
when "comment"
|
||||||
comment_matches(value)
|
comment_matches(value)
|
||||||
when "-comment"
|
|
||||||
comment_matches(value).negate
|
|
||||||
when "search"
|
when "search"
|
||||||
saved_search_matches(value)
|
saved_search_matches(value)
|
||||||
when "-search"
|
|
||||||
saved_search_matches(value).negate
|
|
||||||
when "pool"
|
when "pool"
|
||||||
pool_matches(value)
|
pool_matches(value)
|
||||||
when "-pool"
|
|
||||||
pool_matches(value).negate
|
|
||||||
when "ordpool"
|
when "ordpool"
|
||||||
ordpool_matches(value)
|
ordpool_matches(value)
|
||||||
when "favgroup"
|
when "favgroup"
|
||||||
favgroup_matches(value)
|
favgroup_matches(value)
|
||||||
when "-favgroup"
|
|
||||||
favgroup_matches(value).negate
|
|
||||||
when "ordfavgroup"
|
when "ordfavgroup"
|
||||||
ordfavgroup_matches(value)
|
ordfavgroup_matches(value)
|
||||||
when "fav"
|
when "fav"
|
||||||
favorites_include(value)
|
favorites_include(value)
|
||||||
when "-fav"
|
|
||||||
favorites_exclude(value)
|
|
||||||
when "ordfav"
|
when "ordfav"
|
||||||
ordfav_matches(value)
|
ordfav_matches(value)
|
||||||
when "user"
|
when "user"
|
||||||
user_matches(:uploader, value)
|
user_matches(:uploader, value)
|
||||||
when "-user"
|
|
||||||
user_matches(:uploader, value).negate
|
|
||||||
when "approver"
|
when "approver"
|
||||||
user_matches(:approver, value)
|
user_matches(:approver, value)
|
||||||
when "-approver"
|
|
||||||
user_matches(:approver, value).negate
|
|
||||||
when "flagger"
|
when "flagger"
|
||||||
flagger_matches(value)
|
flagger_matches(value)
|
||||||
when "-flagger"
|
|
||||||
flagger_matches(value).negate
|
|
||||||
when "appealer"
|
when "appealer"
|
||||||
user_subquery_matches(PostAppeal.unscoped, value)
|
user_subquery_matches(PostAppeal.unscoped, value)
|
||||||
when "-appealer"
|
|
||||||
user_subquery_matches(PostAppeal.unscoped, value).negate
|
|
||||||
when "commenter", "comm"
|
when "commenter", "comm"
|
||||||
user_subquery_matches(Comment.unscoped, value)
|
user_subquery_matches(Comment.unscoped, value)
|
||||||
when "-commenter"
|
|
||||||
user_subquery_matches(Comment.unscoped, value).negate
|
|
||||||
when "commentaryupdater", "artcomm"
|
when "commentaryupdater", "artcomm"
|
||||||
user_subquery_matches(ArtistCommentaryVersion.unscoped, value, field: :updater)
|
user_subquery_matches(ArtistCommentaryVersion.unscoped, value, field: :updater)
|
||||||
when "-commentaryupdater", "-artcomm"
|
|
||||||
user_subquery_matches(ArtistCommentaryVersion.unscoped, value, field: :updater).negate
|
|
||||||
when "noter"
|
when "noter"
|
||||||
user_subquery_matches(NoteVersion.unscoped.where(version: 1), value, field: :updater)
|
user_subquery_matches(NoteVersion.unscoped.where(version: 1), value, field: :updater)
|
||||||
when "-noter"
|
|
||||||
user_subquery_matches(NoteVersion.unscoped.where(version: 1), value, field: :updater).negate
|
|
||||||
when "noteupdater"
|
when "noteupdater"
|
||||||
user_subquery_matches(NoteVersion.unscoped, value, field: :updater)
|
user_subquery_matches(NoteVersion.unscoped, value, field: :updater)
|
||||||
when "-noteupdater"
|
|
||||||
user_subquery_matches(NoteVersion.unscoped, value, field: :updater).negate
|
|
||||||
when "upvoter", "upvote"
|
when "upvoter", "upvote"
|
||||||
user_subquery_matches(PostVote.positive.visible(CurrentUser.user), value, field: :user)
|
user_subquery_matches(PostVote.positive.visible(CurrentUser.user), value, field: :user)
|
||||||
when "-upvoter", "-upvote"
|
|
||||||
user_subquery_matches(PostVote.positive.visible(CurrentUser.user), value, field: :user).negate
|
|
||||||
when "downvoter", "downvote"
|
when "downvoter", "downvote"
|
||||||
user_subquery_matches(PostVote.negative.visible(CurrentUser.user), value, field: :user)
|
user_subquery_matches(PostVote.negative.visible(CurrentUser.user), value, field: :user)
|
||||||
when "-downvoter", "-downvote"
|
|
||||||
user_subquery_matches(PostVote.negative.visible(CurrentUser.user), value, field: :user).negate
|
|
||||||
when *CATEGORY_COUNT_METATAGS
|
when *CATEGORY_COUNT_METATAGS
|
||||||
short_category = name.delete_suffix("tags")
|
short_category = name.delete_suffix("tags")
|
||||||
category = TagCategory.short_name_mapping[short_category]
|
category = TagCategory.short_name_mapping[short_category]
|
||||||
@@ -288,11 +198,6 @@ class PostQueryBuilder
|
|||||||
Post.where("posts.tag_index @@ to_tsquery('danbooru', E?)", query)
|
Post.where("posts.tag_index @@ to_tsquery('danbooru', E?)", query)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tags_exclude(*tags)
|
|
||||||
query = tags.map(&:to_escaped_for_tsquery).join(" | ")
|
|
||||||
Post.where("posts.tag_index @@ to_tsquery('danbooru', E?)", "!(#{query})")
|
|
||||||
end
|
|
||||||
|
|
||||||
def attribute_matches(value, field, type = :integer)
|
def attribute_matches(value, field, type = :integer)
|
||||||
operator, *args = parse_metatag_value(value, type)
|
operator, *args = parse_metatag_value(value, type)
|
||||||
Post.where_operator(field, operator, *args)
|
Post.where_operator(field, operator, *args)
|
||||||
@@ -465,16 +370,6 @@ class PostQueryBuilder
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def favorites_exclude(username)
|
|
||||||
favuser = User.find_by_name(username)
|
|
||||||
|
|
||||||
if favuser.present? && Pundit.policy!([CurrentUser.user, nil], favuser).can_see_favorites?
|
|
||||||
tags_exclude("fav:#{favuser.id}")
|
|
||||||
else
|
|
||||||
Post.all
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ordfav_matches(username)
|
def ordfav_matches(username)
|
||||||
user = User.find_by_name(username)
|
user = User.find_by_name(username)
|
||||||
favorites_include(username).joins(:favorites).merge(Favorite.for_user(user.id)).order("favorites.id DESC")
|
favorites_include(username).joins(:favorites).merge(Favorite.for_user(user.id)).order("favorites.id DESC")
|
||||||
@@ -540,8 +435,7 @@ class PostQueryBuilder
|
|||||||
|
|
||||||
def hide_deleted_posts?
|
def hide_deleted_posts?
|
||||||
return false if CurrentUser.admin_mode?
|
return false if CurrentUser.admin_mode?
|
||||||
return false if find_metatag("status").to_s.downcase.in?(%w[deleted active any all])
|
return false if find_metatag(:status).to_s.downcase.in?(%w[deleted active any all])
|
||||||
return false if find_metatag("-status").to_s.downcase.in?(%w[deleted active any all])
|
|
||||||
return CurrentUser.user.hide_deleted_posts?
|
return CurrentUser.user.hide_deleted_posts?
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -726,8 +620,9 @@ class PostQueryBuilder
|
|||||||
until scanner.eos?
|
until scanner.eos?
|
||||||
scanner.skip(/ +/)
|
scanner.skip(/ +/)
|
||||||
|
|
||||||
if scanner.scan(/(#{METATAGS.join("|")}):/io)
|
if scanner.scan(/(-)?(#{METATAGS.join("|")}):/io)
|
||||||
metatag = scanner.captures.first.downcase
|
operator = scanner.captures.first
|
||||||
|
metatag = scanner.captures.second.downcase
|
||||||
|
|
||||||
if scanner.scan(/"(.+)"/) || scanner.scan(/'(.+)'/)
|
if scanner.scan(/"(.+)"/) || scanner.scan(/'(.+)'/)
|
||||||
value = scanner.captures.first
|
value = scanner.captures.first
|
||||||
@@ -746,7 +641,7 @@ class PostQueryBuilder
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
terms << OpenStruct.new({ type: :metatag, name: metatag, value: value, quoted: quoted })
|
terms << OpenStruct.new(type: :metatag, name: metatag, value: value, negated: (operator == "-"), quoted: quoted)
|
||||||
elsif scanner.scan(/([-~])?([^ ]+)/)
|
elsif scanner.scan(/([-~])?([^ ]+)/)
|
||||||
operator = scanner.captures.first
|
operator = scanner.captures.first
|
||||||
tag = scanner.captures.second
|
tag = scanner.captures.second
|
||||||
|
|||||||
@@ -1069,7 +1069,7 @@ class Post < ApplicationRecord
|
|||||||
def fast_count(tags = "", timeout: 1_000, raise_on_timeout: false, skip_cache: false)
|
def fast_count(tags = "", timeout: 1_000, raise_on_timeout: false, skip_cache: false)
|
||||||
tags = tags.to_s
|
tags = tags.to_s
|
||||||
tags += " rating:s" if CurrentUser.safe_mode?
|
tags += " rating:s" if CurrentUser.safe_mode?
|
||||||
tags += " -status:deleted" if CurrentUser.hide_deleted_posts? && !PostQueryBuilder.new(tags).has_metatag?("status", "-status")
|
tags += " -status:deleted" if CurrentUser.hide_deleted_posts? && !PostQueryBuilder.new(tags).has_metatag?("status")
|
||||||
tags = PostQueryBuilder.new(tags).normalize_query
|
tags = PostQueryBuilder.new(tags).normalize_query
|
||||||
|
|
||||||
# Optimize some cases. these are just estimates but at these
|
# Optimize some cases. these are just estimates but at these
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ module Danbooru
|
|||||||
|
|
||||||
# Return true if the given tag shouldn't count against the user's tag search limit.
|
# Return true if the given tag shouldn't count against the user's tag search limit.
|
||||||
def is_unlimited_tag?(term)
|
def is_unlimited_tag?(term)
|
||||||
term.type == :metatag && term.name.in?(%w[-status status rating limit])
|
term.type == :metatag && term.name.in?(%w[status rating limit])
|
||||||
end
|
end
|
||||||
|
|
||||||
# After this many pages, the paginator will switch to sequential mode.
|
# After this many pages, the paginator will switch to sequential mode.
|
||||||
|
|||||||
@@ -147,7 +147,6 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([posts[2]], "id:>#{posts[1].id}")
|
assert_tag_match([posts[2]], "id:>#{posts[1].id}")
|
||||||
assert_tag_match([posts[0]], "id:<#{posts[1].id}")
|
assert_tag_match([posts[0]], "id:<#{posts[1].id}")
|
||||||
|
|
||||||
assert_tag_match([posts[2], posts[0]], "-id:#{posts[1].id}")
|
|
||||||
assert_tag_match([posts[2], posts[1]], "id:>=#{posts[1].id}")
|
assert_tag_match([posts[2], posts[1]], "id:>=#{posts[1].id}")
|
||||||
assert_tag_match([posts[1], posts[0]], "id:<=#{posts[1].id}")
|
assert_tag_match([posts[1], posts[0]], "id:<=#{posts[1].id}")
|
||||||
assert_tag_match([posts[2], posts[0]], "id:#{posts[0].id},#{posts[2].id}")
|
assert_tag_match([posts[2], posts[0]], "id:#{posts[0].id},#{posts[2].id}")
|
||||||
@@ -158,6 +157,13 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([posts[1], posts[0]], "id:#{posts[1].id}..#{posts[0].id}")
|
assert_tag_match([posts[1], posts[0]], "id:#{posts[1].id}..#{posts[0].id}")
|
||||||
assert_tag_match([posts[1], posts[0]], "id:#{posts[0].id}...#{posts[2].id}")
|
assert_tag_match([posts[1], posts[0]], "id:#{posts[0].id}...#{posts[2].id}")
|
||||||
|
|
||||||
|
assert_tag_match([posts[1], posts[0]], "-id:>#{posts[1].id}")
|
||||||
|
assert_tag_match([posts[2], posts[1]], "-id:<#{posts[1].id}")
|
||||||
|
assert_tag_match([posts[0]], "-id:>=#{posts[1].id}")
|
||||||
|
assert_tag_match([posts[2]], "-id:<=#{posts[1].id}")
|
||||||
|
assert_tag_match([posts[0]], "-id:#{posts[1].id}..#{posts[2].id}")
|
||||||
|
assert_tag_match([posts[0]], "-id:#{posts[1].id},#{posts[2].id}")
|
||||||
|
|
||||||
assert_tag_match([], "id:#{posts[0].id} id:#{posts[2].id}")
|
assert_tag_match([], "id:#{posts[0].id} id:#{posts[2].id}")
|
||||||
assert_tag_match([posts[0]], "-id:#{posts[1].id} -id:#{posts[2].id}")
|
assert_tag_match([posts[0]], "-id:#{posts[1].id} -id:#{posts[2].id}")
|
||||||
assert_tag_match([posts[1]], "id:>#{posts[0].id} id:<#{posts[2].id}")
|
assert_tag_match([posts[1]], "id:>#{posts[0].id} id:<#{posts[2].id}")
|
||||||
@@ -349,6 +355,8 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
assert_tag_match([posts[0]], "commenter:#{users[0].name}")
|
assert_tag_match([posts[0]], "commenter:#{users[0].name}")
|
||||||
assert_tag_match([posts[1]], "commenter:#{users[1].name}")
|
assert_tag_match([posts[1]], "commenter:#{users[1].name}")
|
||||||
|
assert_tag_match([posts[1]], "-commenter:#{users[0].name}")
|
||||||
|
assert_tag_match([posts[0]], "-commenter:#{users[1].name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the commenter:<any|none> metatag" do
|
should "return posts for the commenter:<any|none> metatag" do
|
||||||
@@ -369,6 +377,8 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
assert_tag_match([posts[0]], "noter:#{users[0].name}")
|
assert_tag_match([posts[0]], "noter:#{users[0].name}")
|
||||||
assert_tag_match([posts[1]], "noter:#{users[1].name}")
|
assert_tag_match([posts[1]], "noter:#{users[1].name}")
|
||||||
|
assert_tag_match([posts[1]], "-noter:#{users[0].name}")
|
||||||
|
assert_tag_match([posts[0]], "-noter:#{users[1].name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the noter:<any|none> metatag" do
|
should "return posts for the noter:<any|none> metatag" do
|
||||||
@@ -377,7 +387,9 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
create(:note, post: posts[1], is_active: false)
|
create(:note, post: posts[1], is_active: false)
|
||||||
|
|
||||||
assert_tag_match(posts.reverse, "noter:any")
|
assert_tag_match(posts.reverse, "noter:any")
|
||||||
|
assert_tag_match(posts.reverse, "-noter:none")
|
||||||
assert_tag_match([], "noter:none")
|
assert_tag_match([], "noter:none")
|
||||||
|
assert_tag_match([], "-noter:any")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the noteupdater:<name> metatag" do
|
should "return posts for the noteupdater:<name> metatag" do
|
||||||
@@ -404,6 +416,8 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([posts[1], posts[0]], "notes:1")
|
assert_tag_match([posts[1], posts[0]], "notes:1")
|
||||||
assert_tag_match([posts[0]], "active_notes:1")
|
assert_tag_match([posts[0]], "active_notes:1")
|
||||||
assert_tag_match([posts[1]], "deleted_notes:1")
|
assert_tag_match([posts[1]], "deleted_notes:1")
|
||||||
|
|
||||||
|
assert_tag_match([posts[2]], "-note_count:1")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the commentaryupdater:<name> metatag" do
|
should "return posts for the commentaryupdater:<name> metatag" do
|
||||||
@@ -510,6 +524,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
post = create(:post, created_at: Time.parse("2017-01-01 12:00"))
|
post = create(:post, created_at: Time.parse("2017-01-01 12:00"))
|
||||||
|
|
||||||
assert_tag_match([post], "date:2017-01-01")
|
assert_tag_match([post], "date:2017-01-01")
|
||||||
|
assert_tag_match([], "-date:2017-01-01")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the age:<n> metatag" do
|
should "return posts for the age:<n> metatag" do
|
||||||
@@ -534,6 +549,9 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([], "age:>=1y")
|
assert_tag_match([], "age:>=1y")
|
||||||
assert_tag_match([], "age:1y..2y")
|
assert_tag_match([], "age:1y..2y")
|
||||||
assert_tag_match([], "age:>1y age:<1y")
|
assert_tag_match([], "age:>1y age:<1y")
|
||||||
|
|
||||||
|
assert_tag_match([post], "-age:>1y")
|
||||||
|
assert_tag_match([], "-age:<1y")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the ratio:<x:y> metatag" do
|
should "return posts for the ratio:<x:y> metatag" do
|
||||||
@@ -541,6 +559,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
assert_tag_match([post], "ratio:2:1")
|
assert_tag_match([post], "ratio:2:1")
|
||||||
assert_tag_match([post], "ratio:2.0")
|
assert_tag_match([post], "ratio:2.0")
|
||||||
|
assert_tag_match([], "-ratio:2.0")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the status:<type> metatag" do
|
should "return posts for the status:<type> metatag" do
|
||||||
@@ -580,6 +599,7 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
create(:post_disapproval, user: CurrentUser.user, post: disapproved, reason: "disinterest")
|
create(:post_disapproval, user: CurrentUser.user, post: disapproved, reason: "disinterest")
|
||||||
|
|
||||||
assert_tag_match([pending, flagged], "status:unmoderated")
|
assert_tag_match([pending, flagged], "status:unmoderated")
|
||||||
|
assert_tag_match([disapproved], "-status:unmoderated")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "respect the 'Deleted post filter' option when using the status: metatag" do
|
should "respect the 'Deleted post filter' option when using the status: metatag" do
|
||||||
@@ -642,6 +662,9 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([post], "copytags:1")
|
assert_tag_match([post], "copytags:1")
|
||||||
assert_tag_match([post], "chartags:1")
|
assert_tag_match([post], "chartags:1")
|
||||||
assert_tag_match([post], "gentags:1")
|
assert_tag_match([post], "gentags:1")
|
||||||
|
|
||||||
|
assert_tag_match([], "-gentags:1")
|
||||||
|
assert_tag_match([], "-tagcount:4")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for the md5:<md5> metatag" do
|
should "return posts for the md5:<md5> metatag" do
|
||||||
@@ -652,6 +675,8 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([post1], "md5:ABCD")
|
assert_tag_match([post1], "md5:ABCD")
|
||||||
assert_tag_match([post1], "md5:123,abcd")
|
assert_tag_match([post1], "md5:123,abcd")
|
||||||
assert_tag_match([], "md5:abcd md5:xyz")
|
assert_tag_match([], "md5:abcd md5:xyz")
|
||||||
|
|
||||||
|
assert_tag_match([post2], "-md5:abcd")
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return posts for a source:<text> search" do
|
should "return posts for a source:<text> search" do
|
||||||
@@ -790,6 +815,9 @@ class PostQueryBuilderTest < ActiveSupport::TestCase
|
|||||||
assert_tag_match([downvoted], "downvote:#{CurrentUser.name}")
|
assert_tag_match([downvoted], "downvote:#{CurrentUser.name}")
|
||||||
assert_tag_match([], "upvote:nobody upvote:#{CurrentUser.name}")
|
assert_tag_match([], "upvote:nobody upvote:#{CurrentUser.name}")
|
||||||
assert_tag_match([], "downvote:nobody downvote:#{CurrentUser.name}")
|
assert_tag_match([], "downvote:nobody downvote:#{CurrentUser.name}")
|
||||||
|
|
||||||
|
assert_tag_match([downvoted], "-upvote:#{CurrentUser.name}")
|
||||||
|
assert_tag_match([upvoted], "-downvote:#{CurrentUser.name}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user