discourse/plugins/chat/app/jobs/regular/chat_notify_mentioned.rb
Martin Brennan c6764d8c74
FIX: Automatically generate category channel slugs (#18879)
This commit automatically ensures that category channels
have slugs when they are created or updated based on the
channel name, category name, or existing slug. The behaviour
has been copied from the Category model.

We also include a backfill here with a simplified version
of Slug.for with deduplication to fill the slugs for already
created Category chat channels.

The channel slug is also now used for chat notifications,
and for the UI and navigation for chat. `slugifyChannel`
is still used, but now does the following fallback:

* Uses channel.slug if it is present
* Uses channel.escapedTitle if it is present
* Uses channel.title if it is present

In future we may want to remove this altogether
and always rely on the slug being present, but this
is currently not possible because we are not generating
slugs for DM channels at this point.
2022-11-09 10:28:31 +10:00

149 lines
4.5 KiB
Ruby

# frozen_string_literal: true
module Jobs
class ChatNotifyMentioned < ::Jobs::Base
def execute(args = {})
@chat_message =
ChatMessage.includes(:user, :revisions, chat_channel: :chatable).find_by(
id: args[:chat_message_id],
)
if @chat_message.nil? ||
@chat_message.revisions.where("created_at > ?", args[:timestamp]).any?
return
end
@creator = @chat_message.user
@chat_channel = @chat_message.chat_channel
@already_notified_user_ids = args[:already_notified_user_ids] || []
user_ids_to_notify = args[:to_notify_ids_map] || {}
user_ids_to_notify.each { |mention_type, ids| process_mentions(ids, mention_type.to_sym) }
end
private
def get_memberships(user_ids)
query =
UserChatChannelMembership.includes(:user).where(
user_id: (user_ids - @already_notified_user_ids),
chat_channel_id: @chat_message.chat_channel_id,
)
query = query.where(following: true) if @chat_channel.public_channel?
query
end
def build_data_for(membership, identifier_type:)
data = {
chat_message_id: @chat_message.id,
chat_channel_id: @chat_channel.id,
mentioned_by_username: @creator.username,
is_direct_message_channel: @chat_channel.direct_message_channel?,
}
if !@is_direct_message_channel
data[:chat_channel_title] = @chat_channel.title(membership.user)
data[:chat_channel_slug] = @chat_channel.slug
end
return data if identifier_type == :direct_mentions
case identifier_type
when :here_mentions
data[:identifier] = "here"
when :global_mentions
data[:identifier] = "all"
else
data[:identifier] = identifier_type if identifier_type
data[:is_group_mention] = true
end
data
end
def build_payload_for(membership, identifier_type:)
payload = {
notification_type: Notification.types[:chat_mention],
username: @creator.username,
tag: Chat::ChatNotifier.push_notification_tag(:mention, @chat_channel.id),
excerpt: @chat_message.push_notification_excerpt,
post_url: "#{@chat_channel.relative_url}?messageId=#{@chat_message.id}",
}
translation_prefix =
(
if @chat_channel.direct_message_channel?
"discourse_push_notifications.popup.direct_message_chat_mention"
else
"discourse_push_notifications.popup.chat_mention"
end
)
translation_suffix = identifier_type == :direct_mentions ? "direct" : "other_type"
identifier_text =
case identifier_type
when :here_mentions
"@here"
when :global_mentions
"@all"
when :direct_mentions
""
else
"@#{identifier_type}"
end
payload[:translated_title] = I18n.t(
"#{translation_prefix}.#{translation_suffix}",
username: @creator.username,
identifier: identifier_text,
channel: @chat_channel.title(membership.user),
)
payload
end
def create_notification!(membership, notification_data)
is_read = Chat::ChatNotifier.user_has_seen_message?(membership, @chat_message.id)
notification =
Notification.create!(
notification_type: Notification.types[:chat_mention],
user_id: membership.user_id,
high_priority: true,
data: notification_data.to_json,
read: is_read,
)
ChatMention.create!(
notification: notification,
user: membership.user,
chat_message: @chat_message,
)
end
def send_notifications(membership, notification_data, os_payload)
create_notification!(membership, notification_data)
if !membership.desktop_notifications_never? && !membership.muted?
MessageBus.publish(
"/chat/notification-alert/#{membership.user_id}",
os_payload,
user_ids: [membership.user_id],
)
end
if !membership.mobile_notifications_never? && !membership.muted?
PostAlerter.push_notification(membership.user, os_payload)
end
end
def process_mentions(user_ids, mention_type)
memberships = get_memberships(user_ids)
memberships.each do |membership|
notification_data = build_data_for(membership, identifier_type: mention_type)
payload = build_payload_for(membership, identifier_type: mention_type)
send_notifications(membership, notification_data, payload)
end
end
end
end