Files
danbooru/app/models/post_flag.rb
evazion 054ac51d47 policies: remove current request from context.
This refactors Pundit policies to only rely on the current user, not on
the current user and the current HTTP request. In retrospect, it was a
bad idea to include the current request in the Pundit context. It bleeds
out everywhere and there are many contexts (in tests and models) where
we only have the current user, not the current request. The previous
commit got rid of the only two places where we used it.
2021-01-17 00:57:59 -06:00

118 lines
3.5 KiB
Ruby

class PostFlag < ApplicationRecord
class Error < StandardError; end
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
validates :reason, presence: true, length: { in: 1..140 }
validate :validate_creator_is_not_limited, on: :create
validate :validate_post, on: :create
validates_uniqueness_of :creator_id, scope: :post_id, on: :create, unless: :is_deletion, message: "have already flagged this post"
before_save :update_post
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.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)
q = q.text_attribute_matches(:reason, params[:reason_matches])
if params[:creator_id].present?
flagger = User.find(params[:creator_id])
q = q.creator_matches(flagger, CurrentUser.user)
elsif params[:creator_name].present?
flagger = User.find_by_name(params[:creator_name])
q = q.creator_matches(flagger, CurrentUser.user)
end
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 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
errors.add(:post, "is locked and cannot be flagged") if post.is_status_locked?
flag = post.flags.in_cooldown.last
if !is_deletion && flag.present?
errors.add(:post, "cannot be flagged more than once every #{Danbooru.config.moderation_period.inspect} (last flagged: #{flag.created_at.to_s(:long)})")
end
end
def uploader_id
post.uploader_id
end
def self.available_includes
[:post]
end
end