reenable article rescoring when moderators flag users (#12983)

* Update worker calculation and disable early return

* Enable service tests

This updates the test to look at the individual article scores
changing, rather than the sum of the articles scores changing

The scores lambda was added as a way to observe this eagerly

* Correctly handle raising the score when vomit is cleared

The initial implementation loaded the articles reactions and the
user's reactions in order to rescore. This restores that activity.

It occurs to me that article.reactions.sum(:points) +
user.reactions.sum(:points) feels like something articles should know
how to do, in which case we can move this into article (#rescore!)?
and call that instead of knowing how to handle moderation specially here.

* Move logic to Article#update_score

Having realized "sum of reaction scores" was an Article concern, I
found that we have a worker to score articles that does _exactly_ what
we're doing here.

Let's use that and allow the vomit reaction presence or absence on a
user to automatically affect the article calculations.

This is at least n + 1 and maybe worse.
This commit is contained in:
Daniel Uber 2021-03-16 14:04:13 -05:00 committed by GitHub
parent 1b89d6c72b
commit 16d17445a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 14 deletions

View file

@ -1,14 +1,7 @@
module Moderator
class SinkArticles
def self.call(user_id)
# rubocop:disable Lint/UnreachableCode
# HOTFIX
# @mstruve: This worker is broken and needs to be fixed. It can inadvertantly
# bump up scores for a user's articles if they have a lot of good reactions
# this leads to clumps of articles from the same user in feeds
return
Moderator::SinkArticlesWorker.perform_async(user_id)
# rubocop:enable Lint/UnreachableCode
end
end
end

View file

@ -8,10 +8,7 @@ module Moderator
user = User.find_by(id: user_id)
return unless user
articles = Article.where(user: user)
reactions = Reaction.where(reactable: articles)
new_score = reactions.sum(:points) + Reaction.where(reactable: user).sum(:points)
articles.update_all(score: new_score)
Article.where(user: user).each(&:update_score)
rescue StandardError => e
ForemStatsClient.count("moderators.sink", 1, tags: ["action:failed", "user_id:#{user.id}"])
Honeybadger.notify(e)

View file

@ -7,16 +7,17 @@ RSpec.describe Moderator::SinkArticles, type: :service do
create_list(:article, 3, user: user)
user
end
let(:scores) { -> { spam_user.articles.reload.pluck(:score) } }
let(:vomit_reaction) { create(:reaction, reactable: spam_user, user: moderator, category: "vomit") }
xdescribe "#call" do
describe "#call" do
it "lowers all of a user's articles' scores by 25 each if not confirmed" do
vomit_reaction
expect do
sidekiq_perform_enqueued_jobs do
described_class.call(spam_user.id)
end
end.to change { spam_user.articles.sum(:score) }.from(0).to(-75)
end.to change(scores, :call).from([0, 0, 0]).to([-25, -25, -25])
end
it "lowers all of the user's articles' scores by 50 each if confirmed" do
@ -25,7 +26,22 @@ RSpec.describe Moderator::SinkArticles, type: :service do
sidekiq_perform_enqueued_jobs do
described_class.call(spam_user.id)
end
end.to change { spam_user.articles.sum(:score) }.from(0).to(-150)
end.to change(scores, :call).from([0, 0, 0]).to([-50, -50, -50])
end
context "when removing a user vomit reaction" do
before do
# pretend we had a confirmed vomit on the user
spam_user.articles.update(score: -50)
end
it "raises all of the user's articles but the moderation score" do
expect do
sidekiq_perform_enqueued_jobs do
described_class.call(spam_user.id)
end
end.to change(scores, :call).from([-50, -50, -50]).to([0, 0, 0])
end
end
end
end