diff --git a/app/models/user.rb b/app/models/user.rb index 3ac58b758797d68aa0406ab5dc724080905eeb4b..16174dce14d56d65aa508a4e77cb8531617fcf83 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2302,6 +2302,10 @@ def abuse_metadata } end + def allow_possible_spam? + custom_attributes.by_key(UserCustomAttribute::ALLOW_POSSIBLE_SPAM).exists? + end + def namespace_commit_email_for_namespace(namespace) return if namespace.nil? diff --git a/app/models/user_custom_attribute.rb b/app/models/user_custom_attribute.rb index 63a5ee9770fd801a0427448f1533430c8b8c56a8..0ba58a132371a27270e1f415980a52d993446ade 100644 --- a/app/models/user_custom_attribute.rb +++ b/app/models/user_custom_attribute.rb @@ -15,6 +15,7 @@ class UserCustomAttribute < ApplicationRecord UNBLOCKED_BY = 'unblocked_by' ARKOSE_RISK_BAND = 'arkose_risk_band' AUTO_BANNED_BY_ABUSE_REPORT_ID = 'auto_banned_by_abuse_report_id' + ALLOW_POSSIBLE_SPAM = 'allow_possible_spam' class << self def upsert_custom_attributes(custom_attributes) diff --git a/app/services/spam/spam_verdict_service.rb b/app/services/spam/spam_verdict_service.rb index 2ecd431fd91473be9e23e049ec370c38efc9e37b..160ebb81b39724e541870d4cd016be7d3b7f7349 100644 --- a/app/services/spam/spam_verdict_service.rb +++ b/app/services/spam/spam_verdict_service.rb @@ -85,7 +85,7 @@ def override_via_allow_possible_spam?(verdict:) # than the override verdict's priority value), then we don't need to override it. return false if SUPPORTED_VERDICTS[verdict][:priority] > SUPPORTED_VERDICTS[OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM][:priority] - target.allow_possible_spam? + target.allow_possible_spam? || user.allow_possible_spam? end def spamcheck_client diff --git a/app/services/users/allow_possible_spam_service.rb b/app/services/users/allow_possible_spam_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..d9273fe0fc1cf462e7fd116870de64ff1a24507a --- /dev/null +++ b/app/services/users/allow_possible_spam_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Users + class AllowPossibleSpamService < BaseService + def initialize(current_user) + @current_user = current_user + end + + def execute(user) + custom_attribute = { + user_id: user.id, + key: UserCustomAttribute::ALLOW_POSSIBLE_SPAM, + value: "#{current_user.username}/#{current_user.id}+#{Time.current}" + } + UserCustomAttribute.upsert_custom_attributes([custom_attribute]) + end + end +end diff --git a/app/services/users/disallow_possible_spam_service.rb b/app/services/users/disallow_possible_spam_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..e31ba7ddff02a481ef0d0cd1b11beedb2e2336bd --- /dev/null +++ b/app/services/users/disallow_possible_spam_service.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Users + class DisallowPossibleSpamService < BaseService + def initialize(current_user) + @current_user = current_user + end + + def execute(user) + user.custom_attributes.by_key(UserCustomAttribute::ALLOW_POSSIBLE_SPAM).delete_all + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 768198bc8267e4136de22cb2784defe49b67a6ea..3244b60e317ca2af971faa299c0b3c9ee5d977fa 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -6216,6 +6216,29 @@ def add_user(access) expect { user.delete_async(deleted_by: deleted_by) }.not_to change { user.note } end end + + describe '#allow_possible_spam?' do + context 'when no custom attribute is set' do + it 'is false' do + expect(user.allow_possible_spam?).to be_falsey + end + end + + context 'when the custom attribute is set' do + before do + user.custom_attributes.upsert_custom_attributes( + [{ + user_id: user.id, + key: UserCustomAttribute::ALLOW_POSSIBLE_SPAM, + value: "test" + }]) + end + + it '#allow_possible_spam? is true' do + expect(user.allow_possible_spam?).to be_truthy + end + end + end end end diff --git a/spec/services/spam/spam_verdict_service_spec.rb b/spec/services/spam/spam_verdict_service_spec.rb index 6b14cf33041bec28fd25390bf5f5390fa769722c..f54981a7ac2d12dc31722b9257eec80e6a650c6e 100644 --- a/spec/services/spam/spam_verdict_service_spec.rb +++ b/spec/services/spam/spam_verdict_service_spec.rb @@ -136,6 +136,38 @@ end end + context 'if allow_possible_spam user custom attribute is set' do + before do + UserCustomAttribute.upsert_custom_attributes( + [{ + user_id: user.id, + key: 'allow_possible_spam', + value: 'does not matter' + }] + ) + end + + context 'and a service returns a verdict that should be overridden' do + before do + allow(service).to receive(:get_spamcheck_verdict).and_return(BLOCK_USER) + end + + it 'overrides and renders the override verdict' do + is_expected.to eq OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM + end + end + + context 'and a service returns a verdict that does not need to be overridden' do + before do + allow(service).to receive(:get_spamcheck_verdict).and_return(ALLOW) + end + + it 'does not override and renders the original verdict' do + is_expected.to eq ALLOW + end + end + end + context 'records metrics' do let(:histogram) { instance_double(Prometheus::Client::Histogram) } diff --git a/spec/services/users/allow_possible_spam_service_spec.rb b/spec/services/users/allow_possible_spam_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..53618f0c8e961463b0e82b1fe5644e4b35758abe --- /dev/null +++ b/spec/services/users/allow_possible_spam_service_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Users::AllowPossibleSpamService, feature_category: :user_management do + let_it_be(:current_user) { create(:admin) } + + subject(:service) { described_class.new(current_user) } + + describe '#execute' do + let(:user) { create(:user) } + + subject(:operation) { service.execute(user) } + + it 'updates the custom attributes', :aggregate_failures do + expect(user.custom_attributes).to be_empty + + operation + user.reload + + expect(user.custom_attributes.by_key(UserCustomAttribute::ALLOW_POSSIBLE_SPAM)).to be_present + end + end +end diff --git a/spec/services/users/disallow_possible_spam_service_spec.rb b/spec/services/users/disallow_possible_spam_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..32a47e05525a7b5f66659aa3711503d2f17dd5fa --- /dev/null +++ b/spec/services/users/disallow_possible_spam_service_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Users::DisallowPossibleSpamService, feature_category: :user_management do + let_it_be(:current_user) { create(:admin) } + + subject(:service) { described_class.new(current_user) } + + describe '#execute' do + let(:user) { create(:user) } + + subject(:operation) { service.execute(user) } + + before do + UserCustomAttribute.upsert_custom_attributes( + [{ + user_id: user.id, + key: :allow_possible_spam, + value: 'not important' + }] + ) + end + + it 'updates the custom attributes', :aggregate_failures do + expect(user.custom_attributes.by_key(UserCustomAttribute::ALLOW_POSSIBLE_SPAM)).to be_present + + operation + user.reload + + expect(user.custom_attributes).to be_empty + end + end +end