From 04d4b2340da120edb12b1f27792b0e9d81602602 Mon Sep 17 00:00:00 2001 From: Ben Halpern Date: Mon, 8 Jan 2024 11:25:28 -0500 Subject: [PATCH] Add downstream score effects from spam role (#20498) * Add downstream score effects from spam role * Move async score calc down low * Add tests * Add stub * Fix typo * No need for guard * No need for guard --- app/models/article.rb | 16 +++++++++------- app/models/comment.rb | 8 ++++---- app/models/user.rb | 1 + app/queries/homepage/articles_query.rb | 1 + .../moderator/manage_activity_and_roles.rb | 3 +++ app/workers/comments/calculate_score_worker.rb | 2 +- spec/models/article_spec.rb | 6 ++++++ spec/models/user_spec.rb | 8 ++++++++ .../comments/calculate_score_worker_spec.rb | 10 ++++++++++ 9 files changed, 43 insertions(+), 12 deletions(-) diff --git a/app/models/article.rb b/app/models/article.rb index d533396b6..f1c8ec1fb 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -555,7 +555,9 @@ class Article < ApplicationRecord end def update_score - self.score = reactions.sum(:points) + Reaction.where(reactable_id: user_id, reactable_type: "User").sum(:points) + spam_adjustment = user.spam? ? -500 : 0 + negative_reaction_adjustment = Reaction.where(reactable_id: user_id, reactable_type: "User").sum(:points) + self.score = reactions.sum(:points) + spam_adjustment + negative_reaction_adjustment update_columns(score: score, privileged_users_reaction_points_sum: reactions.privileged_category.sum(:points), comment_score: comments.sum(:score), @@ -609,6 +611,12 @@ class Article < ApplicationRecord tag_adjustments.includes(:user).order(:created_at).reverse end + def async_score_calc + return if !published? || destroyed? + + Articles::ScoreCalcWorker.perform_async(id) + end + private def collection_cleanup @@ -700,12 +708,6 @@ class Article < ApplicationRecord self.tag_list = tag_list.map { |tag| Tag.find_preferred_alias_for(tag) } end - def async_score_calc - return if !published? || destroyed? - - Articles::ScoreCalcWorker.perform_async(id) - end - def fetch_video_duration if video.present? && video_duration_in_seconds.zero? url = video_source_url.gsub(".m3u8", "1351620000001-200015_hls_v4.m3u8") diff --git a/app/models/comment.rb b/app/models/comment.rb index 6cd9dfc38..3e960605c 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -202,6 +202,10 @@ class Comment < ApplicationRecord @privileged_reaction_counts ||= reactions.privileged_category.group(:category).count end + def calculate_score + Comments::CalculateScoreWorker.perform_async(id) + end + private_class_method :build_sort_query private @@ -266,10 +270,6 @@ class Comment < ApplicationRecord self.processed_html = doc.to_html.html_safe # rubocop:disable Rails/OutputSafety end - def calculate_score - Comments::CalculateScoreWorker.perform_async(id) - end - def after_create_checks create_id_code touch_user diff --git a/app/models/user.rb b/app/models/user.rb index c159167a9..85f7fd4f1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -307,6 +307,7 @@ class User < ApplicationRecord # mass re-calculation is needed. user_reaction_points = Reaction.user_vomits.where(reactable_id: id).sum(:points) calculated_score = (badge_achievements_count * 10) + user_reaction_points + calculated_score -= 500 if spam? update_column(:score, calculated_score) end diff --git a/app/queries/homepage/articles_query.rb b/app/queries/homepage/articles_query.rb index 8ed1168f8..c25e1ec94 100644 --- a/app/queries/homepage/articles_query.rb +++ b/app/queries/homepage/articles_query.rb @@ -72,6 +72,7 @@ module Homepage @relation = @relation.cached_tagged_with_any(tags) if tags.any? @relation = @relation.not_cached_tagged_with_any(hidden_tags) if hidden_tags.any? @relation = @relation.includes(:distinct_reaction_categories) + @relation = @relation.where("score >= 0") # Never return negative score articles relation end diff --git a/app/services/moderator/manage_activity_and_roles.rb b/app/services/moderator/manage_activity_and_roles.rb index 475131488..c28943ab0 100644 --- a/app/services/moderator/manage_activity_and_roles.rb +++ b/app/services/moderator/manage_activity_and_roles.rb @@ -98,6 +98,9 @@ module Moderator warned end create_note(role, note) + + user.articles.published.find_each(&:async_score_calc) + user.comments.find_each(&:calculate_score) end # rubocop:enable Metrics/CyclomaticComplexity diff --git a/app/workers/comments/calculate_score_worker.rb b/app/workers/comments/calculate_score_worker.rb index 056bb5922..3ffa7a53f 100644 --- a/app/workers/comments/calculate_score_worker.rb +++ b/app/workers/comments/calculate_score_worker.rb @@ -9,7 +9,7 @@ module Comments return unless comment score = BlackBox.comment_quality_score(comment) - + score -= 500 if comment.user&.spam? comment.update_columns(score: score) comment.root.save! if !comment.is_root? && comment.root_exists? end diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 957089366..adcff6c2e 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -1389,6 +1389,12 @@ RSpec.describe Article do expect { article.update_score }.to change { article.reload.privileged_users_reaction_points_sum } end + + it "includes user marked as spam punishment" do + article.user.add_role(:spam) + article.update_score + expect(article.reload.score).to eq(-500) + end end describe "#feed_source_url and canonical_url must be unique for published articles" do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c7148b9db..c9165f3bf 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -734,6 +734,14 @@ RSpec.describe User do user.calculate_score expect(user.score).to eq(30) end + + it "calculates a score of -500 if spam" do + user.add_role(:spam) + user.update_column(:badge_achievements_count, 3) + + user.calculate_score + expect(user.score).to eq(-470) + end end describe "cache counts" do diff --git a/spec/workers/comments/calculate_score_worker_spec.rb b/spec/workers/comments/calculate_score_worker_spec.rb index 1f7c58f60..6522d7dd0 100644 --- a/spec/workers/comments/calculate_score_worker_spec.rb +++ b/spec/workers/comments/calculate_score_worker_spec.rb @@ -21,6 +21,14 @@ RSpec.describe Comments::CalculateScoreWorker, type: :worker do expect(comment.score).to be(7) end + it "updates the score with a penalty if the user is a spammer" do + comment.user.add_role(:spam) + worker.perform(comment.id) + + comment.reload + expect(comment.score).to be(-493) + end + it "calls save on the root comment when given a descendant comment" do child_comment = double root_comment = double @@ -30,6 +38,7 @@ RSpec.describe Comments::CalculateScoreWorker, type: :worker do allow(child_comment).to receive(:is_root?).and_return(false) allow(child_comment).to receive(:root_exists?).and_return(true) allow(child_comment).to receive(:root).and_return(root_comment) + allow(child_comment).to receive(:user).and_return(double(spam?: false)) allow(Comment).to receive(:find_by).with(id: 1).and_return(child_comment) worker.perform(1) @@ -46,6 +55,7 @@ RSpec.describe Comments::CalculateScoreWorker, type: :worker do allow(root_comment).to receive(:update_columns) allow(root_comment).to receive(:is_root?).and_return(true) allow(root_comment).to receive(:root).and_return(root_comment) + allow(root_comment).to receive(:user).and_return(double(spam?: false)) allow(Comment).to receive(:find_by).with(id: 1).and_return(root_comment) worker.perform(1)