DEV: Allow chat mentions to have several notifications (#24874)

This PR is a reworked version of https://github.com/discourse/discourse/pull/24670.

In chat, we need the ability to have several notifications per `chat_mention`. 
Currently, we have one_to_one relationship between `chat_mentions` and `notifications`:

d7a09fb08d/plugins/chat/app/models/chat/mention.rb (L9)

We want to have one_to_many relationship. This PR implements that by introducing 
a join table between `chat_mentions` and `notifications`.

The main motivation for this is that we want to solve some performance problems 
with mentions that we're having now. Let's say a user sends a message with @ all 
in a channel with 50 members, we do two things in this case at the moment:

- create 50 chat_mentions
- create 50 notifications

We don't want to change how notifications work in core, but we want to be more 
efficient in chat, and create only 1 `chat_mention` which would link to 50 notifications. 
Also note, that on the side of notifications, having a lot of notifications is not so 
big problem, because notifications processing can be queued.

Apart from improving performance, this change will make the code design better.

Note that I've marked the old `chat_mention.notification_id` column as ignored, but 
I'm not deleting it in this PR. We'll delete it later in https://github.com/discourse/discourse/pull/24800.
This commit is contained in:
Andrei Prigorshnev
2023-12-19 18:53:00 +04:00
committed by GitHub
parent 558c709fef
commit fbd24fa6ae
22 changed files with 141 additions and 41 deletions

View File

@@ -26,7 +26,7 @@ describe Jobs::Chat::ChannelDelete do
Chat::Mention.create(
user: user2,
chat_message: messages.sample,
notification: Fabricate(:notification),
notifications: [Fabricate(:notification)],
)
@incoming_chat_webhook_id = Fabricate(:incoming_chat_webhook, chat_channel: chat_channel)

View File

@@ -282,10 +282,6 @@ describe Jobs::Chat::NotifyMentioned do
expect(data_hash[:is_direct_message_channel]).to eq(false)
expect(data_hash[:chat_channel_title]).to eq(expected_channel_title)
expect(data_hash[:chat_channel_slug]).to eq(public_channel.slug)
chat_mention =
Chat::Mention.where(notification: created_notification, user: user_2, chat_message: message)
expect(chat_mention).to be_present
end
end

View File

@@ -257,7 +257,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: chat_message,
notification: notification,
notifications: [notification],
)
end
@@ -310,7 +310,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: another_chat_message,
notification: notification,
notifications: [notification],
)
another_chat_channel.update!(last_message: another_chat_message)
@@ -350,7 +350,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: another_chat_message,
notification: notification,
notifications: [notification],
)
another_chat_channel.update!(last_message: another_chat_message)
end
@@ -379,7 +379,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: chat_message,
notification: notification,
notifications: [notification],
)
end
@@ -406,7 +406,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: chat_message,
notification: notification,
notifications: [notification],
)
end
@@ -513,7 +513,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: new_message,
notification: notification,
notifications: [notification],
)
email = described_class.chat_summary(user, {})
@@ -642,7 +642,12 @@ describe UserNotifications do
2.times do
msg = Fabricate(:chat_message, user: sender, chat_channel: channel)
notification = Fabricate(:notification)
Fabricate(:chat_mention, user: user, chat_message: msg, notification: notification)
Fabricate(
:chat_mention,
user: user,
chat_message: msg,
notifications: [notification],
)
end
email = described_class.chat_summary(user, {})
@@ -668,7 +673,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: msg,
notification: notification,
notifications: [notification],
)
end
@@ -695,7 +700,7 @@ describe UserNotifications do
:chat_mention,
user: user,
chat_message: new_message,
notification: notification,
notifications: [notification],
)
email = described_class.chat_summary(user, {})

View File

@@ -449,8 +449,8 @@ describe Chat::Message do
it "destroys chat_mention" do
message_1 = Fabricate(:chat_message)
notification = Fabricate(:notification)
mention_1 = Fabricate(:chat_mention, chat_message: message_1, notification: notification)
notification = Fabricate(:notification, notification_type: Notification.types[:chat_mention])
mention_1 = Fabricate(:chat_mention, chat_message: message_1, notifications: [notification])
message_1.reload.destroy!

