Skip to content

Commit

Permalink
Migrate score settings to use sensitivities
Browse files Browse the repository at this point in the history
We hide scores so these settings no longer made sense.
  • Loading branch information
eviltrout committed May 24, 2019
1 parent fad5d9c commit 89b8465
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 39 deletions.
35 changes: 34 additions & 1 deletion app/models/reviewable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def initialize(action_id, klass)
Jobs.enqueue(:notify_reviewable, reviewable_id: self.id) if pending?
end

# The gaps are in case we want more accuracy in the future
# The gaps are in case we want more precision in the future
def self.priorities
@priorities ||= Enum.new(
low: 0,
Expand All @@ -50,6 +50,16 @@ def self.priorities
)
end

# The gaps are in case we want more precision in the future
def self.sensitivity
@sensitivity ||= Enum.new(
disabled: 0,
low: 9,
medium: 6,
high: 3
)
end

def self.statuses
@statuses ||= Enum.new(
pending: 0,
Expand Down Expand Up @@ -173,6 +183,29 @@ def self.set_priorities(values)
end
end

def self.sensitivity_score(sensitivity, scale: 1.0)
return Float::MAX if sensitivity == 0

ratio = sensitivity / Reviewable.sensitivity[:low].to_f
high = PluginStore.get('reviewables', "priority_#{Reviewable.priorities[:high]}")
return (10.0 * scale) if high.nil?

# We want this to be hard to reach
(high.to_f * ratio) * scale
end

def self.score_to_auto_close_topic
sensitivity_score(SiteSetting.auto_close_topic_sensitivity, scale: 2.5)
end

def self.spam_score_to_silence_new_user
sensitivity_score(SiteSetting.silence_new_user_sensitivity, scale: 0.6)
end

def self.score_required_to_hide_post
sensitivity_score(SiteSetting.hide_post_sensitivity)
end

def self.min_score_for_priority(priority = nil)
priority ||= SiteSetting.reviewable_default_visibility
id = Reviewable.priorities[priority.to_sym]
Expand Down
22 changes: 22 additions & 0 deletions app/models/reviewable_sensitivity_setting.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require_dependency 'enum_site_setting'

class ReviewableSensitivitySetting < EnumSiteSetting

def self.valid_value?(val)
values.any? { |v| v[:value].to_s == val.to_s }
end

def self.values
Reviewable.sensitivity.map do |p|
{ name: I18n.t("reviewables.sensitivity.#{p[0]}"), value: p[1] }
end
end

def self.translate_names?
false
end

end

2 changes: 1 addition & 1 deletion app/models/topic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,7 @@ def auto_close_threshold_reached?
.pluck("COUNT(DISTINCT reviewable_scores.user_id), COALESCE(SUM(reviewable_scores.score), 0.0)")
.first

scores[0] >= SiteSetting.num_flaggers_to_close_topic && scores[1] >= SiteSetting.score_to_auto_close_topic
scores[0] >= SiteSetting.num_flaggers_to_close_topic && scores[1] >= Reviewable.score_to_auto_close_topic
end

def update_category_topic_count_by(num)
Expand Down
11 changes: 3 additions & 8 deletions app/services/spam_rule/auto_silence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,9 @@ def should_autosilence?
return false if @user.staged?
return false if @user.has_trust_level?(TrustLevel[1])

if SiteSetting.spam_score_to_silence_new_user > 0 &&
SiteSetting.num_users_to_silence_new_user > 0 &&
user_spam_stats.total_spam_score >= SiteSetting.spam_score_to_silence_new_user &&
user_spam_stats.spam_user_count >= SiteSetting.num_users_to_silence_new_user
return true
end

false
SiteSetting.num_users_to_silence_new_user > 0 &&
user_spam_stats.total_spam_score >= Reviewable.spam_score_to_silence_new_user &&
user_spam_stats.spam_user_count >= SiteSetting.num_users_to_silence_new_user
end

def user_spam_stats
Expand Down
14 changes: 9 additions & 5 deletions config/locales/server.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1388,7 +1388,10 @@ en:
anon_polling_interval: "How often should anonymous clients poll in milliseconds"
background_polling_interval: "How often should the clients poll in milliseconds (when the window is in the background)"

score_required_to_hide_post: "Score threshold that causes a post to be automatically hidden and message sent to the user (0 to disable)"
hide_post_sensitivity: "The likelyhood that a flagged post will be hidden"
silence_new_user_sensitivity: "The likelyhood that a new user will be silenced based on spam flags"
auto_close_topic_sensitivity: "The likelyhood that a flagged topic will be automatically closed"

cooldown_minutes_after_hiding_posts: "Number of minutes a user must wait before they can edit a post hidden via community flagging"

max_topics_in_first_day: "The maximum number of topics a user is allowed to create in the 24 hour period after creating their first post"
Expand All @@ -1397,8 +1400,6 @@ en:
tl2_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl2 (member) by multiplying with this number"
tl3_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl3 (regular) by multiplying with this number"
tl4_additional_likes_per_day_multiplier: "Increase limit of likes per day for tl4 (leader) by multiplying with this number"

spam_score_to_silence_new_user: "If a new user's posts receive this score from num_users_to_silence_new_user different users, hide all their posts and prevent future posting. 0 to disable."
num_users_to_silence_new_user: "If a new user's posts get num_spam_flags_to_silence_new_user spam flags from this many different users, hide all their posts and prevent future posting. 0 to disable."
num_tl3_flags_to_silence_new_user: "If a new user's posts get this many flags from num_tl3_users_to_silence_new_user different trust level 3 users, hide all their posts and prevent future posting. 0 to disable."
num_tl3_users_to_silence_new_user: "If a new user's posts get num_tl3_flags_to_silence_new_user flags from this many different trust level 3 users, hide all their posts and prevent future posting. 0 to disable."
Expand Down Expand Up @@ -1745,7 +1746,6 @@ en:
max_age_unmatched_ips: "Delete unmatched screened IP entries after (N) days."

num_flaggers_to_close_topic: "Minimum number of unique flaggers that is required to automatically pause a topic for intervention"
score_to_auto_close_topic: "The total flag score of that is required to automatically pause a topic for intervention"
num_hours_to_close_topic: "Number of hours to pause a topic for intervention."

auto_respond_to_flag_actions: "Enable automatic reply when disposing a flag."
Expand Down Expand Up @@ -4418,7 +4418,11 @@ en:
low: "Low"
medium: "Medium"
high: "High"
sensitivity:
disabled: "Disabled"
low: "Low"
medium: "Medium"
high: "High"
must_claim: "You must claim items before acting on them."
user_claimed: "This item has been claimed by another user."
missing_version: "You must supply a version parameter"
Expand Down
15 changes: 12 additions & 3 deletions config/site_settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1366,9 +1366,15 @@ onebox:

spam:
add_rel_nofollow_to_user_content: true
score_required_to_hide_post: 10
hide_post_sensitivity:
type: enum
enum: "ReviewableSensitivitySetting"
default: 6
cooldown_minutes_after_hiding_posts: 10
spam_score_to_silence_new_user: 6.0
silence_new_user_sensitivity:
type: enum
enum: "ReviewableSensitivitySetting"
default: 9
num_users_to_silence_new_user: 3
notify_mods_when_user_silenced: false
flag_sockpuppets: false
Expand All @@ -1384,7 +1390,10 @@ spam:
max_age_unmatched_emails: 365
max_age_unmatched_ips: 365
num_flaggers_to_close_topic: 5
score_to_auto_close_topic: 25.0
auto_close_topic_sensitivity:
type: enum
enum: "ReviewableSensitivitySetting"
default: 3
num_hours_to_close_topic:
default: 4
min: 1
Expand Down
4 changes: 2 additions & 2 deletions lib/post_action_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ def auto_hide_if_needed
@post.user&.trust_level != TrustLevel[4]

@post.hide!(@post_action_type_id, Post.hidden_reasons[:flagged_by_tl4_user])
elsif SiteSetting.score_required_to_hide_post > 0
else
score = ReviewableFlaggedPost.find_by(target: @post)&.score || 0
if score >= SiteSetting.score_required_to_hide_post
if score >= Reviewable.score_required_to_hide_post
@post.hide!(@post_action_type_id)
end
end
Expand Down
10 changes: 6 additions & 4 deletions spec/integration/spam_rules_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
fab!(:user2) { Fabricate(:user) }

before do
SiteSetting.score_required_to_hide_post = 0
SiteSetting.spam_score_to_silence_new_user = 4.0
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:disabled]
Reviewable.set_priorities(high: 4.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:low]
SiteSetting.num_users_to_silence_new_user = 2
end

