2024-02-25 12:15:55 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-06-14 22:27:53 -04:00
|
|
|
class PostFlag < ApplicationRecord
|
2019-08-02 18:25:00 -04:00
|
|
|
class Error < Exception;
|
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2019-09-04 02:06:30 -04:00
|
|
|
COOLDOWN_PERIOD = 1.days
|
2020-02-20 01:19:15 -05:00
|
|
|
MAPPED_REASONS = Danbooru.config.flag_reasons.map { |i| [i[:name], i[:reason]] }.to_h
|
2017-05-04 17:40:09 -04:00
|
|
|
|
2018-06-15 20:11:06 -04:00
|
|
|
belongs_to_creator :class_name => "User"
|
2019-06-04 08:56:20 -04:00
|
|
|
user_status_counter :post_flag_count
|
2011-03-28 18:48:02 -04:00
|
|
|
belongs_to :post
|
2018-06-15 20:11:06 -04:00
|
|
|
validate :validate_creator_is_not_limited, on: :create
|
2017-05-04 15:58:03 -04:00
|
|
|
validate :validate_post
|
2019-08-02 18:25:00 -04:00
|
|
|
validate :validate_reason
|
|
|
|
validate :update_reason, on: :create
|
2019-09-05 08:59:51 -04:00
|
|
|
validates :reason, presence: true
|
2011-03-29 13:56:30 -04:00
|
|
|
before_save :update_post
|
2022-01-06 07:44:30 -05:00
|
|
|
after_create :create_post_event
|
2020-03-10 16:37:30 -04:00
|
|
|
after_commit :index_post
|
2013-01-10 17:45:52 -05:00
|
|
|
|
2020-02-20 01:19:15 -05:00
|
|
|
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) }
|
2019-08-02 18:25:00 -04:00
|
|
|
|
2023-01-26 15:46:20 -05:00
|
|
|
attr_accessor :parent_id, :reason_name, :force_flag
|
2017-05-04 17:40:09 -04:00
|
|
|
|
2013-01-10 17:45:52 -05:00
|
|
|
module SearchMethods
|
2017-03-03 20:30:12 -05:00
|
|
|
def post_tags_match(query)
|
2023-02-21 16:50:17 -05:00
|
|
|
where(post_id: Post.tag_match_sql(query))
|
2017-03-03 20:30:12 -05:00
|
|
|
end
|
|
|
|
|
2013-01-10 17:45:52 -05:00
|
|
|
def resolved
|
|
|
|
where("is_resolved = ?", true)
|
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2013-01-10 17:45:52 -05:00
|
|
|
def unresolved
|
|
|
|
where("is_resolved = ?", false)
|
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2013-08-13 13:33:25 -04:00
|
|
|
def for_creator(user_id)
|
|
|
|
where("creator_id = ?", user_id)
|
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2013-01-10 17:45:52 -05:00
|
|
|
def search(params)
|
2017-12-17 17:58:34 -05:00
|
|
|
q = super
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2018-08-31 20:23:25 -04:00
|
|
|
q = q.attribute_matches(:reason, params[:reason_matches])
|
2023-06-11 05:38:00 -04:00
|
|
|
q = q.attribute_matches(:is_resolved, params[:is_resolved])
|
2014-11-30 16:10:17 -05:00
|
|
|
|
2023-08-03 16:01:53 -04:00
|
|
|
q = q.where_user(:creator_id, :creator, params) do |condition, user_ids|
|
|
|
|
condition.where.not(creator_id: user_ids.reject { |user_id| CurrentUser.can_view_flagger?(user_id) })
|
2013-01-11 17:13:55 -05:00
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2013-02-19 12:27:17 -05:00
|
|
|
if params[:post_id].present?
|
2017-05-14 13:38:39 -04:00
|
|
|
q = q.where(post_id: params[:post_id].split(",").map(&:to_i))
|
2013-01-10 17:45:52 -05:00
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2017-03-03 20:30:12 -05:00
|
|
|
if params[:post_tags_match].present?
|
|
|
|
q = q.post_tags_match(params[:post_tags_match])
|
|
|
|
end
|
|
|
|
|
2021-10-30 13:46:55 -04:00
|
|
|
if params[:ip_addr].present?
|
|
|
|
q = q.where("creator_ip_addr <<= ?", params[:ip_addr])
|
|
|
|
end
|
|
|
|
|
2023-05-30 12:30:41 -04:00
|
|
|
case params[:type]
|
2023-06-03 06:57:11 -04:00
|
|
|
when "flag"
|
|
|
|
q = q.where(is_deletion: false)
|
2023-05-30 12:30:41 -04:00
|
|
|
when "deletion"
|
|
|
|
q = q.where(is_deletion: true)
|
|
|
|
end
|
|
|
|
|
2023-07-07 08:32:57 -04:00
|
|
|
q.apply_basic_order(params)
|
2013-01-10 17:45:52 -05:00
|
|
|
end
|
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2016-08-22 13:41:34 -04:00
|
|
|
module ApiMethods
|
|
|
|
def hidden_attributes
|
2016-10-27 17:53:25 -04:00
|
|
|
list = super
|
2017-11-07 23:02:03 -05:00
|
|
|
unless CurrentUser.can_view_flagger_on_post?(self)
|
2016-08-26 14:18:11 -04:00
|
|
|
list += [:creator_id]
|
|
|
|
end
|
|
|
|
super + list
|
2016-08-22 13:41:34 -04:00
|
|
|
end
|
2023-05-30 12:30:41 -04:00
|
|
|
|
|
|
|
def method_attributes
|
|
|
|
super + [:type]
|
|
|
|
end
|
2016-08-22 13:41:34 -04:00
|
|
|
end
|
|
|
|
|
2013-01-10 17:45:52 -05:00
|
|
|
extend SearchMethods
|
2016-08-22 13:41:34 -04:00
|
|
|
include ApiMethods
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2023-05-30 12:30:41 -04:00
|
|
|
def type
|
|
|
|
return :deletion if is_deletion
|
2023-06-03 06:57:11 -04:00
|
|
|
:flag
|
2023-05-30 12:30:41 -04:00
|
|
|
end
|
|
|
|
|
2011-03-29 13:56:30 -04:00
|
|
|
def update_post
|
2013-02-22 21:13:11 -05:00
|
|
|
post.update_column(:is_flagged, true) unless post.is_flagged?
|
2020-03-10 16:37:30 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def index_post
|
2020-03-10 14:38:04 -04:00
|
|
|
post.update_index
|
2011-03-29 13:56:30 -04:00
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2011-03-28 18:48:02 -04:00
|
|
|
def validate_creator_is_not_limited
|
2017-05-17 23:49:52 -04:00
|
|
|
return if is_deletion
|
|
|
|
|
2018-12-11 19:41:20 -05:00
|
|
|
if creator.no_flagging?
|
2021-02-07 20:16:52 -05:00
|
|
|
errors.add(:creator, "cannot flag posts")
|
2018-12-11 19:41:20 -05:00
|
|
|
end
|
|
|
|
|
2019-08-01 19:03:13 -04:00
|
|
|
return if creator.is_janitor?
|
|
|
|
|
2019-09-04 02:06:30 -04:00
|
|
|
allowed = creator.can_post_flag_with_reason
|
|
|
|
if allowed != true
|
|
|
|
errors.add(:creator, User.throttle_reason(allowed))
|
|
|
|
return false
|
2011-03-28 18:48:02 -04:00
|
|
|
end
|
2017-05-04 17:40:09 -04:00
|
|
|
|
2020-09-29 15:11:31 -04:00
|
|
|
flag = post.flags.in_cooldown.last
|
2017-05-04 17:40:09 -04:00
|
|
|
if flag.present?
|
2022-10-10 07:26:12 -04:00
|
|
|
errors.add(:post, "cannot be flagged more than once every #{COOLDOWN_PERIOD.inspect} (last flagged: #{flag.created_at.to_fs(:long)})")
|
2017-05-04 17:40:09 -04:00
|
|
|
end
|
2011-03-28 18:48:02 -04:00
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2017-05-17 23:49:52 -04:00
|
|
|
def validate_post
|
2023-03-23 14:19:19 -04:00
|
|
|
errors.add(:post, "is locked and cannot be flagged") if post.is_status_locked? && !(creator.is_admin? || force_flag)
|
2021-02-07 20:16:52 -05:00
|
|
|
errors.add(:post, "is deleted") if post.is_deleted?
|
2017-05-17 23:49:52 -04:00
|
|
|
end
|
|
|
|
|
2019-08-02 18:25:00 -04:00
|
|
|
def validate_reason
|
|
|
|
case reason_name
|
2019-08-02 18:39:28 -04:00
|
|
|
when 'deletion'
|
|
|
|
# You're probably looking at this line as you get this validation failure
|
2021-01-10 19:38:09 -05:00
|
|
|
errors.add(:reason, "is not one of the available choices") unless is_deletion
|
2019-08-02 18:25:00 -04:00
|
|
|
when 'inferior'
|
2020-02-20 01:19:15 -05:00
|
|
|
unless parent_post.present?
|
2021-01-10 19:38:09 -05:00
|
|
|
errors.add(:parent_id, "must exist")
|
2020-02-20 01:19:15 -05:00
|
|
|
return false
|
|
|
|
end
|
2022-08-20 12:19:08 -04:00
|
|
|
errors.add(:parent_id, "cannot be set to the post being flagged") if parent_post.id == post.id
|
|
|
|
when 'uploading_guidelines'
|
2024-09-29 16:08:45 -04:00
|
|
|
errors.add(:reason, "cannot be used. The post is grandfathered") unless post.flaggable_for_guidelines?
|
2019-08-02 18:25:00 -04:00
|
|
|
else
|
2021-02-07 20:16:52 -05:00
|
|
|
errors.add(:reason, "is not one of the available choices") unless MAPPED_REASONS.key?(reason_name)
|
2019-08-02 18:25:00 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_reason
|
|
|
|
case reason_name
|
2019-08-02 18:39:28 -04:00
|
|
|
when 'deletion'
|
|
|
|
# NOP
|
2019-08-02 18:25:00 -04:00
|
|
|
when 'inferior'
|
2020-02-20 01:19:15 -05:00
|
|
|
return unless parent_post
|
2020-10-09 16:55:39 -04:00
|
|
|
old_parent_id = post.parent_id
|
2019-08-02 18:25:00 -04:00
|
|
|
post.update_column(:parent_id, parent_post.id)
|
2022-04-03 07:52:25 -04:00
|
|
|
# Fix handling when parent/child is currently inverted. See #258
|
|
|
|
if parent_post.parent_id == post.id
|
|
|
|
parent_post.update_column(:parent_id, nil)
|
|
|
|
post.update_has_children_flag
|
|
|
|
end
|
2020-10-09 16:55:39 -04:00
|
|
|
# Update parent flags on parent post
|
|
|
|
parent_post.update_has_children_flag
|
|
|
|
# Update parent flags on old parent post, if it exists
|
2023-12-03 09:36:37 -05:00
|
|
|
Post.find(old_parent_id).update_has_children_flag if old_parent_id && parent_post.id != old_parent_id
|
2019-08-02 18:25:00 -04:00
|
|
|
self.reason = "Inferior version/duplicate of post ##{parent_post.id}"
|
|
|
|
else
|
|
|
|
self.reason = MAPPED_REASONS[reason_name]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-03-30 14:13:42 -04:00
|
|
|
def resolve!
|
2011-07-16 19:20:02 -04:00
|
|
|
update_column(:is_resolved, true)
|
2011-03-30 14:13:42 -04:00
|
|
|
end
|
2013-03-19 08:10:10 -04:00
|
|
|
|
2019-08-02 18:25:00 -04:00
|
|
|
def parent_post
|
2020-02-20 01:19:15 -05:00
|
|
|
@parent_post ||= begin
|
|
|
|
Post.where('id = ?', parent_id).first
|
|
|
|
rescue
|
|
|
|
nil
|
|
|
|
end
|
2019-08-02 18:25:00 -04:00
|
|
|
end
|
2022-01-06 07:44:30 -05:00
|
|
|
|
|
|
|
def create_post_event
|
|
|
|
# Deletions also create flags, but they create a deletion event instead
|
2022-01-08 20:05:11 -05:00
|
|
|
PostEvent.add(post.id, CurrentUser.user, :flag_created, { reason: reason }) unless is_deletion
|
2022-01-06 07:44:30 -05:00
|
|
|
end
|
2011-03-28 18:48:02 -04:00
|
|
|
end
|