Files
danbooru/app/models/bulk_update_request.rb
evazion d136a12a65 Fix #4359: Allow builders to move small (artist) tags manually.
Allow builders to approve artist alias BURs. The BUR must contain only
artist aliases or mass updates and each artist must have less than 100
posts.
2020-05-11 00:37:37 -05:00

159 lines
4.6 KiB
Ruby

class BulkUpdateRequest < ApplicationRecord
attr_accessor :title
attr_accessor :reason
attr_reader :skip_secondary_validations
belongs_to :user
belongs_to :forum_topic, optional: true
belongs_to :forum_post, optional: true
belongs_to :approver, optional: true, class_name: "User"
before_validation :normalize_text
before_validation :update_tags
validates_presence_of :reason, on: :create
validates_presence_of :script
validates_presence_of :title, if: ->(rec) {rec.forum_topic_id.blank?}
validates_presence_of :forum_topic, if: ->(rec) {rec.forum_topic_id.present?}
validates_inclusion_of :status, :in => %w(pending approved rejected)
validate :validate_script, :on => :create
after_create :create_forum_topic
scope :pending_first, -> { order(Arel.sql("(case status when 'pending' then 0 when 'approved' then 1 else 2 end)")) }
scope :pending, -> {where(status: "pending")}
scope :approved, -> { where(status: "approved") }
scope :rejected, -> { where(status: "rejected") }
scope :has_topic, -> { where.not(forum_topic: nil) }
scope :expired, -> {where("created_at < ?", TagRelationship::EXPIRY.days.ago)}
scope :old, -> {where("created_at between ? and ?", TagRelationship::EXPIRY.days.ago, TagRelationship::EXPIRY_WARNING.days.ago)}
module SearchMethods
def default_order
pending_first.order(id: :desc)
end
def search(params = {})
q = super
q = q.search_attributes(params, :user, :approver, :forum_topic_id, :forum_post_id, :script, :tags)
q = q.text_attribute_matches(:script, params[:script_matches])
if params[:status].present?
q = q.where(status: params[:status].split(","))
end
params[:order] ||= "status_desc"
case params[:order]
when "id_desc"
q = q.order(id: :desc)
when "id_asc"
q = q.order(id: :asc)
when "updated_at_desc"
q = q.order(updated_at: :desc)
when "updated_at_asc"
q = q.order(updated_at: :asc)
else
q = q.apply_default_order(params)
end
q
end
end
module ApprovalMethods
def forum_updater
@forum_updater ||= begin
post = if forum_topic
forum_post || forum_topic.forum_posts.first
else
nil
end
ForumUpdater.new(forum_topic, forum_post: post)
end
end
def approve!(approver)
transaction do
CurrentUser.scoped(approver) do
processor.process!(approver)
update!(status: "approved", approver: approver, skip_secondary_validations: true)
forum_updater.update("The #{bulk_update_request_link} (forum ##{forum_post.id}) has been approved by @#{approver.name}.")
end
end
rescue BulkUpdateRequestProcessor::Error => x
self.approver = approver
CurrentUser.scoped(approver) do
forum_updater.update("The #{bulk_update_request_link} (forum ##{forum_post.id}) has failed: #{x}")
end
end
def create_forum_topic
CurrentUser.as(user) do
body = "[bur:#{id}]\n\n#{reason}"
self.forum_topic = ForumTopic.create(title: title, category_id: 1, creator: user) unless forum_topic.present?
self.forum_post = forum_topic.forum_posts.create(body: body, creator: user) unless forum_post.present?
save
end
end
def reject!(rejector = User.system)
transaction do
update!(status: "rejected")
forum_updater.update("The #{bulk_update_request_link} (forum ##{forum_post.id}) has been rejected by @#{rejector.name}.")
end
end
def bulk_update_request_link
%{"bulk update request ##{id}":/bulk_update_requests?search%5Bid%5D=#{id}}
end
end
module ValidationMethods
def validate_script
processor.validate!
rescue BulkUpdateRequestProcessor::Error => e
errors[:base] << e.message
end
end
extend SearchMethods
include ApprovalMethods
include ValidationMethods
def normalize_text
self.script = script.downcase
end
def update_tags
self.tags = processor.affected_tags
end
def skip_secondary_validations=(v)
@skip_secondary_validations = v.to_s.truthy?
end
def processor
@processor ||= BulkUpdateRequestProcessor.new(script, forum_topic_id: forum_topic_id, skip_secondary_validations: skip_secondary_validations)
end
def is_tag_move_allowed?
processor.is_tag_move_allowed?
end
def is_pending?
status == "pending"
end
def is_approved?
status == "approved"
end
def is_rejected?
status == "rejected"
end
def self.available_includes
[:user, :forum_topic, :forum_post, :approver]
end
end