Expand Down Expand Up @@ -73,9 +74,10 @@
end
end

context 'score_required_to_hide_post takes effect too' do
context 'hide_post_sensitivity' do
it 'should silence the spammer' do
SiteSetting.score_required_to_hide_post = 2.0
Reviewable.set_priorities(high: 2.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:low]
PostActionCreator.create(user2, spam_post, :spam)
expect(spammer.reload).to be_silenced
expect(Guardian.new(spammer).can_create_topic?(nil)).to be false
Expand Down
20 changes: 13 additions & 7 deletions spec/models/post_action_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ def value_for(user_id, dt)
mod = Fabricate(:moderator)
post = Fabricate(:post, user: mod)

SiteSetting.score_required_to_hide_post = 2.0
Reviewable.set_priorities(high: 2.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:low]
Discourse.stubs(:site_contact_user).returns(admin)

PostActionCreator.spam(eviltrout, post)
Expand All @@ -531,7 +532,8 @@ def value_for(user_id, dt)
mod = Fabricate(:moderator)
post = Fabricate(:post, user: mod)

SiteSetting.score_required_to_hide_post = 8.0
Reviewable.set_priorities(high: 8.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:low]
Discourse.stubs(:site_contact_user).returns(admin)

PostActionCreator.spam(eviltrout, post)
Expand All @@ -547,7 +549,8 @@ def value_for(user_id, dt)
post = create_post
walterwhite = Fabricate(:walter_white)

