Automatically resolve spam reports when the offending user is marked as spam (#20781)

* Start resolving spam reports automatically after assigning spam role

* Specs for resolving spam reports + async resolving
This commit is contained in:
Anna Buianova 2024-03-21 20:31:43 +03:00 committed by GitHub
parent c3c8b5f9c4
commit 1008f0af7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 153 additions and 0 deletions

View file

@ -78,6 +78,7 @@ module Moderator
user.add_role(:spam)
remove_privileges
remove_notifications
resolve_spam_reports
when "Super Moderator"
assign_elevated_role_to_user(user, :super_moderator)
TagModerators::AddTrustedRole.call(user)
@ -158,5 +159,11 @@ module Moderator
def update_roles
handle_user_status(user_params[:user_status], user_params[:note_for_current_role])
end
private
def resolve_spam_reports
Users::ResolveSpamReportsWorker.perform_async(user.id)
end
end
end

View file

@ -0,0 +1,35 @@
module Users
class ResolveSpamReports
def self.call(...)
new(...).call
end
def initialize(user)
@user = user
end
def call
relation = FeedbackMessage.where(status: "Open", category: "spam")
# profile reports by url and by path
profile_reports = relation.where(reported_url: [URL.url(user.path), user.path])
profile_reports.update_all(status: "Resolved")
# articles can be reported by url or by path
article_paths = user.articles.map(&:path)
article_paths += article_paths.map { |p| URL.url(p) }
article_reports = relation.where(reported_url: article_paths)
article_reports.update_all(status: "Resolved")
# comments can be reported by url or by path
comment_paths = user.comments.map(&:path)
comment_paths += comment_paths.map { |p| URL.url(p) }
comment_reports = relation.where(reported_url: comment_paths)
comment_reports.update_all(status: "Resolved")
end
private
attr_reader :user
end
end

View file

@ -0,0 +1,14 @@
module Users
class ResolveSpamReportsWorker
include Sidekiq::Job
sidekiq_options queue: :medium_priority, retry: 10, lock: :until_executing
def perform(user_id)
user = User.find_by(id: user_id)
return unless user
Users::ResolveSpamReports.call(user)
end
end
end

View file

@ -250,6 +250,29 @@ RSpec.describe Moderator::ManageActivityAndRoles, type: :service do
end
end
describe "removes reports when adding the spam role" do
let(:spam_user) { create(:user) }
let(:spam_article) { create(:article, user: spam_user) }
let!(:report) do
create(:feedback_message, category: "spam", status: "Open", reported_url: URL.url(spam_article.path))
end
it "calls ResolveSpamReports" do
allow(Users::ResolveSpamReports).to receive(:call)
sidekiq_perform_enqueued_jobs do
manage_roles_for(spam_user, user_status: "Spam")
end
expect(Users::ResolveSpamReports).to have_received(:call).with(spam_user)
end
it "actually removes the report" do
sidekiq_perform_enqueued_jobs do
manage_roles_for(spam_user, user_status: "Spam")
end
expect(report.reload.status).to eq("Resolved")
end
end
describe "removes notifications when adding the spam role" do
let(:nice_article) { create(:article, user: user) }
let(:spam_user) { create(:user) }

View file

@ -0,0 +1,55 @@
require "rails_helper"
RSpec.describe Users::ResolveSpamReports, type: :service do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:article) { create(:article, user: user) }
let(:article2) { create(:article, user: user) }
let(:article3) { create(:article, user: user2) }
let(:comment) { create(:comment, user: user, commentable: article2) }
let(:comment2) { create(:comment, user: user, commentable: article) }
it "doesn't fail when user has no reports" do
described_class.call(user)
end
def spam_report(url)
create(:feedback_message, category: "spam", status: "Open", reported_url: url)
end
context "with reports" do
let!(:rep) { spam_report(user.path) }
let!(:rep2) { spam_report(URL.url(user.path)) }
let!(:a_rep) { spam_report(article.path) }
let!(:a_rep2) { spam_report(URL.url(article2.path)) }
let!(:c_rep) { spam_report(comment.path) }
let!(:c_rep2) { spam_report(URL.url(comment2.path)) }
it "updates statused of the user's profile, article and comment reports", :aggregate_failures do
described_class.call(user)
expect(rep.reload.status).to eq("Resolved")
expect(rep2.reload.status).to eq("Resolved")
expect(a_rep.reload.status).to eq("Resolved")
expect(a_rep2.reload.status).to eq("Resolved")
expect(c_rep.reload.status).to eq("Resolved")
expect(c_rep2.reload.status).to eq("Resolved")
end
it "doesn't update non-spam reports" do
other_rep = create(:feedback_message, category: "other", status: "Open", reported_url: user.path)
harassment_rep = create(:feedback_message, category: "harassment", status: "Open",
reported_url: URL.url(article.path))
described_class.call(user)
expect(other_rep.reload.status).to eq("Open")
expect(harassment_rep.reload.status).to eq("Open")
end
it "doesn't update other users reports" do
u2_rep = spam_report(URL.url(user2.path))
a3_rep = spam_report(article3.path)
described_class.call(user)
expect(u2_rep.reload.status).to eq("Open")
expect(a3_rep.reload.status).to eq("Open")
end
end
end

View file

@ -0,0 +1,19 @@
require "rails_helper"
RSpec.describe Users::ResolveSpamReportsWorker, type: :worker do
describe "#perform" do
let(:user) { create(:user) }
let(:worker) { subject }
it "calls spam reports resolver" do
allow(Users::ResolveSpamReports).to receive(:call).with(user)
worker.perform(user.id)
expect(Users::ResolveSpamReports).to have_received(:call).with(user)
end
it "doesn't fail with invalid url" do
worker.perform(-1)
end
end
end