0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 10:40:48 +08:00
discourse/spec/services/group_action_logger_spec.rb
Bannon Tanner 0acfe07701
PERF: Add Users to Group Improvements Pt. 2 (#38901)
Pt. 2 of the performance update to group add/remove users, building on
#38737

This PR moves the bulk_add/remove logic from the `Group` model into
`GroupManager`, making `GroupManager` the single owner of membership
mutation logic. `Group#bulk_add` and `Group#bulk_remove` become thin
delegators.

The controller's per-user `add_user_to_group` loop is replaced with a
single bulk `add_users_to_group` call. `GroupActionLogger` gets
`bulk_log_add_users_to_group` / `bulk_log_remove_users_from_group`
backed by `insert_all`. `DiscourseConnect` routes through `GroupManager`
instead of raw `GroupUser.create!/destroy_all`

Also moves notifications for adding users to a group to a background
job, as that was running synchronously and causing performance issues
when `notify_users: true`

There will be a Pt. 3 (#39091) that updates all callers using some
variation of `GroupUser.create` and removes callbacks from `GroupUser`
2026-04-06 09:31:50 -05:00

212 lines
6.9 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe GroupActionLogger do
subject(:logger) { described_class.new(group_owner, group) }
fab!(:group_owner, :user)
fab!(:group)
fab!(:user)
before { group.add_owner(group_owner) }
describe "#log_make_user_group_owner" do
it "should create the right record" do
logger.log_make_user_group_owner(user)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:make_user_group_owner])
expect(group_history.acting_user).to eq(group_owner)
expect(group_history.target_user).to eq(user)
end
end
describe "#log_remove_user_as_group_owner" do
it "should create the right record" do
logger.log_remove_user_as_group_owner(user)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:remove_user_as_group_owner])
expect(group_history.acting_user).to eq(group_owner)
expect(group_history.target_user).to eq(user)
end
end
describe "#log_add_user_to_group" do
context "as a group owner" do
it "should create the right record" do
logger.log_add_user_to_group(user)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group])
expect(group_history.acting_user).to eq(group_owner)
expect(group_history.target_user).to eq(user)
end
end
context "as a normal user" do
subject(:logger) { described_class.new(user, group) }
before { group.update!(public_admission: true) }
it "should create the right record" do
logger.log_add_user_to_group(user)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group])
expect(group_history.acting_user).to eq(user)
expect(group_history.target_user).to eq(user)
end
end
end
describe "#log_remove_user_from_group" do
context "as group owner" do
it "should create the right record" do
logger.log_remove_user_from_group(user)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:remove_user_from_group])
expect(group_history.acting_user).to eq(group_owner)
expect(group_history.target_user).to eq(user)
end
end
context "as a normal user" do
subject(:logger) { described_class.new(user, group) }
before { group.update!(public_exit: true) }
it "should create the right record" do
logger.log_remove_user_from_group(user)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:remove_user_from_group])
expect(group_history.acting_user).to eq(user)
expect(group_history.target_user).to eq(user)
end
end
end
describe "#bulk_log_add_users_to_group" do
fab!(:user2, :user)
it "creates a record for each user" do
expect { logger.bulk_log_add_users_to_group([user.id, user2.id]) }.to change {
GroupHistory.where(action: GroupHistory.actions[:add_user_to_group]).count
}.by(2)
records =
GroupHistory.where(action: GroupHistory.actions[:add_user_to_group], group: group).last(2)
expect(records.map(&:acting_user)).to all(eq(group_owner))
expect(records.map(&:target_user)).to contain_exactly(user, user2)
end
it "does nothing when target_users is empty" do
expect { logger.bulk_log_add_users_to_group([]) }.not_to change { GroupHistory.count }
end
it "forwards the subject when present" do
logger.bulk_log_add_users_to_group([user.id], "added_users")
expect(GroupHistory.last.subject).to eq("added_users")
end
end
describe "#bulk_log_remove_users_from_group" do
fab!(:user2, :user)
it "creates a record for each user" do
expect { logger.bulk_log_remove_users_from_group([user.id, user2.id]) }.to change {
GroupHistory.where(action: GroupHistory.actions[:remove_user_from_group]).count
}.by(2)
records =
GroupHistory.where(
action: GroupHistory.actions[:remove_user_from_group],
group: group,
).last(2)
expect(records.map(&:acting_user)).to all(eq(group_owner))
expect(records.map(&:target_user)).to contain_exactly(user, user2)
end
it "does nothing when target_users is empty" do
expect { logger.bulk_log_remove_users_from_group([]) }.not_to change { GroupHistory.count }
end
it "forwards the subject when present" do
logger.bulk_log_remove_users_from_group([user.id], "remove_users")
expect(GroupHistory.last.subject).to eq("remove_users")
end
end
describe "#log_group_creation" do
subject(:log_creation) { logger.log_group_creation }
let(:owner_history) do
GroupHistory.where(group:, action: GroupHistory.actions[:make_user_group_owner])
end
let(:member_history) do
GroupHistory.where(group:, action: GroupHistory.actions[:add_user_to_group])
end
context "when group has only an owner" do
it "logs make_user_group_owner for the owner" do
expect { log_creation }.to change { owner_history.count }.by(1)
expect(owner_history).to contain_exactly(
an_object_having_attributes(acting_user: group_owner, target_user: group_owner),
)
end
it "logs add_user_to_group for the owner" do
expect { log_creation }.to change { member_history.count }.by(1)
expect(member_history).to contain_exactly(
an_object_having_attributes(acting_user: group_owner, target_user: group_owner),
)
end
end
context "when group has an owner and a member" do
before { group.add(user) }
it "logs make_user_group_owner only for the owner" do
expect { log_creation }.to change { owner_history.count }.by(1)
expect(owner_history).to contain_exactly(
an_object_having_attributes(acting_user: group_owner, target_user: group_owner),
)
end
it "logs add_user_to_group for both owner and member" do
expect { log_creation }.to change { member_history.count }.by(2)
expect(member_history).to contain_exactly(
an_object_having_attributes(acting_user: group_owner, target_user: group_owner),
an_object_having_attributes(acting_user: group_owner, target_user: user),
)
end
end
end
describe "#log_change_group_settings" do
it "should create the right record" do
group.update!(public_admission: true, created_at: Time.zone.now)
expect { logger.log_change_group_settings }.to change { GroupHistory.count }.by(1)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:change_group_setting])
expect(group_history.acting_user).to eq(group_owner)
expect(group_history.subject).to eq("public_admission")
expect(group_history.prev_value).to eq("f")
expect(group_history.new_value).to eq("t")
end
end
end