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.
118 lines
3.5 KiB
Ruby
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
|