FIX: chat direct message group user limit is off by 1 (#27014)

This change allows the correct number of members to be added when creating a group direct message, based on the site setting chat_max_direct_message_users.

Previously we counted the current user within the max user limit and therefore the count was off by 1.
This commit is contained in:
David Battersby 2024-06-03 12:11:49 +04:00 committed by GitHub
parent 82cccf89e1
commit 4e80c9eb13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 35 additions and 35 deletions

View File

@ -36,6 +36,9 @@ class Chat::Api::ChannelsMembershipsController < Chat::Api::ChannelsController
on_failed_policy(:can_add_users_to_channel) do on_failed_policy(:can_add_users_to_channel) do
render_json_error(I18n.t("chat.errors.users_cant_be_added_to_channel")) render_json_error(I18n.t("chat.errors.users_cant_be_added_to_channel"))
end end
on_failed_policy(:satisfies_dms_max_users_limit) do |policy|
render_json_dump({ error: policy.reason }, status: 400)
end
on_failed_contract do |contract| on_failed_contract do |contract|
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400) render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
end end

View File

@ -25,10 +25,11 @@ module Chat
contract contract
model :channel model :channel
policy :can_add_users_to_channel policy :can_add_users_to_channel
model :users, optional: true model :target_users, optional: true
policy :satisfies_dms_max_users_limit,
class_name: Chat::DirectMessageChannel::MaxUsersExcessPolicy
transaction do transaction do
step :validate_user_count
step :upsert_memberships step :upsert_memberships
step :recompute_users_count step :recompute_users_count
step :notice_channel step :notice_channel
@ -56,7 +57,7 @@ module Chat
channel.direct_message_channel? && channel.chatable.group channel.direct_message_channel? && channel.chatable.group
end end
def fetch_users(contract:, channel:) def fetch_target_users(contract:, channel:)
::Chat::UsersFromUsernamesAndGroupsQuery.call( ::Chat::UsersFromUsernamesAndGroupsQuery.call(
usernames: contract.usernames, usernames: contract.usernames,
groups: contract.groups, groups: contract.groups,
@ -68,17 +69,11 @@ module Chat
::Chat::Channel.includes(:chatable).find_by(id: contract.channel_id) ::Chat::Channel.includes(:chatable).find_by(id: contract.channel_id)
end end
def validate_user_count(channel:, users:) def upsert_memberships(channel:, target_users:)
if channel.user_count + users.length > SiteSetting.chat_max_direct_message_users
fail!("should have less than #{SiteSetting.chat_max_direct_message_users} elements")
end
end
def upsert_memberships(channel:, users:)
always_level = ::Chat::UserChatChannelMembership::NOTIFICATION_LEVELS[:always] always_level = ::Chat::UserChatChannelMembership::NOTIFICATION_LEVELS[:always]
memberships = memberships =
users.map do |user| target_users.map do |user|
{ {
user_id: user.id, user_id: user.id,
chat_channel_id: channel.id, chat_channel_id: channel.id,
@ -128,8 +123,8 @@ module Chat
) )
end end
def notice_channel(guardian:, channel:, users:) def notice_channel(guardian:, channel:, target_users:)
added_users = users.select { |u| context.added_user_ids.include?(u.id) } added_users = target_users.select { |u| context.added_user_ids.include?(u.id) }
return if added_users.blank? return if added_users.blank?

View File

@ -27,6 +27,10 @@ export default class AddMembers extends Component {
return userCount + (this.args.channel?.membershipsCount ?? 0); return userCount + (this.args.channel?.membershipsCount ?? 0);
} }
get maxMembers() {
return this.siteSettings.chat_max_direct_message_users;
}
@action @action
async saveGroupMembers() { async saveGroupMembers() {
try { try {
@ -60,10 +64,7 @@ export default class AddMembers extends Component {
<template> <template>
<div class="chat-message-creator__add-members-container"> <div class="chat-message-creator__add-members-container">
<div class="chat-message-creator__add-members"> <div class="chat-message-creator__add-members">
<MembersCount <MembersCount @count={{this.membersCount}} @max={{this.maxMembers}} />
@count={{this.membersCount}}
@max={{this.siteSettings.chat_max_direct_message_users}}
/>
<MembersSelector <MembersSelector
@channel={{@channel}} @channel={{@channel}}
@ -72,10 +73,7 @@ export default class AddMembers extends Component {
@close={{@close}} @close={{@close}}
@cancel={{@cancel}} @cancel={{@cancel}}
@membersCount={{this.membersCount}} @membersCount={{this.membersCount}}
@maxReached={{gte @maxReached={{gte this.membersCount this.maxMembers}}
this.membersCount
this.siteSettings.chat_max_direct_message_users
}}
/> />
{{#if @members.length}} {{#if @members.length}}

View File

@ -26,7 +26,11 @@ export default class NewGroup extends Component {
} else { } else {
return acc + 1; return acc + 1;
} }
}, 1); }, 0);
}
get maxMembers() {
return this.siteSettings.chat_max_direct_message_users;
} }
@action @action
@ -82,10 +86,7 @@ export default class NewGroup extends Component {
@close={{@close}} @close={{@close}}
@cancel={{@cancel}} @cancel={{@cancel}}
@membersCount={{this.membersCount}} @membersCount={{this.membersCount}}
@maxReached={{gte @maxReached={{gte this.membersCount this.maxMembers}}
this.membersCount
this.siteSettings.chat_max_direct_message_users
}}
/> />
{{#if @members.length}} {{#if @members.length}}

View File

@ -29,12 +29,12 @@ RSpec.describe Chat::AddUsersToChannel do
before { channel.add(current_user) } before { channel.add(current_user) }
it "fetches users to add" do it "fetches users to add" do
expect(result.users.map(&:username)).to contain_exactly(*users.map(&:username)) expect(result.target_users.map(&:username)).to contain_exactly(*users.map(&:username))
end end
it "includes users from groups" do it "includes users from groups" do
params.merge!(groups: [group.name]) params.merge!(groups: [group.name])
expect(result.users.map(&:username)).to include( expect(result.target_users.map(&:username)).to include(
group_user_1.username, group_user_1.username,
group_user_2.username, group_user_2.username,
) )
@ -59,7 +59,9 @@ RSpec.describe Chat::AddUsersToChannel do
it "doesn't include existing direct message users" do it "doesn't include existing direct message users" do
Chat::DirectMessageUser.create!(user: users.first, direct_message: direct_message) Chat::DirectMessageUser.create!(user: users.first, direct_message: direct_message)
expect(result.users.map(&:username)).to contain_exactly(*users[1..-1].map(&:username)) expect(result.target_users.map(&:username)).to contain_exactly(
*users[1..-1].map(&:username),
)
end end
it "creates memberships" do it "creates memberships" do
@ -77,7 +79,7 @@ RSpec.describe Chat::AddUsersToChannel do
end end
it "creates a chat message to show added users" do it "creates a chat message to show added users" do
added_users = result.users added_users = result.target_users
channel.chat_messages.last.tap do |message| channel.chat_messages.last.tap do |message|
expect(message.message).to eq( expect(message.message).to eq(
@ -93,10 +95,10 @@ RSpec.describe Chat::AddUsersToChannel do
end end
end end
context "when usernames exceeds chat_max_direct_message_users" do context "when users exceed max direct message user limit" do
before { SiteSetting.chat_max_direct_message_users = 4 } before { SiteSetting.chat_max_direct_message_users = 4 }
it { is_expected.to fail_a_step(:validate_user_count) } it { is_expected.to fail_a_policy(:satisfies_dms_max_users_limit) }
end end
context "when channel is not found" do context "when channel is not found" do

View File

@ -111,15 +111,16 @@ RSpec.describe "Flag message", type: :system do
user_1 = Fabricate(:user) user_1 = Fabricate(:user)
user_2 = Fabricate(:user) user_2 = Fabricate(:user)
user_3 = Fabricate(:user) user_3 = Fabricate(:user)
group = Fabricate(:public_group, users: [user_1, user_2]) user_4 = Fabricate(:user)
group = Fabricate(:public_group, users: [user_1, user_2, user_3])
visit("/") visit("/")
chat_page.prefers_full_page chat_page.prefers_full_page
chat_page.open_new_message chat_page.open_new_message
chat_page.find("#new-group-chat").click chat_page.find("#new-group-chat").click
chat_page.find(".chat-message-creator__new-group-header__input").fill_in(with: "hamsters") chat_page.find(".chat-message-creator__new-group-header__input").fill_in(with: "hamsters")
chat_page.find(".chat-message-creator__members-input").fill_in(with: user_3.username) chat_page.find(".chat-message-creator__members-input").fill_in(with: user_4.username)
chat_page.message_creator.click_row(user_3) chat_page.message_creator.click_row(user_4)
chat_page.find(".chat-message-creator__members-input").fill_in(with: group.name) chat_page.find(".chat-message-creator__members-input").fill_in(with: group.name)
chat_page.message_creator.click_row(group) chat_page.message_creator.click_row(group)