SiteSetting.score_required_to_hide_post = 3.0
Reviewable.set_priorities(high: 3.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:low]
Discourse.stubs(:site_contact_user).returns(admin)

PostActionCreator.spam(eviltrout, post)
Expand Down Expand Up @@ -707,8 +710,9 @@ def value_for(user_id, dt)
fab!(:flagger2) { Fabricate(:user) }

before do
SiteSetting.score_required_to_hide_post = 0
SiteSetting.score_to_auto_close_topic = 12.0
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:disabled]
Reviewable.set_priorities(high: 4.5)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:low]
SiteSetting.num_flaggers_to_close_topic = 2
SiteSetting.num_hours_to_close_topic = 1
end
Expand Down Expand Up @@ -769,7 +773,8 @@ def value_for(user_id, dt)
freeze_time

SiteSetting.num_flaggers_to_close_topic = 1
SiteSetting.score_to_auto_close_topic = 2.0
Reviewable.set_priorities(high: 0.5)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:low]

post = Fabricate(:post, topic: topic)
PostActionCreator.spam(flagger1, post)
Expand All @@ -792,7 +797,8 @@ def value_for(user_id, dt)

freeze_time timer.execute_at
SiteSetting.num_flaggers_to_close_topic = 10
SiteSetting.score_to_auto_close_topic = 20.0
Reviewable.set_priorities(high: 10.0)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:low]

Jobs::ToggleTopicClosed.new.execute(topic_timer_id: timer.id, state: false)

