prevent users with a tiny number of posts to dominate the 'new user of the month' leaderboard

This commit is contained in:
Régis Hanol 2018-01-29 12:09:17 +01:00
parent 52fbf9d3ae
commit 77ac14d475
2 changed files with 33 additions and 41 deletions

View File

@ -33,8 +33,6 @@ module Jobs
end
def scores
scores = {}
current_owners = UserBadge.where(badge_id: Badge::NewUserOfTheMonth).pluck(:user_id)
current_owners = [-1] if current_owners.blank?
@ -44,49 +42,43 @@ module Jobs
sql = <<~SQL
SELECT u.id,
SUM(CASE
WHEN pa.id IS NOT NULL THEN
CASE
WHEN liked_by.id <= 0 THEN 0.0
WHEN liked_by.admin OR liked_by.moderator THEN 2.0
WHEN liked_by.trust_level = 0 THEN 0.1
WHEN liked_by.trust_level = 1 THEN 0.25
WHEN liked_by.trust_level = 2 THEN 1.0
WHEN liked_by.trust_level = 3 THEN 1.5
WHEN liked_by.trust_level = 4 THEN 2.0
ELSE 1.0
END
ELSE 0
END) / COUNT(DISTINCT p.id) AS score
WHEN pa.id IS NOT NULL THEN
CASE
WHEN liked_by.id <= 0 THEN 0.0
WHEN liked_by.admin THEN 3.0
WHEN liked_by.moderator THEN 3.0
WHEN liked_by.trust_level = 4 THEN 2.0
WHEN liked_by.trust_level = 3 THEN 1.5
WHEN liked_by.trust_level = 2 THEN 1.0
WHEN liked_by.trust_level = 1 THEN 0.25
WHEN liked_by.trust_level = 0 THEN 0.1
ELSE 1.0
END
ELSE 0
END) / (5 + COUNT(DISTINCT p.id)) AS score
FROM users AS u
INNER JOIN user_stats AS us ON u.id = us.user_id
LEFT OUTER JOIN posts AS p ON p.user_id = u.id
LEFT OUTER JOIN post_actions AS pa ON
pa.post_id = p.id AND pa.post_action_type_id = :like
LEFT OUTER JOIN users AS liked_by ON liked_by.id = pa.user_id
LEFT OUTER JOIN topics AS t ON t.id = p.topic_id
WHERE u.active AND
u.id > 0 AND
NOT(u.admin) AND
NOT(u.moderator) AND
t.archetype <> '#{Archetype.private_message}' AND
u.created_at >= CURRENT_TIMESTAMP - '1 month'::INTERVAL AND
u.id NOT IN (#{current_owners.join(',')})
INNER JOIN user_stats AS us ON u.id = us.user_id
LEFT OUTER JOIN posts AS p ON p.user_id = u.id
LEFT OUTER JOIN post_actions AS pa ON pa.post_id = p.id AND pa.post_action_type_id = #{PostActionType.types[:like]}
LEFT OUTER JOIN users AS liked_by ON liked_by.id = pa.user_id
LEFT OUTER JOIN topics AS t ON t.id = p.topic_id
WHERE u.active
AND u.id > 0
AND NOT u.staged
AND NOT u.admin
AND NOT u.moderator
AND t.archetype <> '#{Archetype.private_message}'
AND u.created_at >= CURRENT_TIMESTAMP - '1 month'::INTERVAL
AND u.id NOT IN (#{current_owners.join(',')})
GROUP BY u.id
HAVING COUNT(DISTINCT p.id) > 1
AND COUNT(DISTINCT p.topic_id) > 1
AND COUNT(pa.id) > 1
AND COUNT(DISTINCT p.topic_id) > 1
AND COUNT(pa.id) > 1
ORDER BY score DESC
LIMIT :max_awarded
LIMIT #{MAX_AWARDED}
SQL
User.exec_sql(
sql,
like: PostActionType.types[:like],
max_awarded: MAX_AWARDED
).each do |row|
scores[row['id'].to_i] = row['score'].to_f
end
scores
User.exec_sql(sql).map { |r| [r['id'].to_i, r['score'].to_f] }.to_h
end
end

View File

@ -162,11 +162,11 @@ describe Jobs::GrantNewUserOfTheMonthBadges do
PostAction.act(um, p, PostActionType.types[:like])
PostAction.act(ua, p, PostActionType.types[:like])
PostAction.act(Discourse.system_user, p, PostActionType.types[:like])
expect(granter.scores[user.id]).to eq(4.425)
expect(granter.scores[user.id]).to eq(1.55)
# It goes down the more they post
Fabricate(:post, user: user)
expect(granter.scores[user.id]).to eq(2.95)
expect(granter.scores[user.id]).to eq(1.35625)
end
it "is limited to two accounts" do