mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 18:41:07 +08:00
This reverts commit 37e6e3be7f3f3ff94baf12230289e38e8cfcc803.
This commit is contained in:
@ -11,7 +11,6 @@ class Chat::ChatMessageCreator
|
||||
def initialize(
|
||||
chat_channel:,
|
||||
in_reply_to_id: nil,
|
||||
thread_id: nil,
|
||||
user:,
|
||||
content:,
|
||||
staged_id: nil,
|
||||
@ -21,15 +20,11 @@ class Chat::ChatMessageCreator
|
||||
@chat_channel = chat_channel
|
||||
@user = user
|
||||
@guardian = Guardian.new(user)
|
||||
|
||||
# NOTE: We confirm this exists and the user can access it in the ChatController,
|
||||
# but in future the checks should be here
|
||||
@in_reply_to_id = in_reply_to_id
|
||||
@content = content
|
||||
@staged_id = staged_id
|
||||
@incoming_chat_webhook = incoming_chat_webhook
|
||||
@upload_ids = upload_ids || []
|
||||
@thread_id = thread_id
|
||||
@error = nil
|
||||
|
||||
@chat_message =
|
||||
@ -47,13 +42,9 @@ class Chat::ChatMessageCreator
|
||||
validate_channel_status!
|
||||
uploads = get_uploads
|
||||
validate_message!(has_uploads: uploads.any?)
|
||||
validate_reply_chain!
|
||||
validate_existing_thread!
|
||||
@chat_message.thread_id = @existing_thread&.id
|
||||
@chat_message.cook
|
||||
@chat_message.save!
|
||||
create_chat_webhook_event
|
||||
create_thread
|
||||
@chat_message.attach_uploads(uploads)
|
||||
ChatDraft.where(user_id: @user.id, chat_channel_id: @chat_channel.id).destroy_all
|
||||
ChatPublisher.publish_new!(@chat_channel, @chat_message, @staged_id)
|
||||
@ -90,56 +81,6 @@ class Chat::ChatMessageCreator
|
||||
end
|
||||
end
|
||||
|
||||
def validate_reply_chain!
|
||||
return if @in_reply_to_id.blank?
|
||||
|
||||
@root_message_id = DB.query_single(<<~SQL).last
|
||||
WITH RECURSIVE root_message_finder( id, in_reply_to_id )
|
||||
AS (
|
||||
-- start with the message id we want to find the parents of
|
||||
SELECT id, in_reply_to_id
|
||||
FROM chat_messages
|
||||
WHERE id = #{@in_reply_to_id}
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- get the chain of direct parents of the message
|
||||
-- following in_reply_to_id
|
||||
SELECT cm.id, cm.in_reply_to_id
|
||||
FROM root_message_finder rm
|
||||
JOIN chat_messages cm ON rm.in_reply_to_id = cm.id
|
||||
)
|
||||
SELECT id FROM root_message_finder
|
||||
|
||||
-- this makes it so only the root parent ID is returned, we can
|
||||
-- exclude this to return all parents in the chain
|
||||
WHERE in_reply_to_id IS NULL;
|
||||
SQL
|
||||
|
||||
raise StandardError.new(I18n.t("chat.errors.root_message_not_found")) if @root_message_id.blank?
|
||||
|
||||
@root_message = ChatMessage.with_deleted.find_by(id: @root_message_id)
|
||||
raise StandardError.new(I18n.t("chat.errors.root_message_not_found")) if @root_message&.trashed?
|
||||
end
|
||||
|
||||
def validate_existing_thread!
|
||||
return if @thread_id.blank?
|
||||
@existing_thread = ChatThread.find(@thread_id)
|
||||
|
||||
if @existing_thread.channel_id != @chat_channel.id
|
||||
raise StandardError.new(I18n.t("chat.errors.thread_invalid_for_channel"))
|
||||
end
|
||||
|
||||
reply_to_thread_mismatch =
|
||||
@chat_message.in_reply_to&.thread_id &&
|
||||
@chat_message.in_reply_to.thread_id != @existing_thread.id
|
||||
root_message_has_no_thread = @root_message && @root_message.thread_id.blank?
|
||||
root_message_thread_mismatch = @root_message && @root_message.thread_id != @existing_thread.id
|
||||
if reply_to_thread_mismatch || root_message_has_no_thread || root_message_thread_mismatch
|
||||
raise StandardError.new(I18n.t("chat.errors.thread_does_not_match_parent"))
|
||||
end
|
||||
end
|
||||
|
||||
def validate_message!(has_uploads:)
|
||||
@chat_message.validate_message(has_uploads: has_uploads)
|
||||
if @chat_message.errors.present?
|
||||
@ -160,39 +101,4 @@ class Chat::ChatMessageCreator
|
||||
|
||||
Upload.where(id: @upload_ids, user_id: @user.id)
|
||||
end
|
||||
|
||||
def create_thread
|
||||
return if @in_reply_to_id.blank?
|
||||
return if @chat_message.thread_id.present?
|
||||
|
||||
thread =
|
||||
@root_message.thread ||
|
||||
ChatThread.create!(
|
||||
original_message: @chat_message.in_reply_to,
|
||||
original_message_user: @chat_message.in_reply_to.user,
|
||||
channel: @chat_message.chat_channel,
|
||||
)
|
||||
|
||||
# NOTE: We intentionally do not try to correct thread IDs within the chain
|
||||
# if they are incorrect, and only set the thread ID of messages where the
|
||||
# thread ID is NULL. In future we may want some sync/background job to correct
|
||||
# any inconsistencies.
|
||||
DB.exec(<<~SQL)
|
||||
WITH RECURSIVE thread_updater AS (
|
||||
SELECT cm.id, cm.in_reply_to_id
|
||||
FROM chat_messages cm
|
||||
WHERE cm.in_reply_to_id IS NULL AND cm.id = #{@root_message_id}
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT cm.id, cm.in_reply_to_id
|
||||
FROM chat_messages cm
|
||||
JOIN thread_updater ON cm.in_reply_to_id = thread_updater.id
|
||||
)
|
||||
UPDATE chat_messages
|
||||
SET thread_id = #{thread.id}
|
||||
FROM thread_updater
|
||||
WHERE thread_id IS NULL AND chat_messages.id = thread_updater.id
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
@ -16,19 +16,6 @@
|
||||
# all of the references associated to a chat message (e.g. reactions, bookmarks,
|
||||
# notifications, revisions, mentions, uploads) will be updated to the new
|
||||
# message IDs via a moved_chat_messages temporary table.
|
||||
#
|
||||
# Reply chains are a little complex. No reply chains are preserved when moving
|
||||
# messages into a new channel. Remaining messages that referenced moved ones
|
||||
# have their in_reply_to_id cleared so the data makes sense.
|
||||
#
|
||||
# Threads are even more complex. No threads are preserved when moving messages
|
||||
# into a new channel, they end up as just a flat series of messages that are
|
||||
# not in a chain. If the original message of a thread and N other messages
|
||||
# in that thread, then any messages left behind just get placed into a new
|
||||
# thread. Message moving will be disabled in the thread UI while
|
||||
# enable_experimental_chat_threaded_discussions is present, its too complicated
|
||||
# to have end users reason about for now, and we may want a standalone
|
||||
# "Move Thread" UI later on.
|
||||
class Chat::MessageMover
|
||||
class NoMessagesFound < StandardError
|
||||
end
|
||||
@ -64,8 +51,6 @@ class Chat::MessageMover
|
||||
bulk_insert_movement_metadata
|
||||
update_references
|
||||
delete_source_messages
|
||||
update_reply_references
|
||||
update_thread_references
|
||||
end
|
||||
|
||||
add_moved_placeholder(destination_channel, moved_messages.first)
|
||||
@ -75,10 +60,7 @@ class Chat::MessageMover
|
||||
private
|
||||
|
||||
def find_messages(message_ids, channel)
|
||||
ChatMessage
|
||||
.includes(thread: %i[original_message original_message_user])
|
||||
.where(id: message_ids, chat_channel_id: channel.id)
|
||||
.order("created_at ASC, id ASC")
|
||||
ChatMessage.where(id: message_ids, chat_channel_id: channel.id).order("created_at ASC, id ASC")
|
||||
end
|
||||
|
||||
def create_temp_table
|
||||
@ -172,13 +154,7 @@ class Chat::MessageMover
|
||||
end
|
||||
|
||||
def delete_source_messages
|
||||
# We do this so @source_messages is not nulled out, which is the
|
||||
# case when using update_all here.
|
||||
DB.exec(<<~SQL, source_message_ids: @source_message_ids, deleted_by_id: @acting_user.id)
|
||||
UPDATE chat_messages
|
||||
SET deleted_at = NOW(), deleted_by_id = :deleted_by_id
|
||||
WHERE id IN (:source_message_ids)
|
||||
SQL
|
||||
@source_messages.update_all(deleted_at: Time.zone.now, deleted_by_id: @acting_user.id)
|
||||
ChatPublisher.publish_bulk_delete!(@source_channel, @source_message_ids)
|
||||
end
|
||||
|
||||
@ -196,41 +172,4 @@ class Chat::MessageMover
|
||||
),
|
||||
)
|
||||
end
|
||||
|
||||
def update_reply_references
|
||||
DB.exec(<<~SQL, deleted_reply_to_ids: @source_message_ids)
|
||||
UPDATE chat_messages
|
||||
SET in_reply_to_id = NULL
|
||||
WHERE in_reply_to_id IN (:deleted_reply_to_ids)
|
||||
SQL
|
||||
end
|
||||
|
||||
def update_thread_references
|
||||
threads_to_update = []
|
||||
@source_messages
|
||||
.select { |message| message.thread_id.present? }
|
||||
.each do |message_with_thread|
|
||||
# If one of the messages we are moving is the original message in a thread,
|
||||
# then all the remaining messages for that thread must be moved to a new one,
|
||||
# otherwise they will be pointing to a thread in a different channel.
|
||||
if message_with_thread.thread.original_message_id == message_with_thread.id
|
||||
threads_to_update << message_with_thread.thread
|
||||
end
|
||||
end
|
||||
|
||||
threads_to_update.each do |thread|
|
||||
# NOTE: We may want to do something with the old empty thread at some
|
||||
# point, maybe close or delete it. For now just leave it dangling.
|
||||
next if thread.chat_messages.empty?
|
||||
|
||||
original_message = thread.chat_messages.first
|
||||
new_thread =
|
||||
ChatThread.create(
|
||||
original_message: original_message,
|
||||
original_message_user: original_message.user,
|
||||
channel: @source_channel,
|
||||
)
|
||||
thread.chat_messages.update_all(thread_id: new_thread.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user