143 lines
4.0 KiB
Ruby
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
|