discourse/app/models/post_mover.rb

127 lines
2.9 KiB
Ruby

class PostMover
attr_reader :original_topic, :destination_topic, :user, :post_ids
def self.move_types
@move_types ||= Enum.new(:new_topic, :existing_topic)
end
def initialize(original_topic, user, post_ids)
@original_topic = original_topic
@user = user
@post_ids = post_ids
end
def to_topic(id)
@move_type = PostMover.move_types[:existing_topic]
Topic.transaction do
move_posts_to Topic.find_by_id(id)
end
end
def to_new_topic(title)
@move_type = PostMover.move_types[:new_topic]
Topic.transaction do
move_posts_to Topic.create!(
user: user,
title: title,
category: original_topic.category
)
end
end
private
def move_posts_to(topic)
Guardian.new(user).ensure_can_see! topic
@destination_topic = topic
move_each_post
notify_users_that_posts_have_moved
update_statistics
update_user_actions
destination_topic
end
def move_each_post
with_max_post_number do |max_post_number|
posts.each_with_index do |post, offset|
post.is_first_post? ? copy(post) : move(post, offset + max_post_number)
end
end
end
def copy(post)
PostCreator.create(
post.user,
raw: post.raw,
topic_id: destination_topic.id,
acting_user: user
)
end
def move(post, post_number)
@first_post_number_moved ||= post.post_number
Post.where(id: post.id, topic_id: original_topic.id).update_all(
[
['post_number = :post_number',
'topic_id = :topic_id',
'sort_order = :post_number'
].join(', '),
post_number: post_number,
topic_id: destination_topic.id
]
)
# Move any links from the post to the new topic
post.topic_links.update_all(topic_id: destination_topic.id)
end
def update_statistics
destination_topic.update_statistics
original_topic.update_statistics
end
def update_user_actions
UserAction.synchronize_target_topic_ids(posts.map(&:id))
end
def notify_users_that_posts_have_moved
enqueue_notification_job
create_moderator_post_in_original_topic
end
def enqueue_notification_job
Jobs.enqueue(
:notify_moved_posts,
post_ids: post_ids,
moved_by_id: user.id
)
end
def create_moderator_post_in_original_topic
original_topic.add_moderator_post(
user,
I18n.t("move_posts.#{PostMover.move_types[@move_type].to_s}_moderator_post",
count: post_ids.count,
topic_link: "[#{destination_topic.title}](#{destination_topic.url})"),
post_number: @first_post_number_moved
)
end
def with_max_post_number
yield destination_topic.max_post_number + 1
end
def posts
@posts ||= begin
Post.where(id: post_ids).order(:created_at).tap do |posts|
raise Discourse::InvalidParameters.new(:post_ids) if posts.empty?
end
end
end
end