mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 21:24:04 +08:00
93859037ef
* FEATURE: Show warning if group cannot be mentioned A similar warning is displayed when the user cannot be mentioned because they have not been invited to the topic. * FEATURE: Resolve mentions for new topic This commit improves several improvements and refactors /u/is_local_username route to a better /composer/mentions route that can handle new topics too. * FEATURE: Show warning if only some are notified Sometimes users are still notified even if the group that was mentioned was not invited to the message. This happens because its members were invited directly or are members of other groups that were invited. * DEV: Refactor _warnCannotSeeMention
185 lines
5.4 KiB
Ruby
185 lines
5.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ComposerController < ApplicationController
|
|
requires_login
|
|
|
|
def mentions
|
|
@names = params.require(:names)
|
|
raise Discourse::InvalidParameters.new(:names) if !@names.kind_of?(Array) || @names.size > 20
|
|
|
|
if params[:topic_id].present?
|
|
@topic = Topic.find_by(id: params[:topic_id])
|
|
guardian.ensure_can_see!(@topic)
|
|
end
|
|
|
|
# allowed_names is necessary just for new private messages.
|
|
@allowed_names = if params[:allowed_names].present?
|
|
raise Discourse::InvalidParameters(:allowed_names) if !params[:allowed_names].is_a?(Array)
|
|
params[:allowed_names] << current_user.username
|
|
else
|
|
[]
|
|
end
|
|
|
|
user_reasons = {}
|
|
group_reasons = {}
|
|
@names.each do |name|
|
|
if user = users[name]
|
|
reason = user_reason(user)
|
|
user_reasons[name] = reason if reason.present?
|
|
elsif group = groups[name]
|
|
reason = group_reason(group)
|
|
group_reasons[name] = reason if reason.present?
|
|
end
|
|
end
|
|
|
|
if @topic && @names.include?(SiteSetting.here_mention) && guardian.can_mention_here?
|
|
here_count = PostAlerter.new.expand_here_mention(@topic.first_post, exclude_ids: [current_user.id]).size
|
|
end
|
|
|
|
serialized_groups = groups.values.reduce({}) do |hash, group|
|
|
serialized_group = { user_count: group.user_count }
|
|
|
|
if group_reasons[group.name] == :not_allowed &&
|
|
members_visible_group_ids.include?(group.id) &&
|
|
(@topic&.private_message? || @allowed_names.present?)
|
|
|
|
# Find users that are notified already because they have been invited
|
|
# directly or via a group
|
|
notified_count = GroupUser
|
|
# invited directly
|
|
.where(user_id: topic_allowed_user_ids)
|
|
.or(
|
|
# invited via a group
|
|
GroupUser.where(
|
|
user_id: GroupUser.where(group_id: topic_allowed_group_ids).select(:user_id)
|
|
)
|
|
)
|
|
.where(group_id: group.id)
|
|
.select(:user_id).distinct.count
|
|
|
|
if notified_count > 0
|
|
group_reasons[group.name] = :some_not_allowed
|
|
serialized_group[:notified_count] = notified_count
|
|
end
|
|
end
|
|
|
|
hash[group.name] = serialized_group
|
|
hash
|
|
end
|
|
|
|
render json: {
|
|
users: users.keys,
|
|
user_reasons: user_reasons,
|
|
groups: serialized_groups,
|
|
group_reasons: group_reasons,
|
|
here_count: here_count,
|
|
max_users_notified_per_group_mention: SiteSetting.max_users_notified_per_group_mention,
|
|
}
|
|
end
|
|
|
|
private
|
|
|
|
def user_reason(user)
|
|
reason = if @topic && !user.guardian.can_see?(@topic)
|
|
@topic.private_message? ? :private : :category
|
|
elsif @allowed_names.present? && !is_user_allowed?(user, topic_allowed_user_ids, topic_allowed_group_ids)
|
|
# This would normally be handled by the previous if, but that does not work for new private messages.
|
|
:private
|
|
elsif topic_muted_by.include?(user.id)
|
|
:muted_topic
|
|
elsif @topic&.private_message? && !is_user_allowed?(user, topic_allowed_user_ids, topic_allowed_group_ids)
|
|
# Admins can see the topic, but they will not be mentioned if they were not invited.
|
|
:not_allowed
|
|
end
|
|
|
|
# Regular users can see only basic information why the users cannot see the topic.
|
|
reason = nil if !guardian.is_staff? && reason != :private && reason != :category
|
|
|
|
reason
|
|
end
|
|
|
|
def group_reason(group)
|
|
if !mentionable_group_ids.include?(group.id)
|
|
:not_mentionable
|
|
elsif (@topic&.private_message? || @allowed_names.present?) && !topic_allowed_group_ids.include?(group.id)
|
|
:not_allowed
|
|
end
|
|
end
|
|
|
|
def is_user_allowed?(user, user_ids, group_ids)
|
|
user_ids.include?(user.id) || user.group_ids.any? { |group_id| group_ids.include?(group_id) }
|
|
end
|
|
|
|
def users
|
|
@users ||= User
|
|
.not_staged
|
|
.where(username_lower: @names.map(&:downcase))
|
|
.index_by(&:username_lower)
|
|
end
|
|
|
|
def groups
|
|
@groups ||= Group
|
|
.visible_groups(current_user)
|
|
.where('lower(name) IN (?)', @names.map(&:downcase))
|
|
.index_by(&:name)
|
|
end
|
|
|
|
def mentionable_group_ids
|
|
@mentionable_group_ids ||= Group
|
|
.mentionable(current_user, include_public: false)
|
|
.where(name: @names)
|
|
.pluck(:id)
|
|
.to_set
|
|
end
|
|
|
|
def members_visible_group_ids
|
|
@members_visible_group_ids ||= Group
|
|
.members_visible_groups(current_user)
|
|
.where(name: @names)
|
|
.pluck(:id)
|
|
.to_set
|
|
end
|
|
|
|
def topic_muted_by
|
|
@topic_muted_by ||= if @topic.present?
|
|
TopicUser
|
|
.where(topic: @topic)
|
|
.where(user_id: users.values.map(&:id))
|
|
.where(notification_level: TopicUser.notification_levels[:muted])
|
|
.pluck(:user_id)
|
|
.to_set
|
|
else
|
|
Set.new
|
|
end
|
|
end
|
|
|
|
def topic_allowed_user_ids
|
|
@topic_allowed_user_ids ||= if @allowed_names.present?
|
|
User
|
|
.where(username_lower: @allowed_names.map(&:downcase))
|
|
.pluck(:id)
|
|
.to_set
|
|
elsif @topic&.private_message?
|
|
TopicAllowedUser
|
|
.where(topic: @topic)
|
|
.pluck(:user_id)
|
|
.to_set
|
|
end
|
|
end
|
|
|
|
def topic_allowed_group_ids
|
|
@topic_allowed_group_ids ||= if @allowed_names.present?
|
|
Group
|
|
.messageable(current_user)
|
|
.where(name: @allowed_names)
|
|
.pluck(:id)
|
|
.to_set
|
|
elsif @topic&.private_message?
|
|
TopicAllowedGroup
|
|
.where(topic: @topic)
|
|
.pluck(:group_id)
|
|
.to_set
|
|
end
|
|
end
|
|
end
|