From 0b4cb5cf0d5f2304a8918384735f93aeca493bbe Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 24 Sep 2015 13:52:32 -0400 Subject: [PATCH] Add better error messages for rate limits. --- config/locales/server.en.yml | 11 +++++++++++ lib/edit_rate_limiter.rb | 6 +++++- lib/rate_limiter.rb | 11 ++++++++--- lib/rate_limiter/limit_exceeded.rb | 11 ++++++++++- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 21e4d67e856..945846f671f 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -377,6 +377,17 @@ en: rate_limiter: slow_down: "You have performed this action too many times, try again later" too_many_requests: "We have a daily limit on how many times that action can be taken. Please wait %{time_left} before trying again." + by_type: + first_day_replies_per_day: "You've reached the maximum number of posts a user can post on their first day. Please wait %{time_left} before trying again." + first_day_topics_per_day: "You've reached the maximum number of topics a user can post on their first day. Please wait %{time_left} before trying again." + topics_per_day: "You've posted too many topics today. Please wait %{time_left} before trying again." + create_topic: "You're posting topics too quickly. Please wait %{time_left} before trying again." + create_post: "You're replying too quickly. Please wait %{time_left} before trying again." + pms_per_day: "You've sent too many messages today. Please wait %{time_left} before trying again." + create_like: "You've liked too many posts today. Please wait %{time_left} before trying again." + create_bookmark: "You've bookmarked too many posts today. Please wait %{time_left} before trying again." + edit_post: "You've edited too many posts today. Please wait %{time_left} before trying again." + hours: one: "1 hour" other: "%{count} hours" diff --git a/lib/edit_rate_limiter.rb b/lib/edit_rate_limiter.rb index 3c42a89bfc0..d30c7c66fc7 100644 --- a/lib/edit_rate_limiter.rb +++ b/lib/edit_rate_limiter.rb @@ -1,6 +1,10 @@ require 'rate_limiter' class EditRateLimiter < RateLimiter def initialize(user) - super(user, "edit-post:#{Date.today}", SiteSetting.max_edits_per_day, 1.day.to_i) + super(user, "edit-post", SiteSetting.max_edits_per_day, 1.day.to_i) + end + + def build_key(type) + "#{super(type)}:#{Date.today}" end end diff --git a/lib/rate_limiter.rb b/lib/rate_limiter.rb index e8b51f0f499..df678960d7d 100644 --- a/lib/rate_limiter.rb +++ b/lib/rate_limiter.rb @@ -27,9 +27,14 @@ class RateLimiter $redis.delete_prefixed(RateLimiter.key_prefix) end - def initialize(user, key, max, secs) + def build_key(type) + "#{RateLimiter.key_prefix}:#{@user && @user.id}:#{type}" + end + + def initialize(user, type, max, secs) @user = user - @key = "#{RateLimiter.key_prefix}:#{@user && @user.id}:#{key}" + @type = type + @key = build_key(type) @max = max @secs = secs end @@ -53,7 +58,7 @@ class RateLimiter # let's ensure we expire this key at some point, otherwise we have leaks $redis.expire(@key, @secs * 2) else - raise LimitExceeded.new(seconds_to_wait) + raise RateLimiter::LimitExceeded.new(seconds_to_wait, @type) end end diff --git a/lib/rate_limiter/limit_exceeded.rb b/lib/rate_limiter/limit_exceeded.rb index c6685484897..ad7a000577b 100644 --- a/lib/rate_limiter/limit_exceeded.rb +++ b/lib/rate_limiter/limit_exceeded.rb @@ -3,11 +3,13 @@ class RateLimiter # A rate limit has been exceeded. class LimitExceeded < StandardError - def initialize(available_in) + def initialize(available_in, type=nil) @available_in = available_in + @type = type end def description + time_left = "" if @available_in < 1.minute.to_i time_left = I18n.t("rate_limiter.seconds", count: @available_in) @@ -16,6 +18,13 @@ class RateLimiter else time_left = I18n.t("rate_limiter.hours", count: (@available_in / 1.hour.to_i)) end + + if @type.present? + type_key = @type.gsub(/-/, '_') + msg = I18n.t("rate_limiter.by_type.#{type_key}", time_left: time_left, default: "") + return msg if msg.present? + end + I18n.t("rate_limiter.too_many_requests", time_left: time_left) end end