Files
danbooru/app/models/post_flag.rb
2020-03-20 18:03:01 -05:00

143 lines
4.0 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
COOLDOWN_PERIOD = 3.days
belongs_to :creator, class_name: "User"
belongs_to :post
validates_presence_of :reason
validate :validate_creator_is_not_limited, on: :create
validate :validate_post
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
scope :by_users, -> { where.not(creator: User.system) }
scope :by_system, -> { where(creator: User.system) }
scope :in_cooldown, -> { by_users.where("created_at >= ?", COOLDOWN_PERIOD.ago) }
scope :resolved, -> { where(is_resolved: true) }
scope :unresolved, -> { where(is_resolved: false) }
scope :recent, -> { where("post_flags.created_at >= ?", 1.day.ago) }
scope :old, -> { where("post_flags.created_at <= ?", 3.days.ago) }
module SearchMethods
def creator_matches(creator, searcher)
policy = Pundit.policy!([searcher, nil], 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 = super
q = q.search_attributes(params, :post, :is_resolved, :reason)
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
module ApiMethods
def api_attributes
attributes = super + [:category]
attributes -= [:creator_id] unless Pundit.policy!([CurrentUser.user, nil], self).can_view_flagger?
attributes
end
end
extend SearchMethods
include ApiMethods
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
return if is_deletion
if creator.can_approve_posts?
# do nothing
elsif creator.created_at > 1.week.ago
errors[:creator] << "cannot flag within the first week of sign up"
elsif creator.is_gold? && flag_count_for_creator >= 10
errors[:creator] << "can flag 10 posts a day"
elsif !creator.is_gold? && flag_count_for_creator >= 1
errors[:creator] << "can flag 1 post a day"
end
flag = post.flags.in_cooldown.last
if flag.present?
errors[:post] << "cannot be flagged more than once every #{COOLDOWN_PERIOD.inspect} (last flagged: #{flag.created_at.to_s(:long)})"
end
end
def validate_post
errors[:post] << "is pending and cannot be flagged" if post.is_pending? && !is_deletion
errors[:post] << "is locked and cannot be flagged" if post.is_status_locked?
errors[:post] << "is deleted" if post.is_deleted?
end
def resolve!
update_column(:is_resolved, true)
end
def flag_count_for_creator
creator.post_flags.recent.count
end
def uploader_id
post.uploader_id
end
def self.available_includes
[:post]
end
end