View File

@@ -128,7 +128,11 @@ describe Chat::ChannelUnreadsQuery do
user_id: current_user.id,
data: { chat_message_id: message.id, chat_channel_id: channel.id }.to_json,
)
Chat::Mention.create!(notification: notification, user: current_user, chat_message: message)
Chat::Mention.create!(
notifications: [notification],
user: current_user,
chat_message: message,
)
end
it "returns a correct unread mention" do

View File

@@ -199,7 +199,7 @@ RSpec.describe Chat::Api::ReadsController do
}.to_json,
)
.tap do |notification|
Chat::Mention.create!(user: user, chat_message: msg, notification: notification)
Chat::Mention.create!(user: user, chat_message: msg, notifications: [notification])
end
end
end

View File

@@ -66,7 +66,7 @@ RSpec.describe Chat::Api::ThreadReadsController do
}.to_json,
)
.tap do |notification|
Chat::Mention.create!(user: user, chat_message: msg, notification: notification)
Chat::Mention.create!(user: user, chat_message: msg, notifications: [notification])
end
end
end

View File

@@ -85,12 +85,12 @@ RSpec.describe Chat::MarkAllUserChannelsRead do
before do
Chat::Mention.create!(
notification: notification_1,
notifications: [notification_1],
user: current_user,
chat_message: message_1,
)
Chat::Mention.create!(
notification: notification_2,
notifications: [notification_2],
user: current_user,
chat_message: message_3,
)

View File

@@ -49,13 +49,13 @@ RSpec.describe Chat::TrashMessage do
it "destroys notifications for mentions" do
notification = Fabricate(:notification)
mention = Fabricate(:chat_mention, chat_message: message, notification: notification)
mention = Fabricate(:chat_mention, chat_message: message, notifications: [notification])
result
mention = Chat::Mention.find_by(id: mention.id)
expect(mention).to be_present
expect(mention.notification_id).to be_nil
expect(mention.notifications).to be_empty
end
it "publishes associated Discourse and MessageBus events" do

View File

@@ -189,7 +189,7 @@ RSpec.describe Chat::UpdateMessage do
)
mention = user3.chat_mentions.where(chat_message: message.id).first
expect(mention.notification).to be_present
expect(mention.notifications.length).to be(1)
end
it "doesn't create mentions for already mentioned users" do
@@ -215,7 +215,7 @@ RSpec.describe Chat::UpdateMessage do
)
mention = user_without_memberships.chat_mentions.where(chat_message: chat_message).first
expect(mention.notification).to be_nil
expect(mention.notifications).to be_empty
end
it "destroys mentions that should be removed" do
@@ -271,7 +271,7 @@ RSpec.describe Chat::UpdateMessage do
)
mention = admin1.chat_mentions.where(chat_message_id: message.id).first
expect(mention.notification).to be_nil
expect(mention.notifications).to be_empty
end
it "creates a chat_mention record without notification when self mentioning" do
@@ -282,7 +282,7 @@ RSpec.describe Chat::UpdateMessage do
mention = user1.chat_mentions.where(chat_message: chat_message).first
expect(mention).to be_present
expect(mention.notification).to be_nil
expect(mention.notifications).to be_empty
end
it "adds mentioned user and their status to the message bus message" do

View File

@@ -85,7 +85,7 @@ RSpec.describe Chat::UpdateUserLastRead do
before do
Jobs.run_immediately!
Chat::Mention.create!(
notification: notification,
notifications: [notification],
user: current_user,
chat_message: message_1,
)

View File

@@ -62,12 +62,12 @@ RSpec.describe Chat::UpdateUserThreadLastRead do
before do
Jobs.run_immediately!
Chat::Mention.create!(
notification: notification_1,
notifications: [notification_1],
user: current_user,
chat_message: Fabricate(:chat_message, chat_channel: channel, thread: thread),
)
Chat::Mention.create!(
notification: notification_2,
notifications: [notification_2],
user: current_user,
chat_message: Fabricate(:chat_message, chat_channel: channel, thread: thread),
)