Skip to content

Commit

Permalink
FIX: recalculating trust levels was not working (discourse#20492)
Browse files Browse the repository at this point in the history
The recalculate code was never firing cause TrustLevel.calculate unconditionally
returned a trust level. (albeit a wrong one)

New code ensures we only bypass promotion checks for cases where trust level
is locked.

see: https://meta.discourse.org/t/user-trust-level-resets-to-zero-when-unlocked/255444
  • Loading branch information
SamSaffron authored Mar 1, 2023
1 parent 8a2995f commit 71be74f
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 18 deletions.
24 changes: 15 additions & 9 deletions lib/promotion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,23 @@ def self.tl3_lost?(user)
# Figure out what a user's trust level should be from scratch
def self.recalculate(user, performed_by = nil, use_previous_trust_level: false)
granted_trust_level =
TrustLevel.calculate(user, use_previous_trust_level: use_previous_trust_level)
return user.update(trust_level: granted_trust_level) if granted_trust_level.present?
TrustLevel.calculate(user, use_previous_trust_level: use_previous_trust_level) ||
TrustLevel[0]

user.update_column(:trust_level, TrustLevel[0])
# TrustLevel.calculate always returns a value, however we added extra protection just
# in case this changes
user.update_column(:trust_level, TrustLevel[granted_trust_level])

p = Promotion.new(user)
p.review_tl0
p.review_tl1
p.review_tl2
if user.trust_level == 3 && Promotion.tl3_lost?(user)
user.change_trust_level!(2, log_action_for: performed_by || Discourse.system_user)
return if user.manual_locked_trust_level.present?

promotion = Promotion.new(user)

promotion.review_tl0 if granted_trust_level < TrustLevel[1]
promotion.review_tl1 if granted_trust_level < TrustLevel[2]
promotion.review_tl2 if granted_trust_level < TrustLevel[3]

if user.trust_level == TrustLevel[3] && Promotion.tl3_lost?(user)
user.change_trust_level!(TrustLevel[2], log_action_for: performed_by || Discourse.system_user)
end
end
end
2 changes: 1 addition & 1 deletion lib/trust_level.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def self.calculate(user, use_previous_trust_level: false)
granted_trust_level = user.group_granted_trust_level || 0
previous_trust_level = use_previous_trust_level ? find_previous_trust_level(user) : 0

[granted_trust_level, previous_trust_level].max
[granted_trust_level, previous_trust_level, SiteSetting.default_trust_level].max
end

private
Expand Down
9 changes: 9 additions & 0 deletions spec/lib/promotion_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,18 @@
stat.posts_read_count = SiteSetting.tl1_requires_read_posts
stat.time_read = SiteSetting.tl1_requires_time_spent_mins * 60
Promotion.recalculate(user)

expect(user.trust_level).to eq(1)

expect(Jobs::SendSystemMessage.jobs.length).to eq(0)
end

it "respects default trust level" do
SiteSetting.default_trust_level = 2
Promotion.recalculate(user)
expect(user.trust_level).to eq(2)
end

it "can be turned off" do
SiteSetting.send_tl1_welcome_message = false
@result = promotion.review
Expand Down
16 changes: 10 additions & 6 deletions spec/models/group_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def real_staff
tl3_users = Group.find(Group::AUTO_GROUPS[:trust_level_3])
tl3_users.add(user)

events = DiscourseEvent.track_events { Group.refresh_automatic_group!(:trust_level_3) }
_events = DiscourseEvent.track_events { Group.refresh_automatic_group!(:trust_level_3) }

expect(GroupUser.exists?(group: tl3_users, user: user)).to eq(false)
publish_event_job_args = Jobs::PublishGroupMembershipUpdates.jobs.last["args"].first
Expand All @@ -267,7 +267,7 @@ def real_staff

expect(GroupUser.exists?(group: tl0_users, user: user)).to eq(false)

events = DiscourseEvent.track_events { Group.refresh_automatic_group!(:trust_level_0) }
_events = DiscourseEvent.track_events { Group.refresh_automatic_group!(:trust_level_0) }

expect(GroupUser.exists?(group: tl0_users, user: user)).to eq(true)
publish_event_job_args = Jobs::PublishGroupMembershipUpdates.jobs.last["args"].first
Expand Down Expand Up @@ -641,20 +641,24 @@ def real_staff
describe "when a user has qualified for trust level 1" do
fab!(:user) { Fabricate(:user, trust_level: 1, created_at: Time.zone.now - 10.years) }

fab!(:group) { Fabricate(:group, grant_trust_level: 1) }
fab!(:group2) { Fabricate(:group, grant_trust_level: 0) }
fab!(:group) { Fabricate(:group, grant_trust_level: 3) }
fab!(:group2) { Fabricate(:group, grant_trust_level: 2) }

before { user.user_stat.update!(topics_entered: 999, posts_read_count: 999, time_read: 999) }

it "should not demote the user" do
group.add(user)
group2.add(user)

expect(user.reload.trust_level).to eq(1)
expect(user.reload.trust_level).to eq(3)

group.remove(user)

expect(user.reload.trust_level).to eq(0)
expect(user.reload.trust_level).to eq(2)

group2.remove(user)

expect(user.reload.trust_level).to eq(1)
end
end

Expand Down
5 changes: 3 additions & 2 deletions spec/models/group_user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,16 @@ def levels
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)
user.change_trust_level!(3, 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!
expect(user.reload.trust_level).to eq(3)
# keep in mind that we do not restore tl3, cause reqs can be lost
expect(user.reload.trust_level).to eq(2)
end
end
end

0 comments on commit 71be74f

Please sign in to comment.