mirror of
https://github.com/discourse/discourse.git
synced 2024-12-03 07:16:48 +08:00
fa543cda06
Before this commit, we created a chat mention record only in case we wanted to send a notification about that mention to the user. Notifications were the only use case for the chat_mention db table. Now we want to use that table for other features, so we have to always create a chat_mention record.
100 lines
2.7 KiB
Ruby
100 lines
2.7 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 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 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
|
|
.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
|