FEATURE: Copy thread messages when copying thread OP (#32139)

This introduces functionality to chat transcripts. If
you select _only_ a thread's OP and press the Copy button,
we will now copy the OP plus all of the thread's replies
into the transcript.

This is being done to make it easier to copy all the context
of a thread easily. The old way of selecting only some messages
inside a thread still works too.

This commit also unskips and refactors some transcript specs.
This commit is contained in:
Martin Brennan
2025-04-04 13:45:37 +10:00
committed by GitHub
parent 568ccdc19d
commit 3d6b7e2574
2 changed files with 122 additions and 36 deletions

View File

@ -166,9 +166,17 @@ module Chat
previous_message = nil previous_message = nil
rendered_markdown = [] rendered_markdown = []
rendered_thread_markdown = [] rendered_thread_markdown = []
all_messages_same_user = messages.count(:user_id) == 1
threading_enabled = @channel.threading_enabled? threading_enabled = @channel.threading_enabled?
thread_id = threading_enabled ? messages.first.thread_id : nil thread_id = threading_enabled ? messages.first.thread_id : nil
thread = Chat::Thread.find_by(id: thread_id) if thread_id.present? && threading_enabled
# We are getting only the OP of the thread, let's expand it to
# include all the replies for the thread.
if messages.count == 1 && thread&.original_message_id == messages.first.id
@messages = [messages.first] + messages.first.thread.replies
end
all_messages_same_user = messages.map(&:user_id).uniq.count == 1
open_bbcode_tag = open_bbcode_tag =
TranscriptBBCode.new( TranscriptBBCode.new(

View File

@ -152,7 +152,7 @@ describe Chat::TranscriptService do
MARKDOWN MARKDOWN
end end
xit "generates the correct markdown for messages that are in reply to other messages" do it "generates the correct markdown for messages that are in reply to other messages" do
channel.update!(threading_enabled: false) channel.update!(threading_enabled: false)
thread = Fabricate(:chat_thread, channel: channel) thread = Fabricate(:chat_thread, channel: channel)
@ -286,15 +286,18 @@ describe Chat::TranscriptService do
MARKDOWN MARKDOWN
end end
xit "generates reaction data for threaded messages" do it "generates reaction data for threaded messages" do
thread = Fabricate(:chat_thread, channel: channel) thread =
thread_om =
Fabricate( Fabricate(
:chat_message, :chat_thread,
user: user1, channel: channel,
chat_channel: channel, original_message:
thread: thread, Fabricate(
message: "an extremely insightful response :)", :chat_message,
chat_channel: channel,
user: user1,
message: "an extremely insightful response :)",
),
) )
thread_reply_1 = thread_reply_1 =
Fabricate( Fabricate(
@ -314,7 +317,7 @@ describe Chat::TranscriptService do
) )
Chat::MessageReaction.create!( Chat::MessageReaction.create!(
chat_message: thread_om, chat_message: thread.original_message,
user: Fabricate(:user, username: "bjorn"), user: Fabricate(:user, username: "bjorn"),
emoji: "heart", emoji: "heart",
) )
@ -337,13 +340,13 @@ describe Chat::TranscriptService do
thread.update!(replies_count: 2) thread.update!(replies_count: 2)
rendered = rendered =
service( service(
[thread_om.id, thread_reply_1.id, thread_reply_2.id], [thread.original_message.id, thread_reply_1.id, thread_reply_2.id],
opts: { opts: {
include_reactions: true, include_reactions: true,
}, },
).generate_markdown ).generate_markdown
expect(rendered).to eq(<<~MARKDOWN) expect(rendered).to eq(<<~MARKDOWN)
[chat quote="martinchat;#{thread_om.id};#{thread_om.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" reactions="heart:bjorn" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"] [chat quote="martinchat;#{thread.original_message.id};#{thread.original_message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" reactions="heart:bjorn" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"]
an extremely insightful response :) an extremely insightful response :)
[chat quote="brucechat;#{thread_reply_1.id};#{thread_reply_1.created_at.iso8601}" chained="true" reactions="+1:hvitserk;heart:sigurd"] [chat quote="brucechat;#{thread_reply_1.id};#{thread_reply_1.created_at.iso8601}" chained="true" reactions="+1:hvitserk;heart:sigurd"]
@ -358,15 +361,13 @@ describe Chat::TranscriptService do
MARKDOWN MARKDOWN
end end
xit "generates a chat transcript for threaded messages" do it "generates a chat transcript for threaded messages" do
thread = Fabricate(:chat_thread, channel: channel) thread =
thread_om =
Fabricate( Fabricate(
:chat_message, :chat_thread,
chat_channel: channel, channel: channel,
user: user1, original_message:
thread: thread, Fabricate(:chat_message, chat_channel: channel, user: user1, message: "reply to me!"),
message: "reply to me!",
) )
thread_reply_1 = thread_reply_1 =
Fabricate(:chat_message, chat_channel: channel, user: user2, thread: thread, message: "done") Fabricate(:chat_message, chat_channel: channel, user: user2, thread: thread, message: "done")
@ -379,9 +380,10 @@ describe Chat::TranscriptService do
message: "thanks", message: "thanks",
) )
thread.update!(replies_count: 2) thread.update!(replies_count: 2)
rendered = service([thread_om.id, thread_reply_1.id, thread_reply_2.id]).generate_markdown rendered =
service([thread.original_message.id, thread_reply_1.id, thread_reply_2.id]).generate_markdown
expect(rendered).to eq(<<~MARKDOWN) expect(rendered).to eq(<<~MARKDOWN)
[chat quote="martinchat;#{thread_om.id};#{thread_om.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"] [chat quote="martinchat;#{thread.original_message.id};#{thread.original_message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"]
reply to me! reply to me!
[chat quote="brucechat;#{thread_reply_1.id};#{thread_reply_1.created_at.iso8601}" chained="true"] [chat quote="brucechat;#{thread_reply_1.id};#{thread_reply_1.created_at.iso8601}" chained="true"]
@ -396,15 +398,83 @@ describe Chat::TranscriptService do
MARKDOWN MARKDOWN
end end
xit "doesn't add thread info for threads with no replies" do it "includes all of the thread replies if only one message is supplied, and it is the thread OP" do
thread = Fabricate(:chat_thread, channel: channel) thread =
thread_om = Fabricate(
:chat_thread,
channel: channel,
original_message:
Fabricate(:chat_message, chat_channel: channel, user: user1, message: "reply to me!"),
)
thread_reply_1 =
Fabricate(:chat_message, chat_channel: channel, user: user2, thread: thread, message: "done")
thread_reply_2 =
Fabricate( Fabricate(
:chat_message, :chat_message,
chat_channel: channel, chat_channel: channel,
user: user1, user: user1,
thread: thread, thread: thread,
message: "has a reply", message: "thanks",
)
thread.update!(original_message_id: thread.original_message.id, replies_count: 2)
rendered = service([thread.original_message.id]).generate_markdown
expect(rendered).to eq(<<~MARKDOWN)
[chat quote="martinchat;#{thread.original_message.id};#{thread.original_message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"]
reply to me!
[chat quote="brucechat;#{thread_reply_1.id};#{thread_reply_1.created_at.iso8601}" chained="true"]
done
[/chat]
[chat quote="martinchat;#{thread_reply_2.id};#{thread_reply_2.created_at.iso8601}" chained="true"]
thanks
[/chat]
[/chat]
MARKDOWN
end
it "does not chain replies if the thread messages are all by the same user" do
thread =
Fabricate(
:chat_thread,
channel: channel,
original_message:
Fabricate(:chat_message, chat_channel: channel, user: user1, message: "reply to me!"),
)
thread_reply_1 =
Fabricate(:chat_message, chat_channel: channel, user: user1, thread: thread, message: "done")
thread_reply_2 =
Fabricate(
:chat_message,
chat_channel: channel,
user: user1,
thread: thread,
message: "thanks",
)
thread.update!(original_message_id: thread.original_message.id, replies_count: 2)
rendered = service([thread.original_message.id]).generate_markdown
expect(rendered).to eq(<<~MARKDOWN)
[chat quote="martinchat;#{thread.original_message.id};#{thread.original_message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"]
reply to me!
[chat quote="martinchat;#{thread_reply_1.id};#{thread_reply_1.created_at.iso8601}"]
done
thanks
[/chat]
[/chat]
MARKDOWN
end
it "doesn't add thread info for threads with no replies" do
thread =
Fabricate(
:chat_thread,
channel: channel,
original_message:
Fabricate(:chat_message, chat_channel: channel, user: user1, message: "has a reply"),
) )
thread_message = thread_message =
Fabricate( Fabricate(
@ -414,19 +484,27 @@ describe Chat::TranscriptService do
message: "a reply", message: "a reply",
thread: thread, thread: thread,
) )
empty_thread_om = empty_thread =
Fabricate( Fabricate(
:chat_message, :chat_thread,
chat_channel: channel, channel: channel,
user: user1, original_message:
thread: Fabricate(:chat_thread, channel: channel), Fabricate(
message: "no replies", :chat_message,
chat_channel: channel,
user: user1,
thread:,
message: "no replies",
),
) )
thread.update!(replies_count: 1) thread.update!(replies_count: 1)
rendered = service([thread_om.id, thread_message.id, empty_thread_om.id]).generate_markdown rendered =
service(
[thread.original_message.id, thread_message.id, empty_thread.original_message.id],
).generate_markdown
expect(rendered).to eq(<<~MARKDOWN) expect(rendered).to eq(<<~MARKDOWN)
[chat quote="martinchat;#{thread_om.id};#{thread_om.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"] [chat quote="martinchat;#{thread.original_message.id};#{thread.original_message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" threadId="#{thread.id}" threadTitle="#{I18n.t("chat.transcript.default_thread_title")}"]
has a reply has a reply
[chat quote="brucechat;#{thread_message.id};#{thread_message.created_at.iso8601}" chained="true"] [chat quote="brucechat;#{thread_message.id};#{thread_message.created_at.iso8601}" chained="true"]
@ -435,7 +513,7 @@ describe Chat::TranscriptService do
[/chat] [/chat]
[chat quote="martinchat;#{empty_thread_om.id};#{empty_thread_om.created_at.iso8601}" chained="true"] [chat quote="martinchat;#{empty_thread.original_message.id};#{empty_thread.original_message.created_at.iso8601}" chained="true"]
no replies no replies
[/chat] [/chat]
MARKDOWN MARKDOWN