Expand Down
3 changes: 2 additions & 1 deletion spec/models/reviewable_queued_post_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@
newuser.update!(trust_level: 0)
post = Fabricate(:post, user: newuser)
PostActionCreator.spam(moderator, post)
SiteSetting.spam_score_to_silence_new_user = 1
Reviewable.set_priorities(high: 1.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:low]
SiteSetting.num_users_to_silence_new_user = 1
expect(Guardian.new(newuser).can_create_post?(topic)).to eq(false)

Expand Down
67 changes: 67 additions & 0 deletions spec/models/reviewable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,73 @@
end
end

context ".score_required_to_hide_post" do
it "returns 10 if we can't calculated any percentiles" do
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:low]
expect(Reviewable.score_required_to_hide_post).to eq(10.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:medium]
expect(Reviewable.score_required_to_hide_post).to eq(10.0)
end

it "returns a fraction of the high percentile" do
Reviewable.set_priorities(high: 100.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:disabled]
expect(Reviewable.score_required_to_hide_post.to_f.truncate(2)).to eq(Float::MAX)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:low]
expect(Reviewable.score_required_to_hide_post.to_f.truncate(2)).to eq(100.0)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:medium]
expect(Reviewable.score_required_to_hide_post.to_f.truncate(2)).to eq(66.66)
SiteSetting.hide_post_sensitivity = Reviewable.sensitivity[:high]
expect(Reviewable.score_required_to_hide_post.to_f.truncate(2)).to eq(33.33)
end
end

context ".spam_score_to_silence_new_user" do
it "returns 6 if we can't calculated any percentiles" do
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:low]
expect(Reviewable.spam_score_to_silence_new_user).to eq(6.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:medium]
expect(Reviewable.spam_score_to_silence_new_user).to eq(6.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:high]
expect(Reviewable.spam_score_to_silence_new_user).to eq(6.0)
end

it "returns a fraction of the high percentile" do
Reviewable.set_priorities(high: 100.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:disabled]
expect(Reviewable.spam_score_to_silence_new_user.to_f.truncate(2)).to eq(Float::MAX)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:low]
expect(Reviewable.spam_score_to_silence_new_user.to_f.truncate(2)).to eq(60.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:medium]
expect(Reviewable.spam_score_to_silence_new_user.to_f.truncate(2)).to eq(39.99)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:high]
expect(Reviewable.spam_score_to_silence_new_user.to_f.truncate(2)).to eq(19.99)
end
end

context ".score_to_auto_close_topic" do
it "returns 25 if we can't calculated any percentiles" do
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:low]
expect(Reviewable.score_to_auto_close_topic).to eq(25.0)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:medium]
expect(Reviewable.score_to_auto_close_topic).to eq(25.0)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:high]
expect(Reviewable.score_to_auto_close_topic).to eq(25.0)
end

it "returns a fraction of the high percentile" do
Reviewable.set_priorities(high: 100.0)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:disabled]
expect(Reviewable.score_to_auto_close_topic.to_f.truncate(2)).to eq(Float::MAX)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:low]
expect(Reviewable.score_to_auto_close_topic.to_f.truncate(2)).to eq(250.0)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:medium]
expect(Reviewable.score_to_auto_close_topic.to_f.truncate(2)).to eq(166.66)
SiteSetting.auto_close_topic_sensitivity = Reviewable.sensitivity[:high]
expect(Reviewable.score_to_auto_close_topic.to_f.truncate(2)).to eq(83.33)
end
end

context "priorities" do
it "returns 0 for unknown priorities" do
expect(Reviewable.min_score_for_priority(:wat)).to eq(0.0)
Expand Down
3 changes: 2 additions & 1 deletion spec/requests/admin/flags_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@

context '#disagree' do
it "unhides the post and unsilences the user if disagreed" do
SiteSetting.spam_score_to_silence_new_user = 1.0
Reviewable.set_priorities(high: 1.0)
SiteSetting.silence_new_user_sensitivity = Reviewable.sensitivity[:low]
SiteSetting.num_users_to_silence_new_user = 1

new_user = Fabricate(:newuser)
Expand Down
Loading

0 comments on commit 89b8465

Please sign in to comment.