mirror of
https://github.com/discourse/discourse.git
synced 2024-12-28 13:13:51 +08:00
e4849445ce
Previously, a "`some_not_allowed`" warning message was appeared in composer even when all the users mentioned via group are already invited to the private message directly or via other groups.
183 lines
5.7 KiB
Ruby
183 lines
5.7 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
|
|
if notified_count == group.user_count
|
|
group_reasons.delete(group.name)
|
|
else
|
|
group_reasons[group.name] = :some_not_allowed
|
|
serialized_group[:notified_count] = notified_count
|
|
end
|
|
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
|
|
|
|
# Non-staff 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
|