diff options
-rw-r--r-- | app/controllers/application_controller.rb | 10 | ||||
-rw-r--r-- | app/controllers/request_controller.rb | 24 | ||||
-rw-r--r-- | app/models/foi_attachment.rb | 1 | ||||
-rw-r--r-- | app/models/incoming_message.rb | 30 | ||||
-rw-r--r-- | app/models/request_mailer.rb | 13 | ||||
-rw-r--r-- | app/views/admin_general/debug.rhtml | 2 | ||||
-rw-r--r-- | app/views/user/sign.rhtml | 13 | ||||
-rw-r--r-- | doc/CHANGES.md | 1 | ||||
-rw-r--r-- | spec/controllers/request_controller_spec.rb | 17 | ||||
-rw-r--r-- | spec/controllers/user_controller_spec.rb | 5 | ||||
-rw-r--r-- | spec/integration/errors_spec.rb | 8 | ||||
-rw-r--r-- | vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb | 25 |
12 files changed, 104 insertions, 45 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8fd2da54a..7aa522389 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -11,6 +11,8 @@ require 'open-uri' class ApplicationController < ActionController::Base + class PermissionDenied < StandardError + end # Standard headers, footers and navigation for whole site layout "default" include FastGettext::Translation # make functions like _, n_, N_ etc available) @@ -120,6 +122,8 @@ class ApplicationController < ActionController::Base case exception when ActiveRecord::RecordNotFound, ActionController::UnknownAction, ActionController::RoutingError @status = 404 + when PermissionDenied + @status = 403 else @status = 500 notify_about_exception exception @@ -189,7 +193,7 @@ class ApplicationController < ActionController::Base return File.exists?(key_path) end def foi_fragment_cache_read(key_path) - cached = File.read(key_path) + return File.read(key_path) end def foi_fragment_cache_write(key_path, content) FileUtils.mkdir_p(File.dirname(key_path)) @@ -367,8 +371,8 @@ class ApplicationController < ActionController::Base # XXX this is a result of the OR hack below -- should fix by # allowing a parameter to perform_search to control the # default operator! - query = query.gsub(/(\s-\s|&)/, "") - query = query.split(/ +(?!-)/) + query = query.strip.gsub(/(\s-\s|&)/, "") + query = query.split(/ +(?![-+]+)/) if query.last.nil? || query.last.strip.length < 3 xapian_requests = nil else diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 6e33fe043..99aa3c7ea 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -37,8 +37,7 @@ class RequestController < ApplicationController end if !params[:query].nil? query = params[:query] - query = query.split(' ').join(' OR ') # XXX: HACK for OR instead of default AND! - @xapian_requests = perform_search([PublicBody], query, 'relevant', nil, 5) + @xapian_requests = perform_search_typeahead(query, PublicBody) end medium_cache end @@ -118,11 +117,14 @@ class RequestController < ApplicationController def details long_cache @info_request = InfoRequest.find_by_url_title(params[:url_title]) - if !@info_request.user_can_view?(authenticated_user) - render :template => 'request/hidden', :status => 410 # gone - return + if @info_request.nil? + raise ActiveRecord::RecordNotFound.new("Request not found") + else + if !@info_request.user_can_view?(authenticated_user) + render :template => 'request/hidden', :status => 410 # gone + return + end end - @columns = ['id', 'event_type', 'created_at', 'described_state', 'last_described_at', 'calculated_state' ] end @@ -600,9 +602,13 @@ class RequestController < ApplicationController before_filter :authenticate_attachment, :only => [ :get_attachment, :get_attachment_as_html ] def authenticate_attachment # Test for hidden - incoming_message = IncomingMessage.find(params[:incoming_message_id]) - if !incoming_message.info_request.user_can_view?(authenticated_user) - render :template => 'request/hidden', :status => 410 # gone + if request.path =~ /\/$/ + raise PermissionDenied.new("Directory listing not allowed") + else + incoming_message = IncomingMessage.find(params[:incoming_message_id]) + if !incoming_message.info_request.user_can_view?(authenticated_user) + render :template => 'request/hidden', :status => 410 # gone + end end end diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb index dc55ff5f6..d12df688a 100644 --- a/app/models/foi_attachment.rb +++ b/app/models/foi_attachment.rb @@ -57,6 +57,7 @@ class FoiAttachment < ActiveRecord::Base end File.open(self.filepath, "wb") { |file| file.write d + file.fsync } update_display_size! @cached_body = d diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb index f0f1680eb..2186d50dc 100644 --- a/app/models/incoming_message.rb +++ b/app/models/incoming_message.rb @@ -128,21 +128,23 @@ class IncomingMessage < ActiveRecord::Base # values in case we want to regenerate them (due to mail # parsing bugs, etc). if (!force.nil? || self.last_parsed.nil?) - self.extract_attachments! - self.sent_at = self.mail.date || self.created_at - self.subject = self.mail.subject - # XXX can probably remove from_name_if_present (which is a - # monkey patch) by just calling .from_addrs[0].name here - # instead? - self.mail_from = self.mail.from_name_if_present - begin - self.mail_from_domain = PublicBody.extract_domain_from_email(self.mail.from_addrs[0].spec) - rescue NoMethodError - self.mail_from_domain = "" + ActiveRecord::Base.transaction do + self.extract_attachments! + self.sent_at = self.mail.date || self.created_at + self.subject = self.mail.subject + # XXX can probably remove from_name_if_present (which is a + # monkey patch) by just calling .from_addrs[0].name here + # instead? + self.mail_from = self.mail.from_name_if_present + begin + self.mail_from_domain = PublicBody.extract_domain_from_email(self.mail.from_addrs[0].spec) + rescue NoMethodError + self.mail_from_domain = "" + end + self.valid_to_reply_to = self._calculate_valid_to_reply_to + self.last_parsed = Time.now + self.save! end - self.valid_to_reply_to = self._calculate_valid_to_reply_to - self.last_parsed = Time.now - self.save! end end diff --git a/app/models/request_mailer.rb b/app/models/request_mailer.rb index 272f2ea83..83cce9045 100644 --- a/app/models/request_mailer.rb +++ b/app/models/request_mailer.rb @@ -353,7 +353,18 @@ class RequestMailer < ApplicationMailer # That that patch has not been applied, despite bribes of beer, is # typical of the lack of quality of Rails. - info_requests = InfoRequest.find(:all, :conditions => [ "(select id from info_request_events where event_type = 'comment' and info_request_events.info_request_id = info_requests.id and created_at > ? limit 1) is not null", Time.now() - 1.month ], :include => [ { :info_request_events => :user_info_request_sent_alerts } ], :order => "info_requests.id, info_request_events.created_at" ) + info_requests = InfoRequest.find(:all, + :conditions => [ + "info_requests.id in ( + select info_request_id + from info_request_events + where event_type = 'comment' + and created_at > (now() - '1 month'::interval) + )" + ], + :include => [ { :info_request_events => :user_info_request_sent_alerts } ], + :order => "info_requests.id, info_request_events.created_at" + ) for info_request in info_requests # Count number of new comments to alert on diff --git a/app/views/admin_general/debug.rhtml b/app/views/admin_general/debug.rhtml index 422edea03..b3b06085f 100644 --- a/app/views/admin_general/debug.rhtml +++ b/app/views/admin_general/debug.rhtml @@ -16,8 +16,6 @@ TMail::VERSION::STRING <%=h TMail::VERSION::STRING%> Xapian::version_string <%=h Xapian::version_string%> <br> Spec::VERSION::STRING <%=h Spec::VERSION::STRING%> -<br> -Spec::Rails::VERSION::STRING <%=h Spec::Rails::VERSION::STRING%> </p> <h2>Configuration</h2> diff --git a/app/views/user/sign.rhtml b/app/views/user/sign.rhtml index afdb90162..bfd0fa63e 100644 --- a/app/views/user/sign.rhtml +++ b/app/views/user/sign.rhtml @@ -1,4 +1,4 @@ -<% if @post_redirect.reason_params[:user_name] %> +<% if !@post_redirect.nil? && @post_redirect.reason_params[:user_name] %> <% @title = _("Sign in") %> <div id="sign_alone"> @@ -19,16 +19,7 @@ <% else %> <% @title = _('Sign in or make a new account') %> - <div id="sign_together"> - - <!--<p id="sign_in_reason"> - <% if @post_redirect.reason_params[:web].empty? %> - <%= _(' Please sign in or make a new account.') %> - <% else %> - <%= @post_redirect.reason_params[:web] %>, <%= _('please sign in or make a new account.') %> - <% end %> - </p>--> - + <div id="sign_together"> <div id="left_half"> <h1><%= _('Sign in') %></h1> <%= render :partial => 'signin', :locals => { :sign_in_as_existing_user => false } %> diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 8778aaac2..99aaf7c98 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -20,6 +20,7 @@ * EXCEPTION_NOTIFICATIONS_FROM * EXCEPTION_NOTIFICATIONS_TO * The recommended Varnish config has changed, so that we ignore more cookies. You should review your Varnish config with respect to the example at `config/varnish-alaveteli.vcl`. +* Consider setting elinks global config as described in the "Troubleshooting" section of INSTALL.md # Version 0.4 diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index fc62edc14..96786a0a3 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -420,7 +420,7 @@ describe RequestController, "when searching for an authority" do get :select_authority, :query => "" response.should render_template('select_authority') - assigns[:xapian_requests].results.size == 0 + assigns[:xapian_requests].should == nil end it "should return matching bodies" do @@ -431,6 +431,18 @@ describe RequestController, "when searching for an authority" do assigns[:xapian_requests].results.size == 1 assigns[:xapian_requests].results[0][:model].name.should == public_bodies(:geraldine_public_body).name end + + it "should not give an error when user users unintended search operators" do + for phrase in ["Marketing/PR activities - Aldborough E-Act Free Schoo", + "Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ", + "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the", + "NHS Ayrshire & Arran", + " cardiff"] + lambda { + get :select_authority, :query => phrase + }.should_not raise_error(StandardError) + end + end end describe RequestController, "when creating a new request" do @@ -1496,7 +1508,8 @@ describe RequestController, "when doing type ahead searches" do it "should not give an error when user users unintended search operators" do for phrase in ["Marketing/PR activities - Aldborough E-Act Free Schoo", "Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ", - "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the"] + "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the", + "NHS Ayrshire & Arran"] lambda { get :search_typeahead, :q => phrase }.should_not raise_error(StandardError) diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index 2560b48c7..30ad61706 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -111,15 +111,16 @@ describe UserController, "when signing in" do it "should not log you in if you use an invalid PostRedirect token, and shouldn't give 500 error either" do ActionController::Routing::Routes.filters.clear - get :signin, :r => "/list" - response.should render_template('sign') post_redirect = "something invalid" lambda { post :signin, { :user_signin => { :email => 'bob@localhost', :password => 'jonespassword' }, :token => post_redirect } }.should_not raise_error(NoMethodError) + post :signin, { :user_signin => { :email => 'bob@localhost', :password => 'jonespassword' }, + :token => post_redirect } response.should render_template('sign') + assigns[:post_redirect].should == nil end # No idea how to test this in the test framework :( diff --git a/spec/integration/errors_spec.rb b/spec/integration/errors_spec.rb index bfb7e5fb5..8084bb35a 100644 --- a/spec/integration/errors_spec.rb +++ b/spec/integration/errors_spec.rb @@ -45,5 +45,13 @@ describe "When rendering errors" do get("/request/#{ir.url_title}") response.code.should == "500" end + it "should render a 403 for attempts at directory listing for attachments" do + get("/request/5/response/4/attach/html/3/" ) + response.code.should == "403" + end + it "should render a 404 for non-existent 'details' pages for requests" do + get("/details/request/wobble" ) + response.code.should == "404" + end end diff --git a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb index 70605ad04..c086c8125 100644 --- a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb +++ b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb @@ -248,6 +248,8 @@ module ActsAsXapian end end + MSET_MAX_TRIES = 5 + MSET_MAX_DELAY = 5 # Set self.query before calling this def initialize_query(options) #raise options.to_yaml @@ -278,7 +280,28 @@ module ActsAsXapian ActsAsXapian.enquire.collapse_key = value end - self.matches = ActsAsXapian.enquire.mset(offset, limit, 100) + tries = 0 + delay = 1 + begin + self.matches = ActsAsXapian.enquire.mset(offset, limit, 100) + rescue IOError => e + if e.message =~ /DatabaseModifiedError: / + # This should be a transient error, so back off and try again, up to a point + if tries > MAX_TRIES + raise "Received DatabaseModifiedError from Xapian even after retrying #{MAX_TRIES} times" + else + sleep delay + end + tries += 1 + delay *= 2 + delay = MAX_DELAY if delay > MAX_DELAY + + @@db.reopen() + retry + else + raise + end + end self.cached_results = nil } end |