aboutsummaryrefslogtreecommitdiffstats
path: root/app/controllers/application_controller.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/application_controller.rb')
-rw-r--r--app/controllers/application_controller.rb103
1 files changed, 86 insertions, 17 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index b7457c48e..b681f455d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -11,10 +11,15 @@
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)
-
+
+ # Send notification email on exceptions
+ include ExceptionNotification::Notifiable
+
# Note: a filter stops the chain if it redirects or renders something
before_filter :authentication_check
before_filter :set_gettext_locale
@@ -84,6 +89,7 @@ class ApplicationController < ActionController::Base
def record_memory
record_memory = MySociety::Config.get('DEBUG_RECORD_MEMORY', false)
if record_memory
+ logger.info "Processing request for #{request.url} with Rails process #{Process.pid}"
File.read("/proc/#{Process.pid}/status").match(/VmRSS:\s+(\d+)/)
rss_before_action = $1.to_i
yield
@@ -117,8 +123,11 @@ 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
end
# Display user appropriate error message
@exception_backtrace = exception.backtrace.join("\n")
@@ -169,11 +178,13 @@ class ApplicationController < ActionController::Base
end
def foi_fragment_cache_path(param)
- path = foi_fragment_cache_part_path(param)
- path = "/views" + path
- foi_cache_path = File.join(File.dirname(__FILE__), '../../cache')
- return File.join(foi_cache_path, path)
+ path = File.join(RAILS_ROOT, 'cache', 'views', foi_fragment_cache_part_path(param))
+ max_file_length = 255 - 35 # we subtract 35 because tempfile
+ # adds on a variable number of
+ # characters
+ return File.join(File.split(path).map{|x| x[0...max_file_length]})
end
+
def foi_fragment_cache_all_for_request(info_request)
# return stub path so admin can expire it
first_three_digits = info_request.id.to_s()[0..2]
@@ -185,10 +196,12 @@ class ApplicationController < ActionController::Base
return File.exists?(key_path)
end
def foi_fragment_cache_read(key_path)
- cached = File.read(key_path)
+ logger.info "Reading from fragment cache #{key_path}"
+ return File.read(key_path)
end
def foi_fragment_cache_write(key_path, content)
FileUtils.mkdir_p(File.dirname(key_path))
+ logger.info "Writing to fragment cache #{key_path}"
File.atomic_write(key_path) do |f|
f.write(content)
end
@@ -341,9 +354,7 @@ class ApplicationController < ActionController::Base
@sortby = sortby
# Work out sorting method
- order_pair = order_to_sort_by(@sortby)
- order = order_pair[0]
- ascending = order_pair[1]
+ order, ascending = order_to_sort_by(@sortby)
# Peform the search
@per_page = per_page
@@ -352,23 +363,71 @@ class ApplicationController < ActionController::Base
else
@page = this_page
end
- return InfoRequest.full_search(models, @query, order, ascending, collapse, @per_page, @page)
+ result = InfoRequest.full_search(models, @query, order, ascending, collapse, @per_page, @page)
+ result.results # Touch the results to load them, otherwise accessing them from the view
+ # might fail later if the database has subsequently been reopened.
+ return result
end
def get_search_page_from_params
return (params[:page] || "1").to_i
end
+ def perform_search_typeahead(query, model)
+ @page = get_search_page_from_params
+ @per_page = 10
+ query_words = query.split(/ +(?![-+]+)/)
+ if query_words.last.nil? || query_words.last.strip.length < 3
+ xapian_requests = nil
+ else
+ if model == PublicBody
+ collapse = nil
+ elsif model == InfoRequestEvent
+ collapse = 'request_collapse'
+ end
+ options = {
+ :offset => (@page - 1) * @per_page,
+ :limit => @per_page,
+ :sort_by_prefix => nil,
+ :sort_by_ascending => true,
+ :collapse_by_prefix => collapse,
+ }
+ ActsAsXapian.readable_init
+ old_default_op = ActsAsXapian.query_parser.default_op
+ ActsAsXapian.query_parser.default_op = Xapian::Query::OP_OR
+ begin
+ user_query = ActsAsXapian.query_parser.parse_query(
+ query.strip + '*',
+ Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_WILDCARD |
+ Xapian::QueryParser::FLAG_SPELLING_CORRECTION)
+ xapian_requests = ActsAsXapian::Search.new([model], query, options, user_query)
+ rescue RuntimeError => e
+ if e.message =~ /^QueryParserError: Wildcard/
+ # Wildcard expands to too many terms
+ logger.info "Wildcard query '#{query.strip + '*'}' caused: #{e.message}"
+
+ user_query = ActsAsXapian.query_parser.parse_query(
+ query,
+ Xapian::QueryParser::FLAG_LOVEHATE |
+ Xapian::QueryParser::FLAG_SPELLING_CORRECTION)
+ xapian_requests = ActsAsXapian::Search.new([model], query, options, user_query)
+ end
+ end
+ ActsAsXapian.query_parser.default_op = old_default_op
+ end
+ return xapian_requests
+ end
+
# Store last visited pages, for contact form; but only for logged in users, as otherwise this breaks caching
def set_last_request(info_request)
if !session[:user_id].nil?
- session[:last_request_id] = info_request.id
- session[:last_body_id] = nil
+ cookies["last_request_id"] = info_request.id
+ cookies["last_body_id"] = nil
end
end
def set_last_body(public_body)
if !session[:user_id].nil?
- session[:last_request_id] = nil
- session[:last_body_id] = public_body.id
+ cookies["last_request_id"] = nil
+ cookies["last_body_id"] = public_body.id
end
end
@@ -406,7 +465,7 @@ class ApplicationController < ActionController::Base
params[:latest_status] = [params[:latest_status]]
end
if params[:latest_status].include?("recent") || params[:latest_status].include?("all")
- query += " variety:sent"
+ query += " (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)"
end
if params[:latest_status].include? "successful"
statuses << ['latest_status:successful', 'latest_status:partially_successful']
@@ -415,7 +474,7 @@ class ApplicationController < ActionController::Base
statuses << ['latest_status:rejected', 'latest_status:not_held']
end
if params[:latest_status].include? "awaiting"
- statuses << ['latest_status:waiting_response', 'latest_status:waiting_clarification', 'waiting_classification:true']
+ statuses << ['latest_status:waiting_response', 'latest_status:waiting_clarification', 'waiting_classification:true', 'latest_status:internal_review','latest_status:gone_postal', 'latest_status:error_message', 'latest_status:requires_admin']
end
if params[:latest_status].include? "internal_review"
statuses << ['status:internal_review']
@@ -475,12 +534,22 @@ class ApplicationController < ActionController::Base
default = MySociety::Config.get('ISO_COUNTRY_CODE', '')
country = ""
if !gaze.empty?
- country = open("#{gaze}/gaze-rest?f=get_country_from_ip;ip=#{request.remote_ip}").read.strip
+ country = quietly_try_to_open("#{gaze}/gaze-rest?f=get_country_from_ip;ip=#{request.remote_ip}")
end
country = default if country.empty?
return country
end
+ def quietly_try_to_open(url)
+ begin
+ result = open(url).read.strip
+ rescue OpenURI::HTTPError, SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ logger.warn("Unable to open third-party URL #{url}")
+ result = ""
+ end
+ return result
+ end
+
# URL generating functions are needed by all controllers (for redirects),
# views (for links) and mailers (for use in emails), so include them into
# all of all.