mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-22 17:41:55 +08:00
Currently, the trust level method is calculating trust level based on maximum value from:
- locked trust level
- group automatic trust level
- previously granted trust level by admin
https://github.com/discourse/discourse/blob/main/lib/trust_level.rb#L33
Let's say the user belongs to groups with automatic trust level 1 and in the meantime meets all criteria to get trust level 2.
Each time, a user is removed from a group with automatic trust_level 1, they will be downgraded to trust_level 1 and promoted to trust_level 2
120a2f70a9/lib/promotion.rb (L142)
This will cause duplicated promotion messages.
Therefore, we have to check if the user meets the criteria, before downgrading.
329 lines
11 KiB
Ruby
Vendored
329 lines
11 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe GroupUser do
|
|
fab!(:group)
|
|
fab!(:user)
|
|
|
|
describe "callbacks" do
|
|
it "increments and decrements `Group#user_count` when record is created and destroyed" do
|
|
group_user = GroupUser.new(user: user, group: group)
|
|
|
|
expect do group_user.save! end.to change { group.reload.user_count }.from(0).to(1)
|
|
|
|
expect do group_user.destroy! end.to change { group.reload.user_count }.from(1).to(0)
|
|
end
|
|
end
|
|
|
|
it "correctly sets notification level" do
|
|
moderator = Fabricate(:moderator)
|
|
|
|
gu = GroupUser.find_by(user_id: moderator.id, group_id: Group::AUTO_GROUPS[:moderators])
|
|
|
|
expect(gu.notification_level).to eq(NotificationLevels.all[:tracking])
|
|
|
|
group = Group.create!(name: "bob")
|
|
group.add(moderator)
|
|
group.save
|
|
|
|
gu = GroupUser.find_by(user_id: moderator.id, group_id: group.id)
|
|
expect(gu.notification_level).to eq(NotificationLevels.all[:watching])
|
|
|
|
group.remove(moderator)
|
|
group.save
|
|
|
|
group.default_notification_level = 1
|
|
group.save
|
|
|
|
group.add(moderator)
|
|
group.save
|
|
|
|
gu = GroupUser.find_by(user_id: moderator.id, group_id: group.id)
|
|
expect(gu.notification_level).to eq(NotificationLevels.all[:regular])
|
|
end
|
|
|
|
describe "default category notifications" do
|
|
fab!(:group)
|
|
fab!(:user)
|
|
fab!(:category1) { Fabricate(:category) }
|
|
fab!(:category2) { Fabricate(:category) }
|
|
fab!(:category3) { Fabricate(:category) }
|
|
fab!(:category4) { Fabricate(:category) }
|
|
fab!(:category5) { Fabricate(:category) }
|
|
|
|
def levels
|
|
CategoryUser.notification_levels
|
|
end
|
|
|
|
it "doesn't change anything with no configured defaults" do
|
|
expect { group.add(user) }.to_not change { CategoryUser.count }
|
|
end
|
|
|
|
it "adds new category notifications" do
|
|
group.muted_category_ids = [category1.id]
|
|
group.regular_category_ids = [category2.id]
|
|
group.tracking_category_ids = [category3.id]
|
|
group.watching_category_ids = [category4.id]
|
|
group.watching_first_post_category_ids = [category5.id]
|
|
group.save!
|
|
expect { group.add(user) }.to change { CategoryUser.count }.by(5)
|
|
h = CategoryUser.notification_levels_for(user)
|
|
expect(h[category1.id]).to eq(levels[:muted])
|
|
expect(h[category2.id]).to eq(levels[:regular])
|
|
expect(h[category3.id]).to eq(levels[:tracking])
|
|
expect(h[category4.id]).to eq(levels[:watching])
|
|
expect(h[category5.id]).to eq(levels[:watching_first_post])
|
|
end
|
|
|
|
it "only upgrades notifications" do
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category1.id,
|
|
notification_level: levels[:muted],
|
|
)
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category2.id,
|
|
notification_level: levels[:tracking],
|
|
)
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category3.id,
|
|
notification_level: levels[:watching_first_post],
|
|
)
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category4.id,
|
|
notification_level: levels[:watching],
|
|
)
|
|
group.regular_category_ids = [category1.id]
|
|
group.watching_first_post_category_ids = [category2.id, category3.id, category4.id]
|
|
group.save!
|
|
group.add(user)
|
|
h = CategoryUser.notification_levels_for(user)
|
|
expect(h[category1.id]).to eq(levels[:regular])
|
|
expect(h[category2.id]).to eq(levels[:watching_first_post])
|
|
expect(h[category3.id]).to eq(levels[:watching_first_post])
|
|
expect(h[category4.id]).to eq(levels[:watching])
|
|
end
|
|
|
|
it "merges notifications" do
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category1.id,
|
|
notification_level: CategoryUser.notification_levels[:tracking],
|
|
)
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category2.id,
|
|
notification_level: CategoryUser.notification_levels[:watching],
|
|
)
|
|
CategoryUser.create!(
|
|
user: user,
|
|
category_id: category4.id,
|
|
notification_level: CategoryUser.notification_levels[:watching_first_post],
|
|
)
|
|
group.muted_category_ids = [category3.id]
|
|
group.tracking_category_ids = [category4.id]
|
|
group.save!
|
|
group.add(user)
|
|
h = CategoryUser.notification_levels_for(user)
|
|
expect(h[category1.id]).to eq(levels[:tracking])
|
|
expect(h[category2.id]).to eq(levels[:watching])
|
|
expect(h[category3.id]).to eq(levels[:muted])
|
|
expect(h[category4.id]).to eq(levels[:watching_first_post])
|
|
end
|
|
end
|
|
|
|
describe "default tag notifications" do
|
|
fab!(:group)
|
|
fab!(:user)
|
|
fab!(:tag1) { Fabricate(:tag) }
|
|
fab!(:tag2) { Fabricate(:tag) }
|
|
fab!(:tag3) { Fabricate(:tag) }
|
|
fab!(:tag4) { Fabricate(:tag) }
|
|
fab!(:tag5) { Fabricate(:tag) }
|
|
fab!(:synonym1) { Fabricate(:tag, target_tag: tag1) }
|
|
|
|
def levels
|
|
TagUser.notification_levels
|
|
end
|
|
|
|
it "doesn't change anything with no configured defaults" do
|
|
expect { group.add(user) }.to_not change { TagUser.count }
|
|
end
|
|
|
|
it "adds new tag notifications" do
|
|
group.muted_tags = [synonym1.name]
|
|
group.regular_tags = [tag2.name]
|
|
group.tracking_tags = [tag3.name]
|
|
group.watching_tags = [tag4.name]
|
|
group.watching_first_post_tags = [tag5.name]
|
|
group.save!
|
|
expect { group.add(user) }.to change { TagUser.count }.by(5)
|
|
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to eq([tag1.id])
|
|
expect(TagUser.lookup(user, :regular).pluck(:tag_id)).to eq([tag2.id])
|
|
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag3.id])
|
|
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag4.id])
|
|
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to eq([tag5.id])
|
|
end
|
|
|
|
it "only upgrades notifications" do
|
|
TagUser.create!(user: user, tag_id: tag1.id, notification_level: levels[:muted])
|
|
TagUser.create!(user: user, tag_id: tag2.id, notification_level: levels[:tracking])
|
|
TagUser.create!(user: user, tag_id: tag3.id, notification_level: levels[:watching_first_post])
|
|
TagUser.create!(user: user, tag_id: tag4.id, notification_level: levels[:watching])
|
|
group.regular_tags = [tag1.name]
|
|
group.watching_first_post_tags = [tag2.name, tag3.name, tag4.name]
|
|
group.save!
|
|
group.add(user)
|
|
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to be_empty
|
|
expect(TagUser.lookup(user, :regular).pluck(:tag_id)).to eq([tag1.id])
|
|
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to be_empty
|
|
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag4.id])
|
|
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to contain_exactly(
|
|
tag2.id,
|
|
tag3.id,
|
|
)
|
|
end
|
|
|
|
it "merges notifications" do
|
|
TagUser.create!(user: user, tag_id: tag1.id, notification_level: levels[:tracking])
|
|
TagUser.create!(user: user, tag_id: tag2.id, notification_level: levels[:watching])
|
|
TagUser.create!(user: user, tag_id: tag4.id, notification_level: levels[:watching_first_post])
|
|
group.muted_tags = [tag3.name]
|
|
group.tracking_tags = [tag2.name]
|
|
group.save!
|
|
group.add(user)
|
|
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to eq([tag3.id])
|
|
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag1.id])
|
|
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag2.id])
|
|
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to eq([tag4.id])
|
|
end
|
|
end
|
|
|
|
describe "#ensure_consistency!" do
|
|
fab!(:group)
|
|
fab!(:group_2) { Fabricate(:group) }
|
|
|
|
fab!(:pm_post) { Fabricate(:private_message_post) }
|
|
|
|
fab!(:pm_topic) { pm_post.topic.tap { |t| t.allowed_groups << group } }
|
|
|
|
fab!(:user) do
|
|
Fabricate(:user, last_seen_at: Time.zone.now).tap do |u|
|
|
group.add(u)
|
|
group_2.add(u)
|
|
|
|
TopicUser.change(
|
|
u.id,
|
|
pm_topic.id,
|
|
notification_level: TopicUser.notification_levels[:tracking],
|
|
last_read_post_number: pm_post.post_number,
|
|
)
|
|
end
|
|
end
|
|
|
|
# User that is not tracking topic
|
|
fab!(:user_2) do
|
|
Fabricate(:user, last_seen_at: Time.zone.now).tap do |u|
|
|
group.add(u)
|
|
|
|
TopicUser.change(
|
|
u.id,
|
|
pm_topic.id,
|
|
notification_level: TopicUser.notification_levels[:regular],
|
|
last_read_post_number: pm_post.post_number,
|
|
)
|
|
end
|
|
end
|
|
|
|
# User that has not been seen
|
|
fab!(:user_3) do
|
|
Fabricate(:user).tap do |u|
|
|
group.add(u)
|
|
|
|
TopicUser.change(
|
|
u.id,
|
|
pm_topic.id,
|
|
notification_level: TopicUser.notification_levels[:tracking],
|
|
last_read_post_number: pm_post.post_number,
|
|
)
|
|
end
|
|
end
|
|
|
|
it "updates first unread pm timestamp correctly" do
|
|
freeze_time 10.minutes.from_now
|
|
|
|
post = create_post(user: pm_topic.user, topic_id: pm_topic.id)
|
|
|
|
expect { GroupUser.ensure_consistency! }.to_not change {
|
|
group.group_users.find_by(user_id: user_3.id).first_unread_pm_at
|
|
}
|
|
|
|
expect(post.topic.updated_at).to_not eq_time(10.minutes.ago)
|
|
expect(group.group_users.find_by(user_id: user.id).first_unread_pm_at).to eq_time(
|
|
post.topic.updated_at,
|
|
)
|
|
expect(group_2.group_users.find_by(user_id: user.id).first_unread_pm_at).to eq_time(
|
|
10.minutes.ago,
|
|
)
|
|
expect(group.group_users.find_by(user_id: user_2.id).first_unread_pm_at).to eq_time(
|
|
10.minutes.ago,
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "#destroy!" do
|
|
fab!(:group)
|
|
|
|
it "removes `primary_group_id`, `flair_group_id` and exec `match_primary_group_changes` method on user model" do
|
|
user = Fabricate(:user, primary_group: group, flair_group: group)
|
|
group_user = Fabricate(:group_user, group: group, user: user)
|
|
|
|
user.expects(:match_primary_group_changes).once
|
|
group_user.destroy!
|
|
|
|
user.reload
|
|
expect(user.primary_group_id).to be_nil
|
|
expect(user.flair_group_id).to be_nil
|
|
end
|
|
|
|
it "restores previous trust level" do
|
|
user = Fabricate(:user)
|
|
expect(user.trust_level).to eq(1)
|
|
|
|
user.change_trust_level!(1, log_action_for: Discourse.system_user)
|
|
user.change_trust_level!(2, log_action_for: Discourse.system_user)
|
|
group.update!(grant_trust_level: 4)
|
|
|
|
group_user = Fabricate(:group_user, group: group, user: user)
|
|
expect(user.reload.trust_level).to eq(4)
|
|
|
|
group_user.destroy!
|
|
# keep in mind that we do not restore tl3, cause reqs can be lost
|
|
expect(user.reload.trust_level).to eq(2)
|
|
end
|
|
|
|
it "protects user trust level if all requirements are met" do
|
|
Promotion.stubs(:tl2_met?).returns(true)
|
|
|
|
user = Fabricate(:user)
|
|
expect(user.trust_level).to eq(1)
|
|
|
|
group.update!(grant_trust_level: 1)
|
|
|
|
Promotion.recalculate(user)
|
|
expect(user.reload.trust_level).to eq(2)
|
|
|
|
group_user = Fabricate(:group_user, group: group, user: user)
|
|
expect_not_enqueued_with(
|
|
job: :send_system_message,
|
|
args: {
|
|
user_id: user.id,
|
|
message_type: "tl2_promotion_message",
|
|
},
|
|
) { group_user.destroy! }
|
|
expect(user.reload.trust_level).to eq(2)
|
|
end
|
|
end
|
|
end
|