Standardize it so that all fields of type `text` are searchable with `search[<field>_matches]`. Before, the `<field>_matches` param was handled manually and some fields were left out or handled inconsistently. Now it applies to all columns of type `text`. This does a full-text search on the field, so for example, searching `/artist_commentaries?search[translated_description_matches]=smiling` will match translated commentaries containing either the word "smiling", "smiles", "smiled", or "smile". Note that this only applies to columns defined as type `text`, not to columns defined as `character varying`. The difference is that `text` is used for fields containing free-form natural language, such as comments, notes, forum posts, wiki pages, pool descriptions, etc, while `character varying` is used for short strings not containing free-form language, such as tag names, wiki page titles, urls, status fields, etc. API changes: * Add the `search[original_title_matches]`, `search[original_description_matches]`, `search[translated_title_matches]`, `search[translated_description_matches]` params to /artist_commentaries and /artist_commentary_versions. * Remove the `search[name_matches]` and `search[group_name_matches]` params from /artist_versions. * Remove the `search[title_matches]` param from /wiki_page_versions. * Change the `search[name_matches]` param on /pools, /favorite_groups, and /pool_versions to do a full-text search instead of a substring match.
116 lines
3.3 KiB
Ruby
116 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class PostFlag < ApplicationRecord
|
|
module Reasons
|
|
UNAPPROVED = "Unapproved in three days"
|
|
REJECTED = "Unapproved in three days after returning to moderation queue%"
|
|
end
|
|
|
|
belongs_to :creator, class_name: "User"
|
|
belongs_to :post
|
|
|
|
before_validation { post.lock! }
|
|
validates :reason, presence: true, length: { in: 1..140 }
|
|
validate :validate_creator_is_not_limited, on: :create
|
|
validate :validate_post, on: :create
|
|
validates :creator_id, uniqueness: { scope: :post_id, on: :create, unless: :is_deletion, message: "have already flagged this post" }
|
|
before_save :update_post
|
|
after_create :prune_disapprovals
|
|
attr_accessor :is_deletion
|
|
|
|
enum status: {
|
|
pending: 0,
|
|
succeeded: 1,
|
|
rejected: 2,
|
|
}
|
|
|
|
scope :by_users, -> { where.not(creator: User.system) }
|
|
scope :by_system, -> { where(creator: User.system) }
|
|
scope :in_cooldown, -> { by_users.where("created_at >= ?", Danbooru.config.moderation_period.ago) }
|
|
scope :expired, -> { pending.where("post_flags.created_at < ?", Danbooru.config.moderation_period.ago) }
|
|
scope :active, -> { pending.or(rejected.in_cooldown) }
|
|
|
|
module SearchMethods
|
|
def creator_matches(creator, searcher)
|
|
return none if creator.nil?
|
|
|
|
policy = Pundit.policy!(searcher, PostFlag.unscoped.new(creator: creator))
|
|
|
|
if policy.can_view_flagger?
|
|
where(creator: creator).where.not(post: searcher.posts)
|
|
else
|
|
none
|
|
end
|
|
end
|
|
|
|
def category_matches(category)
|
|
case category
|
|
when "normal"
|
|
where("reason NOT IN (?) AND reason NOT LIKE ?", [Reasons::UNAPPROVED], Reasons::REJECTED)
|
|
when "unapproved"
|
|
where(reason: Reasons::UNAPPROVED)
|
|
when "rejected"
|
|
where("reason LIKE ?", Reasons::REJECTED)
|
|
when "deleted"
|
|
where("reason = ? OR reason LIKE ?", Reasons::UNAPPROVED, Reasons::REJECTED)
|
|
else
|
|
none
|
|
end
|
|
end
|
|
|
|
def search(params)
|
|
q = search_attributes(params, :id, :created_at, :updated_at, :reason, :status, :post, :creator)
|
|
|
|
if params[:category]
|
|
q = q.category_matches(params[:category])
|
|
end
|
|
|
|
q.apply_default_order(params)
|
|
end
|
|
end
|
|
|
|
extend SearchMethods
|
|
|
|
def category
|
|
case reason
|
|
when Reasons::UNAPPROVED
|
|
:unapproved
|
|
when /#{Reasons::REJECTED.gsub("%", ".*")}/
|
|
:rejected
|
|
else
|
|
:normal
|
|
end
|
|
end
|
|
|
|
def prune_disapprovals
|
|
return if is_deletion
|
|
PostDisapproval.where(post: post).delete_all
|
|
end
|
|
|
|
def update_post
|
|
post.update_column(:is_flagged, true) unless post.is_flagged?
|
|
end
|
|
|
|
def validate_creator_is_not_limited
|
|
errors.add(:creator, "have reached your flag limit") if creator.is_flag_limited? && !is_deletion
|
|
end
|
|
|
|
def validate_post
|
|
errors.add(:post, "is pending and cannot be flagged") if post.is_pending? && !is_deletion
|
|
errors.add(:post, "is deleted and cannot be flagged") if post.is_deleted? && !is_deletion
|
|
|
|
flag = post.flags.in_cooldown.last
|
|
if !is_deletion && !creator.is_approver? && flag.present?
|
|
errors.add(:post, "cannot be flagged more than once every #{Danbooru.config.moderation_period.inspect} (last flagged: #{flag.created_at.to_formatted_s(:long)})")
|
|
end
|
|
end
|
|
|
|
def uploader_id
|
|
post.uploader_id
|
|
end
|
|
|
|
def self.available_includes
|
|
[:post]
|
|
end
|
|
end
|