aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin_user_controller.rb1
-rw-r--r--app/controllers/request_controller.rb8
-rw-r--r--app/models/user.rb22
-rw-r--r--app/views/admin_user/_form.rhtml8
-rw-r--r--app/views/user/rate_limited.rhtml5
-rw-r--r--config/test.yml3
-rw-r--r--db/migrate/110_add_user_no_limit.rb13
-rw-r--r--spec/controllers/request_controller_spec.rb53
8 files changed, 105 insertions, 8 deletions
diff --git a/app/controllers/admin_user_controller.rb b/app/controllers/admin_user_controller.rb
index 5d90e74fe..12b4e553f 100644
--- a/app/controllers/admin_user_controller.rb
+++ b/app/controllers/admin_user_controller.rb
@@ -45,6 +45,7 @@ class AdminUserController < AdminController
@admin_user.admin_level = params[:admin_user][:admin_level]
@admin_user.ban_text = params[:admin_user][:ban_text]
@admin_user.about_me = params[:admin_user][:about_me]
+ @admin_user.no_limit = params[:admin_user][:no_limit]
if @admin_user.valid?
@admin_user.save!
diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb
index a70e8d16c..fc1ffdd75 100644
--- a/app/controllers/request_controller.rb
+++ b/app/controllers/request_controller.rb
@@ -208,8 +208,12 @@ class RequestController < ApplicationController
# Banned from making new requests?
if !authenticated_user.nil? && !authenticated_user.can_file_requests?
- @details = authenticated_user.can_fail_html
- render :template => 'user/banned'
+ if authenticated_user.exceeded_limit?
+ render :template => 'user/rate_limited'
+ else
+ @details = authenticated_user.can_fail_html
+ render :template => 'user/banned'
+ end
return
end
diff --git a/app/models/user.rb b/app/models/user.rb
index b6839aa31..2193805ea 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -19,6 +19,7 @@
# locale :string(255)
# email_bounced_at :datetime
# email_bounce_message :text default(""), not null
+# no_limit :boolean default(FALSE), not null
#
# models/user.rb:
@@ -256,7 +257,7 @@ class User < ActiveRecord::Base
end
def User.owns_every_request?(user)
- !user.nil? && user.owns_every_request?
+ !user.nil? && user.owns_every_request?
end
# Can the user see every request, even hidden ones?
@@ -274,7 +275,18 @@ class User < ActiveRecord::Base
end
# Various ways the user can be banned, and text to describe it if failed
def can_file_requests?
- self.ban_text.empty?
+ self.ban_text.empty? && !self.exceeded_limit?
+ end
+ def exceeded_limit?
+ # Some users have no limit
+ return false if self.no_limit
+
+ # Has the user issued as many as MAX_REQUESTS_PER_USER_PER_DAY requests in the past 24 hours?
+ daily_limit = MySociety::Config.get("MAX_REQUESTS_PER_USER_PER_DAY")
+ return false if daily_limit.nil?
+ recent_requests = InfoRequest.count(:conditions => ["user_id = ? and created_at > now() - '1 day'::interval", self.id])
+
+ return (recent_requests >= daily_limit)
end
def can_make_followup?
self.ban_text.empty?
@@ -286,7 +298,11 @@ class User < ActiveRecord::Base
self.ban_text.empty?
end
def can_fail_html
- text = self.ban_text.strip
+ if ban_text
+ text = self.ban_text.strip
+ else
+ raise "Unknown reason for ban"
+ end
text = CGI.escapeHTML(text)
text = MySociety::Format.make_clickable(text, :contract => 1)
text = text.gsub(/\n/, '<br>')
diff --git a/app/views/admin_user/_form.rhtml b/app/views/admin_user/_form.rhtml
index ba2bd8f8b..be69d9a80 100644
--- a/app/views/admin_user/_form.rhtml
+++ b/app/views/admin_user/_form.rhtml
@@ -8,10 +8,10 @@
<p><label for="admin_user_email">Email</label> (<strong>you must</strong> first validate this)<br/>
<%= text_field 'admin_user', 'email', :size => 60 %></p>
-<p><label for="admin_level">Admin level</label> (<strong>none</strong> or <strong>super</strong>; this is for admin features and links which are in the site proper)<br/>
+<p><label for="admin_user_admin_level">Admin level</label> (<strong>none</strong> or <strong>super</strong>; this is for admin features and links which are in the site proper)<br/>
<%= text_field 'admin_user', 'admin_level', :size => 60 %></p>
-<p><label for="ban_text">Ban text</label> <small>(if not blank will stop the
+<p><label for="admin_user_ban_text">Ban text</label> <small>(if not blank will stop the
user from filing new requests, making annotations or messaging other users;
the text is shown in public on the user's page and when they try to do a
forbidden action; write in the second person (you); see
@@ -19,7 +19,9 @@
<%= text_area 'admin_user', 'ban_text', :cols => 60, :rows => 3 %></p>
-<p><label for="about_me">About me</label> (user's own text on their profile, format like comments):<br/>
+<p><label for="admin_user_about_me">About me</label> (user's own text on their profile, format like comments):<br/>
<%= text_area 'admin_user', 'about_me', :cols => 60, :rows => 3 %></p>
+<p><%= check_box 'admin_user', 'no_limit' %>
+<label for="admin_user_no_limit">No rate limit</label> (disable the limit on daily requests)</p>
diff --git a/app/views/user/rate_limited.rhtml b/app/views/user/rate_limited.rhtml
new file mode 100644
index 000000000..d513cec9e
--- /dev/null
+++ b/app/views/user/rate_limited.rhtml
@@ -0,0 +1,5 @@
+<% @title = "Too many requests" %>
+
+<h1><%=@title%></h1>
+
+<p><%= _('You have made too many requests today. Please try again tomorrow.')%></p>
diff --git a/config/test.yml b/config/test.yml
index 693cdd6b8..6a423b47a 100644
--- a/config/test.yml
+++ b/config/test.yml
@@ -120,3 +120,6 @@ HTML_TO_PDF_COMMAND: /usr/local/bin/wkhtmltopdf-amd64
# Exception notifications
EXCEPTION_NOTIFICATIONS_FROM: do-not-reply-to-this-address@example.com
EXCEPTION_NOTIFICATIONS_TO:
+
+MAX_REQUESTS_PER_USER_PER_DAY: 2
+
diff --git a/db/migrate/110_add_user_no_limit.rb b/db/migrate/110_add_user_no_limit.rb
new file mode 100644
index 000000000..d78a05f75
--- /dev/null
+++ b/db/migrate/110_add_user_no_limit.rb
@@ -0,0 +1,13 @@
+require 'digest/sha1'
+
+class AddUserNoLimit < ActiveRecord::Migration
+ def self.up
+ add_column :users, :no_limit, :boolean, :default => false, :null => false
+ end
+ def self.down
+ remove_column :users, :no_limit
+ end
+end
+
+
+
diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index 77652b26d..3b58df869 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -702,6 +702,58 @@ describe RequestController, "when creating a new request" do
response.should redirect_to(:action => 'show', :url_title => ir2.url_title)
end
+
+ it 'should respect the rate limit' do
+ # Try to create three requests in succession.
+ # (The limit set in config/test.yml is two.)
+ session[:user_id] = users(:robin_user)
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What is the answer to the ultimate question?", :tag_string => "" },
+ :outgoing_message => { :body => "Please supply the answer from your files." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'what_is_the_answer_to_the_ultima')
+
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "Why did the chicken cross the road?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send me all the relevant documents you hold." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'why_did_the_chicken_cross_the_ro')
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What's black and white and red all over?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send all minutes of meetings and email records that address this question." },
+ :submitted_new_request => 1, :preview => 0
+ response.should render_template('user/rate_limited')
+ end
+
+ it 'should ignore the rate limit for specified users' do
+ # Try to create three requests in succession.
+ # (The limit set in config/test.yml is two.)
+ session[:user_id] = users(:robin_user)
+ users(:robin_user).no_limit = true
+ users(:robin_user).save!
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What is the answer to the ultimate question?", :tag_string => "" },
+ :outgoing_message => { :body => "Please supply the answer from your files." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'what_is_the_answer_to_the_ultima')
+
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "Why did the chicken cross the road?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send me all the relevant documents you hold." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'why_did_the_chicken_cross_the_ro')
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What's black and white and red all over?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send all minutes of meetings and email records that address this question." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'whats_black_and_white_and_red_al')
+ end
end
@@ -747,6 +799,7 @@ describe RequestController, "when making a new request" do
it "should fail if user is banned" do
@user.stub!(:can_file_requests?).and_return(false)
+ @user.stub!(:exceeded_limit?).and_return(false)
@user.should_receive(:can_fail_html).and_return('FAIL!')
session[:user_id] = @user.id
get :new, :public_body_id => @body.id