aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/request_controller.rb22
-rw-r--r--app/models/info_request.rb85
-rw-r--r--spec/controllers/request_controller_spec.rb12
-rw-r--r--spec/models/customstates.rb62
-rw-r--r--spec/models/info_request_spec.rb36
5 files changed, 180 insertions, 37 deletions
diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb
index 103349311..9fc0a4e26 100644
--- a/app/controllers/request_controller.rb
+++ b/app/controllers/request_controller.rb
@@ -12,6 +12,21 @@ class RequestController < ApplicationController
before_filter :check_read_only, :only => [ :new, :show_response, :describe_state, :upload_response ]
protect_from_forgery :only => [ :new, :show_response, :describe_state, :upload_response ] # See ActionController::RequestForgeryProtection for details
+ def load_custom_states
+ begin
+ # InfoRequestCustomStates may be `require`d in a theme
+ # plugin, or by a test
+ RequestController.send(:include, RequestControllerCustomStates)
+ @@custom_states_loaded = true
+ rescue NameError
+ @@custom_states_loaded = false
+ end
+ end
+
+ def initialize
+ self.load_custom_states
+ end
+
def show
@locale = self.locale_from_params()
PublicBody.with_locale(@locale) do
@@ -369,6 +384,7 @@ class RequestController < ApplicationController
end
return
end
+
# Display advice for requester on what to do next, as appropriate
if @info_request.calculate_status == 'waiting_response'
flash[:notice] = _("<p>Thank you! Hopefully your wait isn't too long.</p> <p>By law, you should get a response promptly, and normally before the end of <strong>
@@ -420,9 +436,9 @@ class RequestController < ApplicationController
flash[:notice] = _("If you have not done so already, please write a message below telling the authority that you have withdrawn your request. Otherwise they will not know it has been withdrawn.")
redirect_to respond_to_last_url(@info_request)
else
- begin
- return theme_describe_state(@info_request)
- rescue NoMethodError
+ if @@custom_states_loaded
+ return self.theme_describe_state(@info_request)
+ else
raise "unknown calculate_status " + @info_request.calculate_status
end
end
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 07245bdfd..16e66c44a 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -51,30 +51,9 @@ class InfoRequest < ActiveRecord::Base
has_many :exim_logs, :order => 'exim_log_done_id'
has_tag_string
-
- def self.enumerate_states
- states = [
- 'waiting_response',
- 'waiting_clarification',
- 'gone_postal',
- 'not_held',
- 'rejected', # this is called 'refused' in UK FOI law and the user interface, but 'rejected' internally for historic reasons
- 'successful',
- 'partially_successful',
- 'internal_review',
- 'error_message',
- 'requires_admin',
- 'user_withdrawn'
- ]
- begin
- states += theme_extra_states
- rescue NoMethodError
- states
- end
- end
# user described state (also update in info_request_event, admin_request/edit.rhtml)
- validates_inclusion_of :described_state, :in => InfoRequest.enumerate_states
+ validate :must_be_valid_state
validates_inclusion_of :prominence, :in => [
'normal',
@@ -101,7 +80,31 @@ class InfoRequest < ActiveRecord::Base
'blackhole' # just dump them
]
+ def enumerate_states
+ states = [
+ 'waiting_response',
+ 'waiting_clarification',
+ 'gone_postal',
+ 'not_held',
+ 'rejected', # this is called 'refused' in UK FOI law and the user interface, but 'rejected' internally for historic reasons
+ 'successful',
+ 'partially_successful',
+ 'internal_review',
+ 'error_message',
+ 'requires_admin',
+ 'user_withdrawn'
+ ]
+
+ if @@custom_states_loaded
+ states += self.theme_extra_states
+ end
+ states
+ end
+ def must_be_valid_state
+ errors.add(:described_state, "is not a valid state") if
+ !self.enumerate_states.include? described_state
+ end
# only check on create, so existing models with mixed case are allowed
def validate_on_create
if !self.title.nil? && !MySociety::Validate.uses_mixed_capitals(self.title, 10)
@@ -118,6 +121,7 @@ class InfoRequest < ActiveRecord::Base
OLD_AGE_IN_DAYS = 21.days
def after_initialize
+ self.load_custom_states
if self.described_state.nil?
self.described_state = 'waiting_response'
end
@@ -127,6 +131,17 @@ class InfoRequest < ActiveRecord::Base
end
end
+ def load_custom_states
+ begin
+ # InfoRequestCustomStates may be `require`d in a theme
+ # plugin, or by a test
+ InfoRequest.send(:include, InfoRequestCustomStates)
+ @@custom_states_loaded = true
+ rescue NameError
+ @@custom_states_loaded = false
+ end
+ end
+
def visible_comments
self.comments.find(:all, :conditions => 'visible')
end
@@ -520,10 +535,15 @@ public
# waiting_response_overdue
# waiting_response_very_overdue
def calculate_status
+ if @@custom_states_loaded
+ return self.theme_calculate_status
+ else
+ self.base_calculate_status
+ end
+ end
+
+ def base_calculate_status
return 'waiting_classification' if self.awaiting_description
- # if deadline_extended expired do waiting_response_overdue
- return 'waiting_response_overdue' if
- self.described_state == "deadline_extended" && Time.now.strftime("%Y-%m-%d") > self.date_deadline_extended.strftime("%Y-%m-%d")
return described_state unless self.described_state == "waiting_response"
# Compare by date, so only overdue on next day, not if 1 second late
return 'waiting_response_very_overdue' if
@@ -635,10 +655,7 @@ public
return Holiday.due_date_from(self.date_initial_request_last_sent_at, 40)
end
end
- # deadline_extended
- def date_deadline_extended
- return Holiday.due_date_from(self.date_initial_request_last_sent_at, 15)
- end
+
# Where the initial request is sent to
def recipient_email
return self.public_body.request_email
@@ -777,10 +794,6 @@ public
_("Waiting clarification.")
elsif status == 'gone_postal'
_("Handled by post.")
- elsif status == 'deadline_extended'
- _("Deadline extended.")
- elsif status == 'wrong_response'
- _("Wrong Response.")
elsif status == 'internal_review'
_("Awaiting internal review.")
elsif status == 'error_message'
@@ -790,7 +803,11 @@ public
elsif status == 'user_withdrawn'
_("Withdrawn by the requester.")
else
- raise _("unknown status ") + status
+ begin
+ return self.theme_display_status(status)
+ rescue NoMethodError
+ raise _("unknown status ") + status
+ end
end
end
diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index 0d9916b71..64f3f8061 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -526,6 +526,8 @@ describe RequestController, "when classifying an information request" do
response.should render_template('user/wrong_user')
end
+
+
describe 'when the request is old and unclassified' do
before do
@@ -714,6 +716,16 @@ describe RequestController, "when classifying an information request" do
post_status('rejected')
response.should redirect_to(:controller => 'help', :action => 'unhappy', :url_title => @dog_request.url_title)
end
+
+ describe "when using custom statuses from the theme" do
+ InfoRequest.send(:require, File.expand_path(File.join(File.dirname(__FILE__), '..', 'models', 'customstates')))
+
+ it "knows about extended states" do
+ Time.stub!(:now).and_return(Time.utc(2007, 11, 10, 00, 01))
+ post_status('deadline_extended')
+ flash[:notice].should == 'Authority has requested extension of the deadline.'
+ end
+ end
end
describe 'when redirecting after a successful status update by the request owner' do
diff --git a/spec/models/customstates.rb b/spec/models/customstates.rb
new file mode 100644
index 000000000..de8d04ffb
--- /dev/null
+++ b/spec/models/customstates.rb
@@ -0,0 +1,62 @@
+module InfoRequestCustomStates
+ # Mixin methods for InfoRequest
+ def theme_display_status(status)
+ if status == 'deadline_extended'
+ _("Deadline extended.")
+ elsif status == 'wrong_response'
+ _("Wrong Response.")
+ else
+ raise _("unknown status ") + status
+ end
+ end
+
+ def theme_extra_states
+ return ['deadline_extended',
+ 'wrong_response']
+ end
+
+
+ def theme_calculate_status
+ return 'waiting_classification' if self.awaiting_description
+ waiting_response = self.described_state == "waiting_response" || self.described_state == "deadline_extended"
+ return self.described_state unless waiting_response
+ if self.described_state == 'deadline_extended'
+ return 'deadline_extended' if
+ Time.now.strftime("%Y-%m-%d") < self.date_deadline_extended.strftime("%Y-%m-%d")
+ return 'waiting_response_very_overdue' if
+ Time.now.strftime("%Y-%m-%d") > Holiday.due_date_from(self.date_deadline_extended, 15).strftime("%Y-%m-%d")
+ return 'waiting_response_overdue'
+ end
+ return 'waiting_response_very_overdue' if
+ Time.now.strftime("%Y-%m-%d") > self.date_very_overdue_after.strftime("%Y-%m-%d")
+ return 'waiting_response_overdue' if
+ Time.now.strftime("%Y-%m-%d") > self.date_response_required_by.strftime("%Y-%m-%d")
+ return 'waiting_response'
+ end
+
+ def date_deadline_extended
+ # XXX shouldn't this be 15 days after the date the status was
+ # changed to "deadline extended"? Or perhaps 15 days ater the
+ # initial request due date?
+ return Holiday.due_date_from(self.date_response_required_by, 15)
+ end
+
+end
+
+module RequestControllerCustomStates
+
+ def theme_describe_state(info_request)
+ # called after the core describe_state code. It should
+ # end by raising an error if the status is unknown
+ if info_request.calculate_status == 'deadline_extended'
+ flash[:notice] = _("Authority has requested extension of the deadline.")
+ redirect_to unhappy_url(info_request)
+ elsif info_request.calculate_status == 'wrong_response'
+ flash[:notice] = _("Oh no! Sorry to hear that your request was wrong. Here is what to do now.")
+ redirect_to unhappy_url(info_request)
+ else
+ raise "unknown calculate_status " + info_request.calculate_status
+ end
+ end
+
+end
diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb
index 96a4f5bc8..91b1b0876 100644
--- a/spec/models/info_request_spec.rb
+++ b/spec/models/info_request_spec.rb
@@ -159,6 +159,42 @@ describe InfoRequest do
end
end
+
+ describe "when using a plugin and calculating the status" do
+
+ fixtures :info_requests
+
+ before do
+ InfoRequest.send(:require, File.expand_path(File.dirname(__FILE__) + '/customstates'))
+ @ir = info_requests(:naughty_chicken_request)
+ @ir.load_custom_states
+ end
+
+ it "rejects invalid states" do
+ lambda {@ir.set_described_state("foo")}.should raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it "accepts core states" do
+ @ir.set_described_state("requires_admin")
+ end
+
+ it "accepts extended states" do
+ # this time would normally be "overdue"
+ Time.stub!(:now).and_return(Time.utc(2007, 11, 10, 00, 01))
+ @ir.set_described_state("deadline_extended")
+ @ir.display_status.should == 'Deadline extended.'
+ @ir.date_deadline_extended
+ end
+
+ it "is not overdue if it's had the deadline extended" do
+ when_overdue = Time.utc(2007, 11, 10, 00, 01) + 16.days
+ Time.stub!(:now).and_return(when_overdue)
+ @ir.calculate_status.should == 'waiting_response_overdue'
+ end
+
+ end
+
+
describe "when calculating the status for a school" do
fixtures :info_requests, :info_request_events, :holidays, :public_bodies, :public_body_translations