mirror of
https://github.com/discourse/discourse.git
synced 2024-12-03 21:33:44 +08:00
75b81b6854
Initially, the ChatMention model / db table was introduced to better support notifications (see discourse/discourse-chat@0801d10). That means that currently, we create a new chat_mention record only if a user will be notified about the mention. Now we plan to start using the ChatMention model in other scenarios (for example for implementing user status on mentions) so we need to always create a new record in the chat_mention table. This PR does the first step into that direction by decoupling the logic for extracting and expanding mentions from the code related to notifications. This doesn't change any behavior, only extracts code from ChatNotifier.
89 lines
2.4 KiB
Ruby
89 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Chat::ChatMessageMentions
|
|
def initialize(message)
|
|
@message = message
|
|
|
|
mentions = parse_mentions(message)
|
|
group_mentions = parse_group_mentions(message)
|
|
|
|
@has_global_mention = mentions.include?("@all")
|
|
@has_here_mention = mentions.include?("@here")
|
|
@parsed_direct_mentions = normalize(mentions)
|
|
@parsed_group_mentions = normalize(group_mentions)
|
|
end
|
|
|
|
attr_accessor :has_global_mention,
|
|
:has_here_mention,
|
|
:parsed_direct_mentions,
|
|
:parsed_group_mentions
|
|
|
|
def global_mentions
|
|
return User.none unless @has_global_mention
|
|
channel_members.where.not(username_lower: @parsed_direct_mentions)
|
|
end
|
|
|
|
def direct_mentions
|
|
chat_users.where(username_lower: @parsed_direct_mentions)
|
|
end
|
|
|
|
def group_mentions
|
|
chat_users.includes(:groups).joins(:groups).where(groups: mentionable_groups)
|
|
end
|
|
|
|
def here_mentions
|
|
return User.none unless @has_here_mention
|
|
|
|
channel_members
|
|
.where("last_seen_at > ?", 5.minutes.ago)
|
|
.where.not(username_lower: @parsed_direct_mentions)
|
|
end
|
|
|
|
def mentionable_groups
|
|
@mentionable_groups ||=
|
|
Group.mentionable(@message.user, include_public: false).where(id: visible_groups.map(&:id))
|
|
end
|
|
|
|
def visible_groups
|
|
@visible_groups ||=
|
|
Group.where("LOWER(name) IN (?)", @parsed_group_mentions).visible_groups(@message.user)
|
|
end
|
|
|
|
private
|
|
|
|
def channel_members
|
|
chat_users.where(
|
|
user_chat_channel_memberships: {
|
|
following: true,
|
|
chat_channel_id: @message.chat_channel.id,
|
|
},
|
|
)
|
|
end
|
|
|
|
def chat_users
|
|
User
|
|
.includes(:user_chat_channel_memberships, :group_users)
|
|
.distinct
|
|
.joins("LEFT OUTER JOIN user_chat_channel_memberships uccm ON uccm.user_id = users.id")
|
|
.joins(:user_option)
|
|
.real
|
|
.not_suspended
|
|
.where(user_options: { chat_enabled: true })
|
|
.where.not(username_lower: @message.user.username.downcase)
|
|
end
|
|
|
|
def parse_mentions(message)
|
|
Nokogiri::HTML5.fragment(message.cooked).css(".mention").map(&:text)
|
|
end
|
|
|
|
def parse_group_mentions(message)
|
|
Nokogiri::HTML5.fragment(message.cooked).css(".mention-group").map(&:text)
|
|
end
|
|
|
|
def normalize(mentions)
|
|
mentions.reduce([]) do |memo, mention|
|
|
%w[@here @all].include?(mention.downcase) ? memo : (memo << mention[1..-1].downcase)
|
|
end
|
|
end
|
|
end
|