DEV: Redesign chat mentions (#24752)

At the moment, when someone is mentioning a group, or using here or 
all mention, we create a chat_mention record per user. What we want 
instead is to have special kinds of mentions, so we can create only one 
chat_mention record in such cases. This PR implements that.

Note, that such mentions will still have N related notifications, one 
notification per a user. We don't expect we'll have performance 
problems on the notifications side, but if at some point we do, we 
should be able to solve them on the side of notifications 
(notifications are handled in jobs, also some little delays with 
the notifications are acceptable, so we can make sure notifications 
are properly queued, and that processing of every notification is 
fast enough to make delays small enough).

The preparation work for this PR was done in fbd24fa, where we make 
it possible for one mention to have several related notifications.

A pretty tricky part of this PR is schema and data migration, I've explained 
related details inline on the migration files.
This commit is contained in:
Andrei Prigorshnev
2024-01-17 15:24:01 +04:00
committed by GitHub
parent 6876c52857
commit 62f423da15
40 changed files with 613 additions and 157 deletions

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Chat
module GroupExtension
extend ActiveSupport::Concern
prepended do
has_many :chat_mentions, class_name: "Chat::GroupMention", foreign_key: "target_id"
end
end
end

View File

@@ -52,13 +52,17 @@ module Chat
.joins("INNER JOIN chat_channels cc ON cc.id = uccm.chat_channel_id")
.joins("INNER JOIN chat_messages c_msg ON c_msg.chat_channel_id = uccm.chat_channel_id")
.joins("LEFT OUTER JOIN chat_mentions c_mentions ON c_mentions.chat_message_id = c_msg.id")
.joins(
"LEFT OUTER JOIN chat_mention_notifications cmn ON cmn.chat_mention_id = c_mentions.id",
)
.joins("LEFT OUTER JOIN notifications n ON cmn.notification_id = n.id")
.where("c_msg.deleted_at IS NULL AND c_msg.user_id <> users.id")
.where("c_msg.created_at > ?", 1.week.ago)
.where(<<~SQL)
(uccm.last_read_message_id IS NULL OR c_msg.id > uccm.last_read_message_id) AND
(uccm.last_unread_mention_when_emailed_id IS NULL OR c_msg.id > uccm.last_unread_mention_when_emailed_id) AND
(
(uccm.user_id = c_mentions.user_id AND uccm.following IS true AND cc.chatable_type = 'Category') OR
(uccm.user_id = n.user_id AND uccm.following IS true AND cc.chatable_type = 'Category') OR
(cc.chatable_type = 'DirectMessage')
)
SQL

View File

@@ -83,10 +83,15 @@ module Chat
def notify_edit
already_notified_user_ids =
Chat::Mention
.where(chat_message: @chat_message)
.left_outer_joins(:notifications)
.where.not(notifications: { id: nil })
Notification
.where(notification_type: Notification.types[:chat_mention])
.joins(
"INNER JOIN chat_mention_notifications ON chat_mention_notifications.notification_id = notifications.id",
)
.joins(
"INNER JOIN chat_mentions ON chat_mentions.id = chat_mention_notifications.chat_mention_id",
)
.where("chat_mentions.chat_message_id = ?", @chat_message.id)
.pluck(:user_id)
to_notify, inaccessible, all_mentioned_user_ids = list_users_to_notify

View File

@@ -19,18 +19,6 @@ module Chat
:parsed_direct_mentions,
:parsed_group_mentions
def all_mentioned_users_ids
@all_mentioned_users_ids ||=
begin
user_ids = global_mentions.pluck(:id)
user_ids.concat(direct_mentions.pluck(:id))
user_ids.concat(group_mentions.pluck(:id))
user_ids.concat(here_mentions.pluck(:id))
user_ids.uniq!
user_ids
end
end
def count
@count ||=
begin

View File

@@ -12,7 +12,7 @@ module Chat
class_name: "Chat::UserChatThreadMembership",
dependent: :destroy
has_many :chat_message_reactions, class_name: "Chat::MessageReaction", dependent: :destroy
has_many :chat_mentions, class_name: "Chat::Mention"
has_many :chat_mentions, class_name: "Chat::UserMention", foreign_key: "target_id"
has_many :direct_message_users, class_name: "Chat::DirectMessageUser"
has_many :direct_messages, through: :direct_message_users, class_name: "Chat::DirectMessage"
end

View File

@@ -13,6 +13,7 @@ module Chat
.where("chat_messages.created_at > ?", 1.week.ago)
.joins("LEFT OUTER JOIN chat_mentions cm ON cm.chat_message_id = chat_messages.id")
.joins("LEFT OUTER JOIN chat_mention_notifications cmn ON cmn.chat_mention_id = cm.id")
.joins("LEFT OUTER JOIN notifications n ON cmn.notification_id = n.id")
.joins(
"INNER JOIN user_chat_channel_memberships uccm ON uccm.chat_channel_id = chat_channels.id",
)
@@ -21,7 +22,7 @@ module Chat
(uccm.last_read_message_id IS NULL OR chat_messages.id > uccm.last_read_message_id) AND
(uccm.last_unread_mention_when_emailed_id IS NULL OR chat_messages.id > uccm.last_unread_mention_when_emailed_id) AND
(
(cm.user_id = :user_id AND cmn.notification_id IS NOT NULL AND uccm.following IS true AND chat_channels.chatable_type = 'Category') OR
(n.user_id = :user_id AND cmn.notification_id IS NOT NULL AND uccm.following IS true AND chat_channels.chatable_type = 'Category') OR
(chat_channels.chatable_type = 'DirectMessage')
)
SQL