search: split tag_match into user_tag_match / system_tag_match.
When doing a tag search, we have to be careful about which user we're running the search as because the results depend on the current user. Specifically, things like private favorites, private favorite groups, post votes, saved searches, and flagger names depend on the user's permissions, and whether non-safe or deleted posts are filtered out depend on whether the user has safe mode on or the hide deleted posts setting enabled. * Refactor internal searches to explicitly state whether they're running as the system user (DanbooruBot) or as the current user. * Explicitly pass in the current user to PostQueryBuilder instead of implicitly relying on the CurrentUser global. * Get rid of CurrentUser.admin_mode? (used to ignore the hide deleted post setting) and CurrentUser.without_safe_mode (used to ignore safe mode). * Change the /counts/posts.json endpoint to ignore safe mode and the hide deleted posts settings when counting posts. * Fix searches not correctly overriding the hide deleted posts setting when multiple status: metatags were used (e.g. `status:banned status:active`) * Fix fast_count not respecting the hide deleted posts setting when the status:banned metatag was used.
This commit is contained in:
@@ -134,10 +134,8 @@ class Artist < ApplicationRecord
|
||||
source = params.delete(:source)
|
||||
|
||||
if source.blank? && params[:name].present?
|
||||
CurrentUser.without_safe_mode do
|
||||
post = Post.tag_match("source:http* #{params[:name]}").first
|
||||
source = post.try(:source)
|
||||
end
|
||||
post = Post.system_tag_match("source:http* #{params[:name]}").first
|
||||
source = post.try(:source)
|
||||
end
|
||||
|
||||
if source.present?
|
||||
@@ -168,36 +166,32 @@ class Artist < ApplicationRecord
|
||||
module BanMethods
|
||||
def unban!
|
||||
Post.transaction do
|
||||
CurrentUser.without_safe_mode do
|
||||
ti = TagImplication.find_by(antecedent_name: name, consequent_name: "banned_artist")
|
||||
ti&.destroy
|
||||
ti = TagImplication.find_by(antecedent_name: name, consequent_name: "banned_artist")
|
||||
ti&.destroy
|
||||
|
||||
Post.tag_match(name).find_each do |post|
|
||||
post.unban!
|
||||
fixed_tags = post.tag_string.sub(/(?:\A| )banned_artist(?:\Z| )/, " ").strip
|
||||
post.update(tag_string: fixed_tags)
|
||||
end
|
||||
|
||||
update!(is_banned: false)
|
||||
ModAction.log("unbanned artist ##{id}", :artist_unban)
|
||||
Post.raw_tag_match(name).find_each do |post|
|
||||
post.unban!
|
||||
fixed_tags = post.tag_string.sub(/(?:\A| )banned_artist(?:\Z| )/, " ").strip
|
||||
post.update(tag_string: fixed_tags)
|
||||
end
|
||||
|
||||
update!(is_banned: false)
|
||||
ModAction.log("unbanned artist ##{id}", :artist_unban)
|
||||
end
|
||||
end
|
||||
|
||||
def ban!(banner: CurrentUser.user)
|
||||
Post.transaction do
|
||||
CurrentUser.without_safe_mode do
|
||||
Post.tag_match(name).each(&:ban!)
|
||||
Post.raw_tag_match(name).each(&:ban!)
|
||||
|
||||
# potential race condition but unlikely
|
||||
unless TagImplication.where(:antecedent_name => name, :consequent_name => "banned_artist").exists?
|
||||
tag_implication = TagImplication.create!(antecedent_name: name, consequent_name: "banned_artist", skip_secondary_validations: true, creator: banner)
|
||||
tag_implication.approve!(approver: banner)
|
||||
end
|
||||
|
||||
update!(is_banned: true)
|
||||
ModAction.log("banned artist ##{id}", :artist_ban)
|
||||
# potential race condition but unlikely
|
||||
unless TagImplication.where(:antecedent_name => name, :consequent_name => "banned_artist").exists?
|
||||
tag_implication = TagImplication.create!(antecedent_name: name, consequent_name: "banned_artist", skip_secondary_validations: true, creator: banner)
|
||||
tag_implication.approve!(approver: banner)
|
||||
end
|
||||
|
||||
update!(is_banned: true)
|
||||
ModAction.log("banned artist ##{id}", :artist_ban)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,7 +27,7 @@ class Pool < ApplicationRecord
|
||||
end
|
||||
|
||||
def post_tags_match(query)
|
||||
posts = Post.tag_match(query).select(:id).reorder(nil)
|
||||
posts = Post.user_tag_match(query).select(:id).reorder(nil)
|
||||
pools = Pool.joins("CROSS JOIN unnest(post_ids) AS post_id").group(:id).where("post_id IN (?)", posts)
|
||||
where(id: pools)
|
||||
end
|
||||
|
||||
@@ -604,7 +604,7 @@ class Post < ApplicationRecord
|
||||
# If someone else committed changes to this post before we did,
|
||||
# then try to merge the tag changes together.
|
||||
current_tags = tag_string_was.split
|
||||
new_tags = PostQueryBuilder.new(tag_string).parse_tag_edit
|
||||
new_tags = PostQueryBuilder.new(tag_string).split_query
|
||||
old_tags = old_tag_string.split
|
||||
|
||||
kept_tags = current_tags & new_tags
|
||||
@@ -642,7 +642,7 @@ class Post < ApplicationRecord
|
||||
end
|
||||
|
||||
def normalize_tags
|
||||
normalized_tags = PostQueryBuilder.new(tag_string).parse_tag_edit
|
||||
normalized_tags = PostQueryBuilder.new(tag_string).split_query
|
||||
normalized_tags = apply_casesensitive_metatags(normalized_tags)
|
||||
normalized_tags = normalized_tags.map(&:downcase)
|
||||
normalized_tags = filter_metatags(normalized_tags)
|
||||
@@ -1372,9 +1372,7 @@ class Post < ApplicationRecord
|
||||
end
|
||||
|
||||
def sample(query, sample_size)
|
||||
CurrentUser.without_safe_mode do
|
||||
tag_match(query).reorder(:md5).limit(sample_size)
|
||||
end
|
||||
user_tag_match(query, safe_mode: false, hide_deleted_posts: false).reorder(:md5).limit(sample_size)
|
||||
end
|
||||
|
||||
# unflattens the tag_string into one tag per row.
|
||||
@@ -1472,8 +1470,12 @@ class Post < ApplicationRecord
|
||||
where("posts.tag_index @@ to_tsquery('danbooru', E?)", tag.to_escaped_for_tsquery)
|
||||
end
|
||||
|
||||
def tag_match(query)
|
||||
PostQueryBuilder.new(query).build
|
||||
def system_tag_match(query)
|
||||
user_tag_match(query, User.system, safe_mode: false, hide_deleted_posts: false)
|
||||
end
|
||||
|
||||
def user_tag_match(query, user = CurrentUser.user, safe_mode: CurrentUser.safe_mode?, hide_deleted_posts: user.hide_deleted_posts?)
|
||||
PostQueryBuilder.new(query, user, safe_mode: safe_mode, hide_deleted_posts: hide_deleted_posts).build
|
||||
end
|
||||
|
||||
def search(params)
|
||||
@@ -1488,7 +1490,7 @@ class Post < ApplicationRecord
|
||||
)
|
||||
|
||||
if params[:tags].present?
|
||||
q = q.tag_match(params[:tags])
|
||||
q = q.user_tag_match(params[:tags])
|
||||
end
|
||||
|
||||
if params[:order].present?
|
||||
|
||||
@@ -114,18 +114,16 @@ class SavedSearch < ApplicationRecord
|
||||
end
|
||||
|
||||
def populate(query, timeout: 10_000)
|
||||
CurrentUser.as_system do
|
||||
redis_key = "search:#{query}"
|
||||
return if redis.exists(redis_key)
|
||||
redis_key = "search:#{query}"
|
||||
return if redis.exists(redis_key)
|
||||
|
||||
post_ids = Post.with_timeout(timeout, [], query: query) do
|
||||
Post.tag_match(query).limit(QUERY_LIMIT).pluck(:id)
|
||||
end
|
||||
post_ids = Post.with_timeout(timeout, [], query: query) do
|
||||
Post.system_tag_match(query).limit(QUERY_LIMIT).pluck(:id)
|
||||
end
|
||||
|
||||
if post_ids.present?
|
||||
redis.sadd(redis_key, post_ids)
|
||||
redis.expire(redis_key, REDIS_EXPIRY.to_i)
|
||||
end
|
||||
if post_ids.present?
|
||||
redis.sadd(redis_key, post_ids)
|
||||
redis.expire(redis_key, REDIS_EXPIRY.to_i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -349,7 +349,7 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
|
||||
def posts
|
||||
Post.tag_match(name)
|
||||
Post.system_tag_match(name)
|
||||
end
|
||||
|
||||
def self.available_includes
|
||||
|
||||
Reference in New Issue
Block a user