mirror of
https://github.com/discourse/discourse.git
synced 2025-02-11 05:44:59 +00:00
0924f874bd
We've had the UploadReference table for some time now in core, but it was added after ChatUpload was and chat was just never moved over to this new system. This commit changes all chat code dealing with uploads to create/ update/delete/query UploadReference records instead of ChatUpload records for consistency. At a later date we will drop the ChatUpload table, but for now keeping it for data backup. The migration + post migration are the same, we need both in case any chat uploads are added/removed during deploy.
377 lines
14 KiB
Ruby
377 lines
14 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "rails_helper"
|
|
|
|
describe Chat::ChatChannelArchiveService do
|
|
class FakeArchiveError < StandardError
|
|
end
|
|
|
|
fab!(:channel) { Fabricate(:category_channel) }
|
|
fab!(:user) { Fabricate(:user, admin: true) }
|
|
fab!(:category) { Fabricate(:category) }
|
|
let(:topic_params) { { topic_title: "This will be a new topic", category_id: category.id } }
|
|
subject { Chat::ChatChannelArchiveService }
|
|
|
|
before { SiteSetting.chat_enabled = true }
|
|
|
|
describe "#create_archive_process" do
|
|
before { 3.times { Fabricate(:chat_message, chat_channel: channel) } }
|
|
|
|
it "marks the channel as read_only" do
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
expect(channel.reload.status).to eq("read_only")
|
|
end
|
|
|
|
it "creates the chat channel archive record to save progress and topic params" do
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
channel_archive = ChatChannelArchive.find_by(chat_channel: channel)
|
|
expect(channel_archive.archived_by).to eq(user)
|
|
expect(channel_archive.destination_topic_title).to eq("This will be a new topic")
|
|
expect(channel_archive.destination_category_id).to eq(category.id)
|
|
expect(channel_archive.total_messages).to eq(3)
|
|
expect(channel_archive.archived_messages).to eq(0)
|
|
end
|
|
|
|
it "enqueues the archive job" do
|
|
channel_archive =
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
expect(
|
|
job_enqueued?(
|
|
job: :chat_channel_archive,
|
|
args: {
|
|
chat_channel_archive_id: channel_archive.id,
|
|
},
|
|
),
|
|
).to eq(true)
|
|
end
|
|
|
|
it "does nothing if there is already an archive record for the channel" do
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
expect {
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
}.not_to change { ChatChannelArchive.count }
|
|
end
|
|
|
|
it "does not count already deleted messages toward the archive total" do
|
|
new_message = Fabricate(:chat_message, chat_channel: channel)
|
|
new_message.trash!
|
|
channel_archive =
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
expect(channel_archive.total_messages).to eq(3)
|
|
end
|
|
end
|
|
|
|
describe "#execute" do
|
|
def create_messages(num)
|
|
num.times { Fabricate(:chat_message, chat_channel: channel) }
|
|
end
|
|
|
|
def start_archive
|
|
@channel_archive =
|
|
subject.create_archive_process(
|
|
chat_channel: channel,
|
|
acting_user: user,
|
|
topic_params: topic_params,
|
|
)
|
|
end
|
|
|
|
context "when archiving to a new topic" do
|
|
let(:topic_params) do
|
|
{ topic_title: "This will be a new topic", category_id: category.id, tags: %w[news gossip] }
|
|
end
|
|
|
|
it "makes a topic, deletes all the messages, creates posts for batches of messages, and changes the channel to archived" do
|
|
create_messages(50) && start_archive
|
|
reaction_message = ChatMessage.last
|
|
ChatMessageReaction.create!(
|
|
chat_message: reaction_message,
|
|
user: Fabricate(:user),
|
|
emoji: "+1",
|
|
)
|
|
stub_const(Chat::ChatChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
|
subject.new(@channel_archive).execute
|
|
end
|
|
|
|
@channel_archive.reload
|
|
expect(@channel_archive.destination_topic.title).to eq("This will be a new topic")
|
|
expect(@channel_archive.destination_topic.category).to eq(category)
|
|
expect(@channel_archive.destination_topic.user).to eq(Discourse.system_user)
|
|
expect(@channel_archive.destination_topic.tags.map(&:name)).to match_array(%w[news gossip])
|
|
|
|
topic = @channel_archive.destination_topic
|
|
expect(topic.posts.count).to eq(11)
|
|
topic
|
|
.posts
|
|
.where.not(post_number: 1)
|
|
.each do |post|
|
|
expect(post.raw).to include("[chat")
|
|
expect(post.raw).to include("noLink=\"true\"")
|
|
expect(post.user).to eq(Discourse.system_user)
|
|
|
|
if post.raw.include?(";#{reaction_message.id};")
|
|
expect(post.raw).to include("reactions=")
|
|
end
|
|
end
|
|
expect(topic.archived).to eq(true)
|
|
|
|
expect(@channel_archive.archived_messages).to eq(50)
|
|
expect(@channel_archive.chat_channel.status).to eq("archived")
|
|
expect(@channel_archive.chat_channel.chat_messages.count).to eq(0)
|
|
end
|
|
|
|
it "does not stop the process if the post length is too high (validations disabled)" do
|
|
create_messages(50) && start_archive
|
|
SiteSetting.max_post_length = 1
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(true)
|
|
end
|
|
|
|
it "successfully links uploads from messages to the post" do
|
|
create_messages(3) && start_archive
|
|
UploadReference.create(target: ChatMessage.last, upload: Fabricate(:upload))
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(true)
|
|
expect(@channel_archive.destination_topic.posts.last.upload_references.count).to eq(1)
|
|
end
|
|
|
|
it "successfully sends a private message to the archiving user" do
|
|
create_messages(3) && start_archive
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(true)
|
|
pm_topic = Topic.private_messages.last
|
|
expect(pm_topic.topic_allowed_users.first.user).to eq(@channel_archive.archived_by)
|
|
expect(pm_topic.title).to eq(
|
|
I18n.t("system_messages.chat_channel_archive_complete.subject_template"),
|
|
)
|
|
end
|
|
|
|
it "does not continue archiving if the destination topic fails to be created" do
|
|
SiteSetting.max_emojis_in_title = 1
|
|
|
|
create_messages(3) && start_archive
|
|
@channel_archive.update!(destination_topic_title: "Wow this is the new title :tada: :joy:")
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(false)
|
|
expect(@channel_archive.reload.failed?).to eq(true)
|
|
expect(@channel_archive.archive_error).to eq("Title can't have more than 1 emoji")
|
|
|
|
pm_topic = Topic.private_messages.last
|
|
expect(pm_topic.title).to eq(
|
|
I18n.t("system_messages.chat_channel_archive_failed.subject_template"),
|
|
)
|
|
expect(pm_topic.first_post.raw).to include("Title can't have more than 1 emoji")
|
|
end
|
|
|
|
context "when enable_experimental_hashtag_autocomplete" do
|
|
before { SiteSetting.enable_experimental_hashtag_autocomplete = true }
|
|
|
|
it "uses the channel slug to autolink a hashtag for the channel in the PM" do
|
|
create_messages(3) && start_archive
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(true)
|
|
pm_topic = Topic.private_messages.last
|
|
expect(pm_topic.first_post.cooked).to include(
|
|
"<a class=\"hashtag-cooked\" href=\"#{channel.relative_url}\" data-type=\"channel\" data-slug=\"#{channel.slug}\" data-ref=\"#{channel.slug}::channel\"><svg class=\"fa d-icon d-icon-comment svg-icon svg-node\"><use href=\"#comment\"></use></svg><span>#{channel.title(user)}</span></a>",
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "channel members" do
|
|
before do
|
|
create_messages(3)
|
|
channel
|
|
.chat_messages
|
|
.map(&:user)
|
|
.each do |user|
|
|
UserChatChannelMembership.create!(chat_channel: channel, user: user, following: true)
|
|
end
|
|
end
|
|
|
|
it "unfollows (leaves) the channel for all users" do
|
|
expect(
|
|
UserChatChannelMembership.where(chat_channel: channel, following: true).count,
|
|
).to eq(3)
|
|
start_archive
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(true)
|
|
expect(
|
|
UserChatChannelMembership.where(chat_channel: channel, following: true).count,
|
|
).to eq(0)
|
|
end
|
|
|
|
it "resets unread state for all users" do
|
|
UserChatChannelMembership.last.update!(
|
|
last_read_message_id: channel.chat_messages.first.id,
|
|
)
|
|
start_archive
|
|
subject.new(@channel_archive).execute
|
|
expect(@channel_archive.reload.complete?).to eq(true)
|
|
expect(UserChatChannelMembership.last.last_read_message_id).to eq(
|
|
channel.chat_messages.last.id,
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "chat_archive_destination_topic_status setting" do
|
|
context "when set to archived" do
|
|
before { SiteSetting.chat_archive_destination_topic_status = "archived" }
|
|
|
|
it "archives the topic" do
|
|
create_messages(3) && start_archive
|
|
subject.new(@channel_archive).execute
|
|
topic = @channel_archive.destination_topic
|
|
topic.reload
|
|
expect(topic.archived).to eq(true)
|
|
end
|
|
end
|
|
|
|
context "when set to open" do
|
|
before { SiteSetting.chat_archive_destination_topic_status = "open" }
|
|
|
|
it "leaves the topic open" do
|
|
create_messages(3) && start_archive
|
|
subject.new(@channel_archive).execute
|
|
topic = @channel_archive.destination_topic
|
|
topic.reload
|
|
expect(topic.archived).to eq(false)
|
|
expect(topic.open?).to eq(true)
|
|
end
|
|
end
|
|
|
|
context "when set to closed" do
|
|
before { SiteSetting.chat_archive_destination_topic_status = "closed" }
|
|
|
|
it "closes the topic" do
|
|
create_messages(3) && start_archive
|
|
subject.new(@channel_archive).execute
|
|
topic = @channel_archive.destination_topic
|
|
topic.reload
|
|
expect(topic.archived).to eq(false)
|
|
expect(topic.closed?).to eq(true)
|
|
end
|
|
end
|
|
|
|
context "when archiving to an existing topic" do
|
|
it "does not change the status of the topic" do
|
|
create_messages(3) && start_archive
|
|
@channel_archive.update(
|
|
destination_topic_title: nil,
|
|
destination_topic_id: Fabricate(:topic).id,
|
|
)
|
|
subject.new(@channel_archive).execute
|
|
topic = @channel_archive.destination_topic
|
|
topic.reload
|
|
expect(topic.archived).to eq(false)
|
|
expect(topic.closed?).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when archiving to an existing topic" do
|
|
fab!(:topic) { Fabricate(:topic) }
|
|
let(:topic_params) { { topic_id: topic.id } }
|
|
|
|
before { 3.times { Fabricate(:post, topic: topic) } }
|
|
|
|
it "deletes all the messages, creates posts for batches of messages, and changes the channel to archived" do
|
|
create_messages(50) && start_archive
|
|
reaction_message = ChatMessage.last
|
|
ChatMessageReaction.create!(
|
|
chat_message: reaction_message,
|
|
user: Fabricate(:user),
|
|
emoji: "+1",
|
|
)
|
|
stub_const(Chat::ChatChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
|
subject.new(@channel_archive).execute
|
|
end
|
|
|
|
@channel_archive.reload
|
|
expect(@channel_archive.destination_topic.title).to eq(topic.title)
|
|
expect(@channel_archive.destination_topic.category).to eq(topic.category)
|
|
expect(@channel_archive.destination_topic.user).to eq(topic.user)
|
|
|
|
topic = @channel_archive.destination_topic
|
|
|
|
# existing posts + 10 archive posts
|
|
expect(topic.posts.count).to eq(13)
|
|
topic
|
|
.posts
|
|
.where.not(post_number: [1, 2, 3])
|
|
.each do |post|
|
|
expect(post.raw).to include("[chat")
|
|
expect(post.raw).to include("noLink=\"true\"")
|
|
expect(post.user).to eq(Discourse.system_user)
|
|
|
|
if post.raw.include?(";#{reaction_message.id};")
|
|
expect(post.raw).to include("reactions=")
|
|
end
|
|
end
|
|
expect(topic.archived).to eq(false)
|
|
|
|
expect(@channel_archive.archived_messages).to eq(50)
|
|
expect(@channel_archive.chat_channel.status).to eq("archived")
|
|
expect(@channel_archive.chat_channel.chat_messages.count).to eq(0)
|
|
end
|
|
|
|
it "handles errors gracefully, sends a private message to the archiving user, and is idempotent on retry" do
|
|
Rails.logger = @fake_logger = FakeLogger.new
|
|
create_messages(35) && start_archive
|
|
|
|
Chat::ChatChannelArchiveService
|
|
.any_instance
|
|
.stubs(:create_post)
|
|
.raises(FakeArchiveError.new("this is a test error"))
|
|
|
|
stub_const(Chat::ChatChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
|
expect { subject.new(@channel_archive).execute }.to raise_error(FakeArchiveError)
|
|
end
|
|
|
|
expect(@channel_archive.reload.archive_error).to eq("this is a test error")
|
|
|
|
pm_topic = Topic.private_messages.last
|
|
expect(pm_topic.topic_allowed_users.first.user).to eq(@channel_archive.archived_by)
|
|
expect(pm_topic.title).to eq(
|
|
I18n.t("system_messages.chat_channel_archive_failed.subject_template"),
|
|
)
|
|
|
|
Chat::ChatChannelArchiveService.any_instance.unstub(:create_post)
|
|
stub_const(Chat::ChatChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
|
subject.new(@channel_archive).execute
|
|
end
|
|
|
|
@channel_archive.reload
|
|
expect(@channel_archive.archive_error).to eq(nil)
|
|
expect(@channel_archive.archived_messages).to eq(35)
|
|
expect(@channel_archive.complete?).to eq(true)
|
|
# existing posts + 7 archive posts
|
|
expect(topic.posts.count).to eq(10)
|
|
end
|
|
end
|
|
end
|
|
end
|