discourse/plugins/chat/spec/components/chat_message_creator_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

609 lines
20 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
require "rails_helper"
describe Chat::ChatMessageCreator do
fab!(:admin1) { Fabricate(:admin) }
fab!(:admin2) { Fabricate(:admin) }
fab!(:user1) { Fabricate(:user, group_ids: [Group::AUTO_GROUPS[:everyone]]) }
fab!(:user2) { Fabricate(:user) }
fab!(:user3) { Fabricate(:user) }
fab!(:user4) { Fabricate(:user) }
fab!(:admin_group) do
Fabricate(
:public_group,
users: [admin1, admin2],
mentionable_level: Group::ALIAS_LEVELS[:everyone],
)
end
fab!(:user_group) do
Fabricate(
:public_group,
users: [user1, user2, user3],
mentionable_level: Group::ALIAS_LEVELS[:everyone],
)
end
fab!(:user_without_memberships) { Fabricate(:user) }
fab!(:public_chat_channel) { Fabricate(:category_channel) }
fab!(:dm_chat_channel) do
Fabricate(
:direct_message_channel,
chatable: Fabricate(:direct_message, users: [user1, user2, user3]),
)
end
let(:direct_message_channel) do
Chat::DirectMessageChannelCreator.create!(acting_user: user1, target_users: [user1, user2])
end
before do
SiteSetting.chat_enabled = true
SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:everyone]
SiteSetting.chat_duplicate_message_sensitivity = 0
# Create channel memberships
[admin1, admin2, user1, user2, user3].each do |user|
Fabricate(:user_chat_channel_membership, chat_channel: public_chat_channel, user: user)
end
Group.refresh_automatic_groups!
direct_message_channel
end
describe "Integration tests with jobs running immediately" do
before { Jobs.run_immediately! }
it "errors when length is less than `chat_minimum_message_length`" do
SiteSetting.chat_minimum_message_length = 10
creator =
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "2 short",
)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to match(
I18n.t(
"chat.errors.minimum_length_not_met",
{ minimum: SiteSetting.chat_minimum_message_length },
),
)
end
it "errors when length is greater than `chat_maximum_message_length`" do
SiteSetting.chat_maximum_message_length = 100
creator =
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "a really long and in depth message that is just too detailed" * 100,
)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to match(
I18n.t(
"chat.errors.message_too_long",
{ maximum: SiteSetting.chat_maximum_message_length },
),
)
end
it "allows message creation when length is less than `chat_minimum_message_length` when upload is present" do
upload = Fabricate(:upload, user: user1)
SiteSetting.chat_minimum_message_length = 10
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "2 short",
upload_ids: [upload.id],
)
}.to change { ChatMessage.count }.by(1)
end
it "creates messages for users who can see the channel" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "this is a message",
)
}.to change { ChatMessage.count }.by(1)
end
it "updates the channels last message date" do
previous_last_message_sent_at = public_chat_channel.last_message_sent_at
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "this is a message",
)
expect(previous_last_message_sent_at).to be < public_chat_channel.reload.last_message_sent_at
end
it "sets the last_editor_id to the user who created the message" do
message =
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "this is a message",
).chat_message
expect(message.last_editor_id).to eq(user1.id)
end
it "publishes a DiscourseEvent for new messages" do
events =
DiscourseEvent.track_events do
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "this is a message",
)
end
expect(events.map { _1[:event_name] }).to include(:chat_message_created)
end
it "creates mention notifications for public chat" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content:
"this is a @#{user1.username} message with @system @mentions @#{user2.username} and @#{user3.username}",
)
# Only 2 mentions are created because user mentioned themselves, system, and an invalid username.
}.to change { ChatMention.count }.by(2).and not_change { user1.chat_mentions.count }
end
it "mentions are case insensitive" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "Hey @#{user2.username.upcase}",
)
}.to change { user2.chat_mentions.count }.by(1)
end
it "notifies @all properly" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "@all",
)
}.to change { ChatMention.count }.by(4)
UserChatChannelMembership.where(user: user2, chat_channel: public_chat_channel).update_all(
following: false,
)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "again! @all",
)
}.to change { ChatMention.count }.by(3)
end
it "notifies @here properly" do
admin1.update(last_seen_at: 1.year.ago)
admin2.update(last_seen_at: 1.year.ago)
user1.update(last_seen_at: Time.now)
user2.update(last_seen_at: Time.now)
user3.update(last_seen_at: Time.now)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "@here",
)
}.to change { ChatMention.count }.by(2)
end
it "doesn't sent double notifications when '@here' is mentioned" do
user2.update(last_seen_at: Time.now)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "@here @#{user2.username}",
)
}.to change { user2.chat_mentions.count }.by(1)
end
it "notifies @here plus other mentions" do
admin1.update(last_seen_at: Time.now)
admin2.update(last_seen_at: 1.year.ago)
user1.update(last_seen_at: 1.year.ago)
user2.update(last_seen_at: 1.year.ago)
user3.update(last_seen_at: 1.year.ago)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "@here plus @#{user3.username}",
)
}.to change { user3.chat_mentions.count }.by(1)
end
it "doesn't create mention notifications for users without a membership record" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hello @#{user_without_memberships.username}",
)
}.not_to change { ChatMention.count }
end
it "doesn't create mention notifications for users who cannot chat" do
new_group = Group.create
SiteSetting.chat_allowed_groups = new_group.id
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hi @#{user2.username} @#{user3.username}",
)
}.not_to change { ChatMention.count }
end
it "doesn't create mention notifications for users with chat disabled" do
user2.user_option.update(chat_enabled: false)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hi @#{user2.username}",
)
}.not_to change { ChatMention.count }
end
it "creates only mention notifications for users with access in private chat" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: direct_message_channel,
user: user1,
content: "hello there @#{user2.username} and @#{user3.username}",
)
# Only user2 should be notified
}.to change { user2.chat_mentions.count }.by(1).and not_change { user3.chat_mentions.count }
end
it "creates a mention notifications for group users that are participating in private chat" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: direct_message_channel,
user: user1,
content: "hello there @#{user_group.name}",
)
# Only user2 should be notified
}.to change { user2.chat_mentions.count }.by(1).and not_change { user3.chat_mentions.count }
end
it "publishes inaccessible mentions when user isn't aren't a part of the channel" do
ChatPublisher.expects(:publish_inaccessible_mentions).once
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: admin1,
content: "hello @#{user4.username}",
)
end
it "publishes inaccessible mentions when user doesn't have chat access" do
SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:staff]
ChatPublisher.expects(:publish_inaccessible_mentions).once
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: admin1,
content: "hello @#{user3.username}",
)
end
it "doesn't publish inaccessible mentions when user is following channel" do
ChatPublisher.expects(:publish_inaccessible_mentions).never
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: admin1,
content: "hello @#{admin2.username}",
)
end
it "does not create mentions for suspended users" do
user2.update(suspended_till: Time.now + 10.years)
expect {
Chat::ChatMessageCreator.create(
chat_channel: direct_message_channel,
user: user1,
content: "hello @#{user2.username}",
)
}.not_to change { user2.chat_mentions.count }
end
it "does not create @all mentions for users when ignore_channel_wide_mention is enabled" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "@all",
)
}.to change { ChatMention.count }.by(4)
user2.user_option.update(ignore_channel_wide_mention: true)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hi! @all",
)
}.to change { ChatMention.count }.by(3)
end
it "does not create @here mentions for users when ignore_channel_wide_mention is enabled" do
admin1.update(last_seen_at: 1.year.ago)
admin2.update(last_seen_at: 1.year.ago)
user1.update(last_seen_at: Time.now)
user2.update(last_seen_at: Time.now)
user2.user_option.update(ignore_channel_wide_mention: true)
user3.update(last_seen_at: Time.now)
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "@here",
)
}.to change { ChatMention.count }.by(1)
end
describe "group mentions" do
it "creates chat mentions for group mentions where the group is mentionable" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hello @#{admin_group.name}",
)
}.to change { admin1.chat_mentions.count }.by(1).and change {
admin2.chat_mentions.count
}.by(1)
end
it "doesn't mention users twice if they are direct mentioned and group mentioned" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hello @#{admin_group.name} @#{admin1.username} and @#{admin2.username}",
)
}.to change { admin1.chat_mentions.count }.by(1).and change {
admin2.chat_mentions.count
}.by(1)
end
it "creates chat mentions for group mentions and direct mentions" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hello @#{admin_group.name} @#{user2.username}",
)
}.to change { admin1.chat_mentions.count }.by(1).and change {
admin2.chat_mentions.count
}.by(1).and change { user2.chat_mentions.count }.by(1)
end
it "creates chat mentions for group mentions and direct mentions" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hello @#{admin_group.name} @#{user_group.name}",
)
}.to change { admin1.chat_mentions.count }.by(1).and change {
admin2.chat_mentions.count
}.by(1).and change { user2.chat_mentions.count }.by(1).and change {
user3.chat_mentions.count
}.by(1)
end
it "doesn't create chat mentions for group mentions where the group is un-mentionable" do
admin_group.update(mentionable_level: Group::ALIAS_LEVELS[:nobody])
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "hello @#{admin_group.name}",
)
}.not_to change { ChatMention.count }
end
end
describe "push notifications" do
before do
UserChatChannelMembership.where(user: user1, chat_channel: public_chat_channel).update(
mobile_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always],
)
PresenceChannel.clear_all!
end
it "sends a push notification to watching users who are not in chat" do
PostAlerter.expects(:push_notification).once
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user2,
content: "Beep boop",
)
end
it "does not send a push notification to watching users who are in chat" do
PresenceChannel.new("/chat/online").present(user_id: user1.id, client_id: 1)
PostAlerter.expects(:push_notification).never
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user2,
content: "Beep boop",
)
end
end
describe "with uploads" do
fab!(:upload1) { Fabricate(:upload, user: user1) }
fab!(:upload2) { Fabricate(:upload, user: user1) }
fab!(:private_upload) { Fabricate(:upload, user: user2) }
it "can attach 1 upload to a new message" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "Beep boop",
upload_ids: [upload1.id],
)
}.to change { ChatUpload.where(upload_id: upload1.id).count }.by(1)
end
it "can attach multiple uploads to a new message" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "Beep boop",
upload_ids: [upload1.id, upload2.id],
)
}.to change { ChatUpload.where(upload_id: upload1.id).count }.by(1).and change {
ChatUpload.where(upload_id: upload2.id).count
}.by(1)
end
it "filters out uploads that weren't uploaded by the user" do
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "Beep boop",
upload_ids: [private_upload.id],
)
}.not_to change { ChatUpload.where(upload_id: private_upload.id).count }
end
it "doesn't attach uploads when `chat_allow_uploads` is false" do
SiteSetting.chat_allow_uploads = false
expect {
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "Beep boop",
upload_ids: [upload1.id],
)
}.not_to change { ChatUpload.where(upload_id: upload1.id).count }
end
end
end
it "destroys draft after message was created" do
ChatDraft.create!(user: user1, chat_channel: public_chat_channel, data: "{}")
expect do
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "Hi @#{user2.username}",
)
end.to change { ChatDraft.count }.by(-1)
end
describe "watched words" do
fab!(:watched_word) { Fabricate(:watched_word) }
it "errors when a blocked word is present" do
creator =
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user1,
content: "bad word - #{watched_word.word}",
)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to match(
I18n.t("contains_blocked_word", { word: watched_word.word }),
)
end
end
describe "channel statuses" do
def create_message(user)
Chat::ChatMessageCreator.create(
chat_channel: public_chat_channel,
user: user,
content: "test message",
)
end
context "when channel is closed" do
before { public_chat_channel.update(status: :closed) }
it "errors when trying to create the message for non-staff" do
creator = create_message(user1)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to eq(
I18n.t(
"chat.errors.channel_new_message_disallowed",
status: public_chat_channel.status_name,
),
)
end
it "does not error when trying to create a message for staff" do
expect { create_message(admin1) }.to change { ChatMessage.count }.by(1)
end
end
context "when channel is read_only" do
before { public_chat_channel.update(status: :read_only) }
it "errors when trying to create the message for all users" do
creator = create_message(user1)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to eq(
I18n.t(
"chat.errors.channel_new_message_disallowed",
status: public_chat_channel.status_name,
),
)
creator = create_message(admin1)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to eq(
I18n.t(
"chat.errors.channel_new_message_disallowed",
status: public_chat_channel.status_name,
),
)
end
end
context "when channel is archived" do
before { public_chat_channel.update(status: :archived) }
it "errors when trying to create the message for all users" do
creator = create_message(user1)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to eq(
I18n.t(
"chat.errors.channel_new_message_disallowed",
status: public_chat_channel.status_name,
),
)
creator = create_message(admin1)
expect(creator.failed?).to eq(true)
expect(creator.error.message).to eq(
I18n.t(
"chat.errors.channel_new_message_disallowed",
status: public_chat_channel.status_name,
),
)
end
end
end
end