mirror of
https://github.com/discourse/discourse.git
synced 2025-01-02 08:48:42 +08:00
bee7312f46
Follow up to #27631 to account for group mentions in channels. We only want to show mentions for groups that are currently mentionable and those that the current user belongs to.
186 lines
7.4 KiB
Ruby
186 lines
7.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Chat
|
|
module UserNotificationsExtension
|
|
def chat_summary(user, _ = nil)
|
|
guardian = Guardian.new(user)
|
|
return unless guardian.can_chat?
|
|
|
|
# TODO: handle muted & silenced users ?
|
|
|
|
# ensures these haven't since the job was enqueued
|
|
return if user.last_seen_at > 15.minutes.ago
|
|
return if user.user_option.send_chat_email_never?
|
|
return if user.user_option.email_level == UserOption.email_level_types[:never]
|
|
|
|
group_ids = user.groups.where.not(mentionable_level: Group::ALIAS_LEVELS[:nobody]).pluck(:id)
|
|
group_sql =
|
|
(
|
|
if group_ids.any?
|
|
"WHEN 'Chat::GroupMention' THEN chat_mentions.target_id IN (#{group_ids.join(",")})"
|
|
else
|
|
""
|
|
end
|
|
)
|
|
|
|
unread_mentions = DB.query_array <<~SQL
|
|
WITH unread_mentions AS (
|
|
SELECT uccm.id membership_id, uccm.chat_channel_id, MIN(chat_messages.id) first_chat_message_id, MAX(chat_messages.id) last_chat_message_id
|
|
FROM user_chat_channel_memberships uccm
|
|
JOIN chat_channels ON chat_channels.id = uccm.chat_channel_id
|
|
JOIN chat_messages ON chat_messages.chat_channel_id = chat_channels.id
|
|
JOIN chat_mentions ON chat_mentions.chat_message_id = chat_messages.id
|
|
JOIN chat_mention_notifications cmn ON cmn.chat_mention_id = chat_mentions.id
|
|
JOIN notifications ON notifications.id = cmn.notification_id
|
|
JOIN users ON users.id = chat_messages.user_id
|
|
WHERE uccm.user_id = #{user.id}
|
|
AND NOT uccm.muted
|
|
AND uccm.following
|
|
AND chat_channels.deleted_at IS NULL
|
|
AND chat_channels.chatable_type = 'Category'
|
|
AND chat_messages.deleted_at IS NULL
|
|
AND chat_messages.user_id != uccm.user_id
|
|
AND chat_messages.created_at > now() - interval '1 week'
|
|
AND (uccm.last_read_message_id IS NULL OR uccm.last_read_message_id < chat_messages.id)
|
|
AND (uccm.last_unread_mention_when_emailed_id IS NULL OR uccm.last_unread_mention_when_emailed_id < chat_messages.id)
|
|
AND (
|
|
CASE chat_mentions.type
|
|
WHEN 'Chat::UserMention' THEN chat_mentions.target_id = #{user.id}
|
|
WHEN 'Chat::AllMention' THEN chat_channels.allow_channel_wide_mentions = true
|
|
#{group_sql} END
|
|
)
|
|
AND NOT notifications.read
|
|
GROUP BY uccm.id
|
|
)
|
|
UPDATE user_chat_channel_memberships uccm
|
|
SET last_unread_mention_when_emailed_id = um.last_chat_message_id
|
|
FROM unread_mentions um
|
|
WHERE uccm.id = um.membership_id
|
|
AND uccm.user_id = #{user.id}
|
|
RETURNING um.membership_id, um.chat_channel_id, um.first_chat_message_id
|
|
SQL
|
|
|
|
unread_messages = DB.query_array <<~SQL
|
|
WITH unread_messages AS (
|
|
SELECT uccm.id membership_id, uccm.chat_channel_id, MIN(chat_messages.id) first_chat_message_id, MAX(chat_messages.id) last_chat_message_id
|
|
FROM user_chat_channel_memberships uccm
|
|
JOIN chat_channels ON chat_channels.id = uccm.chat_channel_id
|
|
JOIN chat_messages ON chat_messages.chat_channel_id = chat_channels.id
|
|
JOIN users ON users.id = chat_messages.user_id
|
|
WHERE uccm.user_id = #{user.id}
|
|
AND NOT uccm.muted
|
|
AND chat_channels.deleted_at IS NULL
|
|
AND chat_channels.chatable_type = 'DirectMessage'
|
|
AND chat_messages.deleted_at IS NULL
|
|
AND chat_messages.user_id != uccm.user_id
|
|
AND chat_messages.created_at > now() - interval '1 week'
|
|
AND (uccm.last_read_message_id IS NULL OR uccm.last_read_message_id < chat_messages.id)
|
|
AND (uccm.last_unread_mention_when_emailed_id IS NULL OR uccm.last_unread_mention_when_emailed_id < chat_messages.id)
|
|
GROUP BY uccm.id
|
|
)
|
|
UPDATE user_chat_channel_memberships uccm
|
|
SET last_unread_mention_when_emailed_id = um.last_chat_message_id
|
|
FROM unread_messages um
|
|
WHERE uccm.id = um.membership_id
|
|
AND uccm.user_id = #{user.id}
|
|
RETURNING um.membership_id, um.chat_channel_id, um.first_chat_message_id
|
|
SQL
|
|
|
|
@grouped_channels = chat_messages_for(unread_mentions, guardian)
|
|
|
|
@grouped_dms =
|
|
user.user_option.allow_private_messages ? chat_messages_for(unread_messages, guardian) : {}
|
|
|
|
@count = @grouped_channels.values.sum(&:size) + @grouped_dms.values.sum(&:size)
|
|
|
|
return if @count.zero?
|
|
|
|
@user_tz = UserOption.user_tzinfo(user.id)
|
|
@preferences_path = "#{Discourse.base_url}/my/preferences/chat"
|
|
|
|
build_summary_for(user)
|
|
|
|
build_email(
|
|
user.email,
|
|
from_alias: chat_summary_from_alias,
|
|
subject: chat_summary_subject(@grouped_channels, @grouped_dms, @count),
|
|
)
|
|
end
|
|
|
|
private
|
|
|
|
def chat_messages_for(data, guardian)
|
|
# Note: we probably want to limit the number of messages we fetch
|
|
# since we only display the first 2 per channel in the email
|
|
# I've left this as if for now because we also display the total count
|
|
# and a count of unread messages per channel
|
|
Chat::Message
|
|
.includes(:user, :chat_channel)
|
|
.where(chat_channel_id: data.map { _1[1] })
|
|
.where(
|
|
"chat_messages.id >= (
|
|
SELECT min_unread_id
|
|
FROM (VALUES #{data.map { "(#{_1[1]}, #{_1[2]})" }.join(",")}) AS t(channel_id, min_unread_id)
|
|
WHERE t.channel_id = chat_messages.chat_channel_id
|
|
)",
|
|
)
|
|
.order(created_at: :asc)
|
|
.group_by(&:chat_channel)
|
|
.select { |channel, _| guardian.can_join_chat_channel?(channel) }
|
|
end
|
|
|
|
def chat_summary_from_alias
|
|
I18n.t("user_notifications.chat_summary.from", site_name: @site_name)
|
|
end
|
|
|
|
def subject(type, **args)
|
|
I18n.t("user_notifications.chat_summary.subject.#{type}", { site_name: @site_name, **args })
|
|
end
|
|
|
|
def chat_summary_subject(grouped_channels, grouped_dms, count)
|
|
return subject(:private_email, count:) if SiteSetting.private_email
|
|
|
|
# consider "direct messages" with more than 2 users as group messages (aka. channels)
|
|
dms, groups = grouped_dms.keys.partition { _1.user_chat_channel_memberships.count == 2 }
|
|
|
|
channels = grouped_channels.keys + groups
|
|
|
|
if channels.any?
|
|
if dms.any?
|
|
subject(
|
|
:chat_channel_and_dm,
|
|
channel: channels.first.title(@user),
|
|
name: dms.first.title(@user),
|
|
)
|
|
elsif channels.size == 1
|
|
subject(
|
|
:chat_channel_1,
|
|
channel: channels.first.title(@user),
|
|
count: (grouped_channels[channels.first] || grouped_dms[channels.first]).size,
|
|
)
|
|
elsif channels.size == 2
|
|
subject(
|
|
:chat_channel_2,
|
|
channel_1: channels.first.title(@user),
|
|
channel_2: channels.second.title(@user),
|
|
)
|
|
else
|
|
subject(
|
|
:chat_channel_3_or_more,
|
|
channel: channels.first.title(@user),
|
|
count: channels.size - 1,
|
|
)
|
|
end
|
|
elsif dms.size == 1
|
|
subject(:chat_dm_1, name: dms.first.title(@user), count: grouped_dms[dms.first].size)
|
|
elsif dms.size == 2
|
|
subject(:chat_dm_2, name_1: dms.first.title(@user), name_2: dms.second.title(@user))
|
|
elsif dms.size >= 3
|
|
subject(:chat_dm_3_or_more, name: dms.first.title(@user), count: dms.size - 1)
|
|
else
|
|
subject(:private_email, count:)
|
|
end
|
|
end
|
|
end
|
|
end
|