mirror of
https://github.com/discourse/discourse.git
synced 2025-06-10 17:23:49 +08:00
rate limits for topics and posts on first day
max_topics_in_first_day and max_replies_in_first_day
This commit is contained in:
@ -17,6 +17,7 @@ class Post < ActiveRecord::Base
|
|||||||
versioned if: :raw_changed?
|
versioned if: :raw_changed?
|
||||||
|
|
||||||
rate_limit
|
rate_limit
|
||||||
|
rate_limit :limit_posts_per_day
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :topic, counter_cache: :posts_count
|
belongs_to :topic, counter_cache: :posts_count
|
||||||
@ -54,6 +55,12 @@ class Post < ActiveRecord::Base
|
|||||||
@types ||= Enum.new(:regular, :moderator_action)
|
@types ||= Enum.new(:regular, :moderator_action)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def limit_posts_per_day
|
||||||
|
if user.created_at > 1.day.ago && post_number > 1
|
||||||
|
RateLimiter.new(user, "first-day-replies-per-day:#{Date.today.to_s}", SiteSetting.max_replies_in_first_day, 1.day.to_i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def trash!(trashed_by=nil)
|
def trash!(trashed_by=nil)
|
||||||
self.topic_links.each(&:destroy)
|
self.topic_links.each(&:destroy)
|
||||||
super(trashed_by)
|
super(trashed_by)
|
||||||
|
@ -66,6 +66,9 @@ class SiteSetting < ActiveRecord::Base
|
|||||||
setting(:flags_required_to_hide_post, 3)
|
setting(:flags_required_to_hide_post, 3)
|
||||||
setting(:cooldown_minutes_after_hiding_posts, 10)
|
setting(:cooldown_minutes_after_hiding_posts, 10)
|
||||||
|
|
||||||
|
setting(:max_topics_in_first_day, 5)
|
||||||
|
setting(:max_replies_in_first_day, 10)
|
||||||
|
|
||||||
setting(:num_flags_to_block_new_user, 3)
|
setting(:num_flags_to_block_new_user, 3)
|
||||||
setting(:num_users_to_block_new_user, 3)
|
setting(:num_users_to_block_new_user, 3)
|
||||||
setting(:notify_mods_when_user_blocked, false)
|
setting(:notify_mods_when_user_blocked, false)
|
||||||
|
@ -183,6 +183,9 @@ class Topic < ActiveRecord::Base
|
|||||||
# Additional rate limits on topics: per day and private messages per day
|
# Additional rate limits on topics: per day and private messages per day
|
||||||
def limit_topics_per_day
|
def limit_topics_per_day
|
||||||
RateLimiter.new(user, "topics-per-day:#{Date.today.to_s}", SiteSetting.max_topics_per_day, 1.day.to_i)
|
RateLimiter.new(user, "topics-per-day:#{Date.today.to_s}", SiteSetting.max_topics_per_day, 1.day.to_i)
|
||||||
|
if user.created_at > 1.day.ago
|
||||||
|
RateLimiter.new(user, "first-day-topics-per-day:#{Date.today.to_s}", SiteSetting.max_topics_in_first_day, 1.day.to_i)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def limit_private_messages_per_day
|
def limit_private_messages_per_day
|
||||||
|
@ -530,6 +530,10 @@ en:
|
|||||||
|
|
||||||
flags_required_to_hide_post: "Number of flags that cause a post to be automatically hidden and PM sent to the user (0 for never)"
|
flags_required_to_hide_post: "Number of flags that cause a post to be automatically hidden and PM sent to the user (0 for never)"
|
||||||
cooldown_minutes_after_hiding_posts: "Number of minutes a user must wait before they can edit a post hidden via flagging"
|
cooldown_minutes_after_hiding_posts: "Number of minutes a user must wait before they can edit a post hidden via flagging"
|
||||||
|
|
||||||
|
max_topics_in_first_day: "The maximum number of topics a user is alowed to create in thier first day on the site"
|
||||||
|
max_replies_in_first_day: "The maximum number of replies a user is alowed to create in thier first day on the site"
|
||||||
|
|
||||||
num_flags_to_block_new_user: "If a new user's posts get this many spam flags from (n) different users, hide all their posts and prevent future posting. 0 disables this feature."
|
num_flags_to_block_new_user: "If a new user's posts get this many spam flags from (n) different users, hide all their posts and prevent future posting. 0 disables this feature."
|
||||||
num_users_to_block_new_user: "If a new user's posts get (x) spam flags from this many different users, hide all their posts and prevent future posting. 0 disables this feature."
|
num_users_to_block_new_user: "If a new user's posts get (x) spam flags from this many different users, hide all their posts and prevent future posting. 0 disables this feature."
|
||||||
notify_mods_when_user_blocked: "If a user is automatically blocked, send a message to all moderators."
|
notify_mods_when_user_blocked: "If a user is automatically blocked, send a message to all moderators."
|
||||||
|
@ -67,10 +67,14 @@ module SiteSettingExtension
|
|||||||
|
|
||||||
def client_settings_json
|
def client_settings_json
|
||||||
Rails.cache.fetch(SiteSettingExtension.client_settings_cache_key, expires_in: 30.minutes) do
|
Rails.cache.fetch(SiteSettingExtension.client_settings_cache_key, expires_in: 30.minutes) do
|
||||||
MultiJson.dump(Hash[*@@client_settings.map{|n| [n, self.send(n)]}.flatten])
|
client_settings_json_uncached
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def client_settings_json_uncached
|
||||||
|
MultiJson.dump(Hash[*@@client_settings.map{|n| [n, self.send(n)]}.flatten])
|
||||||
|
end
|
||||||
|
|
||||||
# Retrieve all settings
|
# Retrieve all settings
|
||||||
def all_settings
|
def all_settings
|
||||||
@defaults.map do |s, v|
|
@defaults.map do |s, v|
|
||||||
|
@ -565,11 +565,10 @@ describe Topic do
|
|||||||
shared_examples_for "adding a star to a topic" do
|
shared_examples_for "adding a star to a topic" do
|
||||||
it 'triggers a forum topic user change with true' do
|
it 'triggers a forum topic user change with true' do
|
||||||
# otherwise no chance the mock will work
|
# otherwise no chance the mock will work
|
||||||
freeze_time do
|
freeze_time
|
||||||
TopicUser.expects(:change).with(@user, @topic.id, starred: true, starred_at: DateTime.now, unstarred_at: nil)
|
TopicUser.expects(:change).with(@user, @topic.id, starred: true, starred_at: DateTime.now, unstarred_at: nil)
|
||||||
@topic.toggle_star(@user, true)
|
@topic.toggle_star(@user, true)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it 'increases the star_count of the forum topic' do
|
it 'increases the star_count of the forum topic' do
|
||||||
lambda {
|
lambda {
|
||||||
@ -603,11 +602,10 @@ describe Topic do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'triggers a forum topic user change with false' do
|
it 'triggers a forum topic user change with false' do
|
||||||
freeze_time do
|
freeze_time
|
||||||
TopicUser.expects(:change).with(@user, @topic.id, starred: false, unstarred_at: DateTime.now)
|
TopicUser.expects(:change).with(@user, @topic.id, starred: false, unstarred_at: DateTime.now)
|
||||||
@topic.toggle_star(@user, false)
|
@topic.toggle_star(@user, false)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it 'reduces the star_count' do
|
it 'reduces the star_count' do
|
||||||
lambda {
|
lambda {
|
||||||
@ -1181,4 +1179,32 @@ describe Topic do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "limits new users to max_topics_in_first_day and max_posts_in_first_day" do
|
||||||
|
SiteSetting.stubs(:max_topics_in_first_day).returns(1)
|
||||||
|
SiteSetting.stubs(:max_replies_in_first_day).returns(1)
|
||||||
|
RateLimiter.stubs(:disabled?).returns(false)
|
||||||
|
SiteSetting.stubs(:client_settings_json).returns(SiteSetting.client_settings_json_uncached)
|
||||||
|
|
||||||
|
start = Time.now.tomorrow.beginning_of_day
|
||||||
|
|
||||||
|
freeze_time(start)
|
||||||
|
|
||||||
|
user = Fabricate(:user)
|
||||||
|
topic_id = create_post(user: user).topic_id
|
||||||
|
|
||||||
|
freeze_time(start + 10.minutes)
|
||||||
|
lambda {
|
||||||
|
create_post(user: user)
|
||||||
|
}.should raise_exception
|
||||||
|
|
||||||
|
freeze_time(start + 20.minutes)
|
||||||
|
create_post(user: user, topic_id: topic_id)
|
||||||
|
|
||||||
|
freeze_time(start + 30.minutes)
|
||||||
|
|
||||||
|
lambda {
|
||||||
|
create_post(user: user, topic_id: topic_id)
|
||||||
|
}.should raise_exception
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -85,26 +85,9 @@ Spork.prefork do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class DateTime
|
def freeze_time(now=Time.now)
|
||||||
class << self
|
DateTime.stubs(:now).returns(DateTime.parse(now.to_s))
|
||||||
alias_method :old_now, :now
|
Time.stubs(:now).returns(Time.parse(now.to_s))
|
||||||
def now
|
|
||||||
@now || old_now
|
|
||||||
end
|
|
||||||
def now=(v)
|
|
||||||
@now = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def freeze_time(d=nil)
|
|
||||||
begin
|
|
||||||
d ||= DateTime.now
|
|
||||||
DateTime.now = d
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
DateTime.now = nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user