diff options
Diffstat (limited to 'app/controllers')
-rw-r--r-- | app/controllers/admin_controller.rb | 14 | ||||
-rw-r--r-- | app/controllers/admin_public_body_controller.rb | 83 | ||||
-rw-r--r-- | app/controllers/admin_user_controller.rb | 12 | ||||
-rw-r--r-- | app/controllers/application_controller.rb | 154 | ||||
-rw-r--r-- | app/controllers/general_controller.rb | 151 | ||||
-rw-r--r-- | app/controllers/public_body_controller.rb | 56 | ||||
-rw-r--r-- | app/controllers/request_controller.rb | 140 | ||||
-rw-r--r-- | app/controllers/services_controller.rb | 32 | ||||
-rw-r--r-- | app/controllers/user_controller.rb | 47 |
9 files changed, 531 insertions, 158 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 655670b5a..0bfbcd3d1 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -45,13 +45,17 @@ class AdminController < ApplicationController end end private + def authenticate - username = MySociety::Config.get('ADMIN_USERNAME', '') - password = MySociety::Config.get('ADMIN_PASSWORD', '') - if !username.empty? && !password.empty? + config_username = MySociety::Config.get('ADMIN_USERNAME', '') + config_password = MySociety::Config.get('ADMIN_PASSWORD', '') + if !config_username.empty? && !config_password.empty? authenticate_or_request_with_http_basic do |user_name, password| - user_name == username && password == password - session[:using_admin] = 1 + if user_name == config_username && password == config_password + session[:using_admin] = 1 + else + request_http_basic_authentication + end end else session[:using_admin] = 1 diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index 021122734..e249cef11 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -6,6 +6,8 @@ # # $Id: admin_public_body_controller.rb,v 1.23 2009-08-26 00:58:29 francis Exp $ +require "public_body_categories" + class AdminPublicBodyController < AdminController def index list @@ -82,16 +84,12 @@ class AdminPublicBodyController < AdminController end def new - @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do - @public_body = PublicBody.new - render - end + @public_body = PublicBody.new + render end - + def create - @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + PublicBody.with_locale(I18n.default_locale) do params[:public_body][:last_edit_editor] = admin_http_auth_user() @public_body = PublicBody.new(params[:public_body]) if @public_body.save @@ -104,17 +102,13 @@ class AdminPublicBodyController < AdminController end def edit - @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do - @public_body = PublicBody.find(params[:id]) - @public_body.last_edit_comment = "" - render - end + @public_body = PublicBody.find(params[:id]) + @public_body.last_edit_comment = "" + render end def update - @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + PublicBody.with_locale(I18n.default_locale) do params[:public_body][:last_edit_editor] = admin_http_auth_user() @public_body = PublicBody.find(params[:id]) if @public_body.update_attributes(params[:public_body]) @@ -146,41 +140,36 @@ class AdminPublicBodyController < AdminController def import_csv if params[:csv_file] - if !params[:tag].empty? - if params['commit'] == 'Dry run' - dry_run_only = true - elsif params['commit'] == 'Upload' - dry_run_only = false + if params['commit'] == 'Dry run' + dry_run_only = true + elsif params['commit'] == 'Upload' + dry_run_only = false + else + raise "internal error, unknown button label" + end + + # Try with dry run first + csv_contents = params[:csv_file].read + en = PublicBody.import_csv(csv_contents, params[:tag], params[:tag_behaviour], true, admin_http_auth_user(), I18n.available_locales) + errors = en[0] + notes = en[1] + + if errors.size == 0 + if dry_run_only + notes.push("Dry run was successful, real run would do as above.") else - raise "internal error, unknown button label" - end - - # Try with dry run first - csv_contents = params[:csv_file].read - en = PublicBody.import_csv(csv_contents, params[:tag], true, admin_http_auth_user(), I18n.available_locales) - errors = en[0] - notes = en[1] - - if errors.size == 0 - if dry_run_only - notes.push("Dry run was successful, real run would do as above.") - else - # And if OK, with real run - en = PublicBody.import_csv(csv_contents, params[:tag], false, admin_http_auth_user(), available_locales) - errors = en[0] - notes = en[1] - if errors.size != 0 - raise "dry run mismatched real run" - end - notes.push("Import was successful.") + # And if OK, with real run + en = PublicBody.import_csv(csv_contents, params[:tag], params[:tag_behaviour], false, admin_http_auth_user(), I18n.available_locales) + errors = en[0] + notes = en[1] + if errors.size != 0 + raise "dry run mismatched real run" end + notes.push("Import was successful.") end - @errors = errors.join("\n") - @notes = notes.join("\n") - else - @errors = "Please enter a tag, use a singular e.g. sea_fishery_committee" - @notes = "" end + @errors = errors.join("\n") + @notes = notes.join("\n") else @errors = "" @notes = "" diff --git a/app/controllers/admin_user_controller.rb b/app/controllers/admin_user_controller.rb index 404c4c3fe..5d90e74fe 100644 --- a/app/controllers/admin_user_controller.rb +++ b/app/controllers/admin_user_controller.rb @@ -28,6 +28,10 @@ class AdminUserController < AdminController # Don't use @user as that is any logged in user @admin_user = User.find(params[:id]) end + + def show_bounce_message + @admin_user = User.find(params[:id]) + end def edit @admin_user = User.find(params[:id]) @@ -57,6 +61,14 @@ class AdminUserController < AdminController flash[:notice] = 'Track destroyed' redirect_to user_admin_url(track_thing.tracking_user) end + + def clear_bounce + user = User.find(params[:id]) + user.email_bounced_at = nil + user.email_bounce_message = "" + user.save! + redirect_to user_admin_url(user) + end def login_as @admin_user = User.find(params[:id]) # check user does exist diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0df3e22da..b7457c48e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,13 +8,20 @@ # # $Id: application.rb,v 1.59 2009-09-17 13:01:56 francis Exp $ +require 'open-uri' class ApplicationController < ActionController::Base # Standard headers, footers and navigation for whole site layout "default" include FastGettext::Translation # make functions like _, n_, N_ etc available) + + # Note: a filter stops the chain if it redirects or renders something + before_filter :authentication_check before_filter :set_gettext_locale + before_filter :check_in_post_redirect + before_filter :session_remember_me before_filter :set_vary_header + # scrub sensitive parameters from the logs filter_parameter_logging :password @@ -47,7 +54,14 @@ class ApplicationController < ActionController::Base else requested_locale = params[:locale] || session[:locale] || cookies[:locale] || I18n.default_locale end + requested_locale = FastGettext.best_locale_in(requested_locale) session[:locale] = FastGettext.set_locale(requested_locale) + if !@user.nil? + if @user.locale != requested_locale + @user.locale = session[:locale] + @user.save! + end + end end # scrub sensitive parameters from the logs @@ -84,7 +98,6 @@ class ApplicationController < ActionController::Base # Set cookie expiry according to "remember me" checkbox, as per "An easier # and more flexible hack" on this page: # http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions - before_filter :session_remember_me def session_remember_me # Reset the "sliding window" session expiry time. if request.env['rack.session.options'] @@ -101,11 +114,17 @@ class ApplicationController < ActionController::Base # Make sure expiry time for session is set (before_filters are # otherwise missed by this override) session_remember_me - + case exception + when ActiveRecord::RecordNotFound, ActionController::UnknownAction, ActionController::RoutingError + @status = 404 + else + @status = 500 + end # Display user appropriate error message @exception_backtrace = exception.backtrace.join("\n") @exception_class = exception.class.to_s - render :template => "general/exception_caught.rhtml", :status => 404 + @exception_message = exception.message + render :template => "general/exception_caught.rhtml", :status => @status end # For development sites. @@ -192,7 +211,9 @@ class ApplicationController < ActionController::Base post_redirect = PostRedirect.new(:uri => request.request_uri, :post_params => params, :reason_params => reason_params) post_redirect.save! - redirect_to signin_url(:token => post_redirect.token) + # 'modal' controls whether the sign-in form will be displayed in the typical full-blown + # page or on its own, useful for pop-ups + redirect_to signin_url(:token => post_redirect.token, :modal => params[:modal]) return false end return true @@ -256,7 +277,6 @@ class ApplicationController < ActionController::Base end # If we are in a faked redirect to POST request, then set post params. - before_filter :check_in_post_redirect def check_in_post_redirect if params[:post_redirect] and session[:post_redirect_token] post_redirect = PostRedirect.find_by_token(session[:post_redirect_token]) @@ -265,7 +285,6 @@ class ApplicationController < ActionController::Base end # Default layout shows user in corner, so needs access to it - before_filter :authentication_check def authentication_check if session[:user_id] @user = authenticated_user @@ -339,14 +358,127 @@ class ApplicationController < ActionController::Base return (params[:page] || "1").to_i end - # Store last visited pages, for contact form + # Store last visited pages, for contact form; but only for logged in users, as otherwise this breaks caching def set_last_request(info_request) - session[:last_request_id] = info_request.id - session[:last_body_id] = nil + if !session[:user_id].nil? + session[:last_request_id] = info_request.id + session[:last_body_id] = nil + end end def set_last_body(public_body) - session[:last_request_id] = nil - session[:last_body_id] = public_body.id + if !session[:user_id].nil? + session[:last_request_id] = nil + session[:last_body_id] = public_body.id + end + end + + def param_exists(item) + return params[item] && !params[item].empty? + end + + def get_request_variety_from_params + query = "" + sortby = "newest" + varieties = [] + if params[:request_variety] && !(query =~ /variety:/) + if params[:request_variety].include? "sent" + varieties -= ['variety:sent', 'variety:followup_sent', 'variety:response', 'variety:comment'] + varieties << ['variety:sent', 'variety:followup_sent'] + end + if params[:request_variety].include? "response" + varieties << ['variety:response'] + end + if params[:request_variety].include? "comment" + varieties << ['variety:comment'] + end + end + if !varieties.empty? + query = " (#{varieties.join(' OR ')})" + end + return query + end + + def get_status_from_params + query = "" + if params[:latest_status] + statuses = [] + if params[:latest_status].class == String + params[:latest_status] = [params[:latest_status]] + end + if params[:latest_status].include?("recent") || params[:latest_status].include?("all") + query += " variety:sent" + end + if params[:latest_status].include? "successful" + statuses << ['latest_status:successful', 'latest_status:partially_successful'] + end + if params[:latest_status].include? "unsuccessful" + 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'] + end + if params[:latest_status].include? "internal_review" + statuses << ['status:internal_review'] + end + if params[:latest_status].include? "other" + statuses << ['latest_status:gone_postal', 'latest_status:error_message', 'latest_status:requires_admin', 'latest_status:user_withdrawn'] + end + if params[:latest_status].include? "gone_postal" + statuses << ['latest_status:gone_postal'] + end + if !statuses.empty? + query = " (#{statuses.join(' OR ')})" + end + end + return query + end + + def get_date_range_from_params + query = "" + if param_exists(:request_date_after) && !param_exists(:request_date_before) + params[:request_date_before] = Time.now.strftime("%d/%m/%Y") + query += " #{params[:request_date_after]}..#{params[:request_date_before]}" + elsif !param_exists(:request_date_after) && param_exists(:request_date_before) + params[:request_date_after] = "01/01/2001" + end + if param_exists(:request_date_after) + query = " #{params[:request_date_after]}..#{params[:request_date_before]}" + end + return query + end + + def get_tags_from_params + query = "" + tags = [] + if param_exists(:tags) + params[:tags].split().each do |tag| + tags << "tag:#{tag}" + end + end + if !tags.empty? + query = " (#{tags.join(' OR ')})" + end + return query + end + + def make_query_from_params + query = params[:query] || "" if query.nil? + query += get_date_range_from_params + query += get_request_variety_from_params + query += get_status_from_params + query += get_tags_from_params + return query + end + + def country_from_ip + gaze = MySociety::Config.get('GAZE_URL', '') + 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 + end + country = default if country.empty? + return country end # URL generating functions are needed by all controllers (for redirects), diff --git a/app/controllers/general_controller.rb b/app/controllers/general_controller.rb index 4fa603aab..194a1cec0 100644 --- a/app/controllers/general_controller.rb +++ b/app/controllers/general_controller.rb @@ -45,20 +45,23 @@ class GeneralController < ApplicationController :joins => :translations) end end - @search_examples = MySociety::Config.get('FRONTPAGE_SEARCH_EXAMPLES', '').split(/\s*;\s*/) - if @search_examples.empty? - @search_examples = @popular_bodies.map { |body| body.name } - end # Get some successful requests # begin query = 'variety:response (status:successful OR status:partially_successful)' # query = 'variety:response' # XXX debug sortby = "described" - xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_title_collapse', 8) - @successful_request_events = xapian_object.results.map { |r| r[:model] } - @successful_request_events = @successful_request_events.sort_by { |e| e.described_at }.reverse + max_count = 5 + xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_title_collapse', max_count) + @request_events = xapian_object.results.map { |r| r[:model] } + @request_events = @request_events.sort_by { |e| e.described_at }.reverse + if @request_events.count < max_count + query = 'variety:sent' + xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_title_collapse', max_count-@request_events.count) + more_events = xapian_object.results.map { |r| r[:model] } + @request_events += more_events.sort_by { |e| e.described_at }.reverse + end rescue - @successful_request_events = [] + @request_events = [] end end end @@ -67,13 +70,13 @@ class GeneralController < ApplicationController def blog medium_cache @feed_autodetect = [] - feed_url = MySociety::Config.get('BLOG_FEED', '') - if not feed_url.empty? - content = open(feed_url).read + @feed_url = "#{MySociety::Config.get('BLOG_FEED', '')}?lang=#{self.locale_from_params()}" + if not @feed_url.empty? + content = open(@feed_url).read @data = XmlSimple.xml_in(content) @channel = @data['channel'][0] @blog_items = @channel['item'] - @feed_autodetect = [{:url => feed_url, :title => "#{site_name} blog"}] + @feed_autodetect = [{:url => @feed_url, :title => "#{site_name} blog"}] else @blog_items = [] end @@ -82,20 +85,34 @@ class GeneralController < ApplicationController # Just does a redirect from ?query= search to /query def search_redirect - @query = params[:query] + if params[:advanced].nil? + @query, _ = make_query_from_params + else + @query, _ = params[:query] + end @sortby = params[:sortby] - @bodies = params[:bodies] + path = request.path.split("/") + if path.size > 0 && (['newest', 'described', 'relevant'].include?(path[-1])) + @sort_postfix = path.pop + end + if path.size > 0 && (['bodies', 'requests', 'users', 'all'].include?(path[-1])) + @variety_postfix = path.pop + end + @variety_postfix = "bodies" if @variety_postfix.nil? && !params[:bodies].nil? + @variety_postfix = "requests" if @variety_postfix.nil? + if @variety_postfix != "users" + @common_query = get_tags_from_params + end + [:latest_status, :request_variety, :request_date_after, :request_date_before, :query, :tags].each do |x| + session[x] = params[x] + end if @query.nil? || @query.empty? @query = nil @page = 1 + @advanced = !params[:advanced].nil? render :action => "search" else - if (@bodies == '1') && (@sortby.nil? || @sortby.empty?) - @postfix = 'bodies' - else - @postfix = @sortby - end - redirect_to search_url(@query, @postfix) + redirect_to search_url(@query, @variety_postfix, @sort_postfix, params[:advanced]) end end @@ -103,23 +120,59 @@ class GeneralController < ApplicationController def search # XXX Why is this so complicated with arrays and stuff? Look at the route # in config/routes.rb for comments. + if !params[:commit].nil? + search_redirect + return + end + [:latest_status, :request_variety, :request_date_after, :request_date_before, :query, :tags].each do |x| + params[x] = session[x] if params[x].nil? + end combined = params[:combined] @sortby = nil - @bodies = false # searching from front page, largely for a public authority + @bodies = @requests = @users = true + if combined.size > 0 && (['advanced'].include?(combined[-1])) + combined.pop + @advanced = true + else + @advanced = false + end # XXX currently /described isn't linked to anywhere, just used in RSS and for /list/successful # This is because it's confusingly different from /newest - but still useful for power users. - if combined.size > 1 && (['newest', 'described', 'bodies', 'relevant'].include?(combined[-1])) - @postfix = combined[-1] - combined = combined[0..-2] - if @postfix == 'bodies' + if combined.size > 0 && (['newest', 'described', 'relevant'].include?(combined[-1])) + @sort_postfix = combined.pop + @sortby = @sort_postfix + end + if !params[:view].nil? + combined += [params[:view]] + end + if combined.size > 0 && (['bodies', 'requests', 'users', 'all'].include?(combined[-1])) + @variety_postfix = combined.pop + case @variety_postfix + when 'bodies' @bodies = true + @requests = false + @users = false + when 'requests' + @bodies = false + @requests = true + @users = false + when 'users' + @bodies = false + @requests = false + @users = true else - @sortby = @postfix + @variety_postfix = "all" end end @query = combined.join("/") - + if params[:query].nil? + params[:query] = @query + end + if @variety_postfix != "all" && @requests + @query, _ = make_query_from_params + end @inputted_sortby = @sortby + @common_query = get_tags_from_params if @sortby.nil? # Parse query, so can work out if it has prefix terms only - if so then it is a # structured query which should show newest first, rather than a free text search @@ -145,21 +198,41 @@ class GeneralController < ApplicationController if params[:requests_per_page] requests_per_page = params[:requests_per_page].to_i end - @xapian_requests = perform_search([InfoRequestEvent], @query, @sortby, 'request_collapse', requests_per_page) - @requests_per_page = @per_page - @xapian_bodies = perform_search([PublicBody], @query, @sortby, nil, 5) - @bodies_per_page = @per_page - @xapian_users = perform_search([User], @query, @sortby, nil, 5) - @users_per_page = @per_page - - @this_page_hits = @xapian_requests.results.size + @xapian_bodies.results.size + @xapian_users.results.size - @total_hits = @xapian_requests.matches_estimated + @xapian_bodies.matches_estimated + @xapian_users.matches_estimated + @this_page_hits = @total_hits = @xapian_requests_hits = @xapian_bodies_hits = @xapian_users_hits = 0 + if @requests + @xapian_requests = perform_search([InfoRequestEvent], @query, @sortby, 'request_collapse', requests_per_page) + @requests_per_page = @per_page + @this_page_hits += @xapian_requests.results.size + @xapian_requests_hits = @xapian_requests.results.size + @xapian_requests_total_hits = @xapian_requests.matches_estimated + @total_hits += @xapian_requests.matches_estimated + end + if @bodies + @xapian_bodies = perform_search([PublicBody], @query, @sortby, nil, 5) + @bodies_per_page = @per_page + @this_page_hits += @xapian_bodies.results.size + @xapian_bodies_hits = @xapian_bodies.results.size + @xapian_bodies_total_hits = @xapian_bodies.matches_estimated + @total_hits += @xapian_bodies.matches_estimated + end + if @users + @xapian_users = perform_search([User], @query, @sortby, nil, 5) + @users_per_page = @per_page + @this_page_hits += @xapian_users.results.size + @xapian_users_hits = @xapian_users.results.size + @xapian_users_total_hits = @xapian_users.matches_estimated + @total_hits += @xapian_users.matches_estimated + end # Spelling and highight words are same for all three queries - @spelling_correction = @xapian_requests.spelling_correction - @highlight_words = @xapian_requests.words_to_highlight + if !@xapian_requests.nil? + @highlight_words = @xapian_requests.words_to_highlight + if !(@xapian_requests.spelling_correction =~ /[a-z]+:/) + @spelling_correction = @xapian_requests.spelling_correction + end + end - @track_thing = TrackThing.create_track_for_search_query(@query) + @track_thing = TrackThing.create_track_for_search_query(@query, @variety_postfix) @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ] end diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index 05acf4868..251ab5efe 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -16,11 +16,10 @@ class PublicBodyController < ApplicationController redirect_to :url_name => MySociety::Format.simplify_url_part(params[:url_name], 'body'), :status => :moved_permanently return end - @locale = self.locale_from_params() PublicBody.with_locale(@locale) do @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name]) - raise "None found" if @public_body.nil? # XXX proper 404 + raise ActiveRecord::RecordNotFound.new("None found") if @public_body.nil? if @public_body.url_name.nil? redirect_to :back return @@ -39,11 +38,16 @@ class PublicBodyController < ApplicationController if !referrer.nil? && referrer.match(%r{^#{top_url}search/.*/bodies$}) @searched_to_send_request = true end + @view = params[:view] + params[:latest_status] = @view + query = make_query_from_params + query += " requested_from:#{@public_body.url_name}" # Use search query for this so can collapse and paginate easily # XXX really should just use SQL query here rather than Xapian. + sortby = "described" begin - @xapian_requests = perform_search([InfoRequestEvent], 'requested_from:' + @public_body.url_name, 'newest', 'request_collapse') + @xapian_requests = perform_search([InfoRequestEvent], query, sortby, 'request_collapse') if (@page > 1) @page_desc = " (page " + @page.to_s + ")" else @@ -65,8 +69,9 @@ class PublicBodyController < ApplicationController end def view_email - @public_bodies = PublicBody.find(:all, :conditions => [ "url_name = ?", params[:url_name] ]) - @public_body = @public_bodies[0] + @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name]) + raise ActiveRecord::RecordNotFound.new("None found") if @public_body.nil? + PublicBody.with_locale(self.locale_from_params()) do if params[:submitted_view_email] if verify_recaptcha @@ -83,39 +88,46 @@ class PublicBodyController < ApplicationController def list long_cache # XXX move some of these tag SQL queries into has_tag_string.rb + @query = "%#{params[:public_body_query].nil? ? "" : params[:public_body_query]}%" @tag = params[:tag] @locale = self.locale_from_params() - locale_condition = 'public_body_translations.locale = ?' - if @tag.nil? + + locale_condition = "(upper(public_body_translations.name) LIKE upper(?) + OR upper(public_body_translations.notes) LIKE upper (?)) + AND public_body_translations.locale = ? + AND public_bodies.id <> #{PublicBody.internal_admin_body.id}" + if @tag.nil? or @tag == "all" @tag = "all" - conditions = [locale_condition, @locale] + conditions = [locale_condition, @query, @query, @locale] elsif @tag == 'other' - category_list = PublicBodyCategories::CATEGORIES.map{|c| "'"+c+"'"}.join(",") + category_list = PublicBodyCategories::get().tags().map{|c| "'"+c+"'"}.join(",") conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id and has_tag_string_tags.model = \'PublicBody\' - and has_tag_string_tags.name in (' + category_list + ')) = 0', @locale] + and has_tag_string_tags.name in (' + category_list + ')) = 0', @query, @query, @locale] elsif @tag.size == 1 @tag.upcase! - conditions = [locale_condition + ' AND public_body_translations.first_letter = ?', @locale, @tag] + conditions = [locale_condition + ' AND public_body_translations.first_letter = ?', @query, @query, @locale, @tag] elsif @tag.include?(":") name, value = HasTagString::HasTagStringTag.split_tag_into_name_value(@tag) conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id and has_tag_string_tags.model = \'PublicBody\' - and has_tag_string_tags.name = ? and has_tag_string_tags.value = ?) > 0', @locale, name, value] + and has_tag_string_tags.name = ? and has_tag_string_tags.value = ?) > 0', @query, @query, @locale, name, value] else conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id and has_tag_string_tags.model = \'PublicBody\' - and has_tag_string_tags.name = ?) > 0', @locale, @tag] + and has_tag_string_tags.name = ?) > 0', @query, @query, @locale, @tag] end - if @tag.size == 1 + if @tag == "all" + @description = "" + elsif @tag.size == 1 @description = _("beginning with") + " '" + @tag + "'" else - @description = PublicBodyCategories::CATEGORIES_BY_TAG[@tag] + @description = PublicBodyCategories::get().by_tag()[@tag] if @description.nil? @description = @tag end end - PublicBody.with_locale(@locale) do + PublicBody.with_locale(@locale) do @public_bodies = PublicBody.paginate( :order => "public_body_translations.name", :page => params[:page], :per_page => 1000, # fit all councils on one page :conditions => conditions, @@ -168,5 +180,17 @@ class PublicBodyController < ApplicationController :filename => 'all-authorities.csv', :disposition =>'attachment', :encoding => 'utf8') end + + # Type ahead search + def search_typeahead + # Since acts_as_xapian doesn't support the Partial match flag, we work around it + # by making the last work a wildcard, which is quite the same + query = params[:q] + '*' + + query = query.split(' ').join(' OR ') # XXX: HACK for OR instead of default AND! + @xapian_requests = perform_search([PublicBody], query, 'relevant', nil, 5) + + render :partial => "public_body/search_ahead" + end end diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index c1a13273a..4b7884065 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -7,6 +7,8 @@ # $Id: request_controller.rb,v 1.192 2009-10-19 19:26:40 francis Exp $ require 'alaveteli_file_types' +require 'zip/zip' +require 'open-uri' class RequestController < ApplicationController before_filter :check_read_only, :only => [ :new, :show_response, :describe_state, :upload_response ] @@ -22,6 +24,26 @@ class RequestController < ApplicationController rescue MissingSourceFile, NameError end + def select_authority + # Check whether we force the user to sign in right at the start, or we allow her + # to start filling the request anonymously + if force_registration_on_new_request && !authenticated?( + :web => _("To send your FOI request"), + :email => _("Then you'll be allowed to send FOI requests."), + :email_subject => _("Confirm your email address") + ) + # do nothing - as "authenticated?" has done the redirect to signin page for us + return + 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) + end + medium_cache + end + def show medium_cache @locale = self.locale_from_params() @@ -37,7 +59,7 @@ class RequestController < ApplicationController # Look up by new style text names @info_request = InfoRequest.find_by_url_title(params[:url_title]) if @info_request.nil? - raise "Request not found" + raise ActiveRecord::RecordNotFound.new("Request not found") end set_last_request(@info_request) @@ -52,7 +74,6 @@ class RequestController < ApplicationController @status = @info_request.calculate_status @collapse_quotes = params[:unfold] ? false : true @update_status = params[:update_status] ? true : false - @is_owning_user = @info_request.is_owning_user?(authenticated_user) @old_unclassified = @info_request.is_old_unclassified? && !authenticated_user.nil? if @update_status @@ -66,7 +87,7 @@ class RequestController < ApplicationController @last_info_request_event_id = @info_request.last_event_id_needing_description @new_responses_count = @info_request.events_needing_description.select {|i| i.event_type == 'response'}.size -1 + # Sidebar stuff # ... requests that have similar imporant terms behavior_cache :tag => ['similar', @info_request.id] do @@ -86,7 +107,7 @@ class RequestController < ApplicationController # For send followup link at bottom @last_response = @info_request.get_last_response - + @is_owning_user = @info_request.is_owning_user?(authenticated_user) respond_to do |format| format.html { @has_json = true; render :template => 'request/show'} format.json { render :json => @info_request.json_for_api(true) } @@ -129,26 +150,10 @@ class RequestController < ApplicationController def list medium_cache @view = params[:view] - - if @view.nil? - redirect_to request_list_url(:view => 'successful') - return - end - - if @view == 'recent' - @title = _("Recently sent Freedom of Information requests") - query = "variety:sent"; - sortby = "newest" - @track_thing = TrackThing.create_track_for_all_new_requests - elsif @view == 'successful' - @title = _("Recently successful responses") - query = 'variety:response (status:successful OR status:partially_successful)' - sortby = "described" - @track_thing = TrackThing.create_track_for_all_successful_requests - else - raise "unknown request list view " + @view.to_s - end - + params[:latest_status] = @view + query = make_query_from_params + @title = _("View and search requests") + sortby = "newest" @page = get_search_page_from_params if !@page # used in cache case, as perform_search sets @page as side effect behavior_cache :tag => [@view, @page] do xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_collapse') @@ -157,7 +162,7 @@ class RequestController < ApplicationController end @title = @title + " (page " + @page.to_s + ")" if (@page > 1) - + @track_thing = TrackThing.create_track_for_search_query(query) @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ] # Don't let robots go more than 20 pages in @@ -203,7 +208,7 @@ class RequestController < ApplicationController params[:info_request][:public_body_id] = params[:url_name] else public_body = PublicBody.find_by_url_name_with_historic(params[:url_name]) - raise "None found" if public_body.nil? # XXX proper 404 + raise ActiveRecord::RecordNotFound.new("None found") if public_body.nil? # XXX proper 404 params[:info_request][:public_body_id] = public_body.id end elsif params[:public_body_id] @@ -309,10 +314,11 @@ class RequestController < ApplicationController # XXX send_message needs the database id, so we send after saving, which isn't ideal if the request broke here. @outgoing_message.send_message flash[:notice] = _("<p>Your {{law_used_full}} request has been <strong>sent on its way</strong>!</p> - <p><strong>We will email you</strong> when there is a response, or after 20 working days if the authority still hasn't + <p><strong>We will email you</strong> when there is a response, or after {{late_number_of_days}} working days if the authority still hasn't replied by then.</p> <p>If you write about this request (for example in a forum or a blog) please link to this page, and add an - annotation below telling people about your writing.</p>",:law_used_full=>@info_request.law_used_full) + annotation below telling people about your writing.</p>",:law_used_full=>@info_request.law_used_full, + :late_number_of_days => MySociety::Config.get('REPLY_LATE_AFTER_DAYS', 20)) redirect_to show_new_request_path(:url_title => @info_request.url_title) end @@ -686,10 +692,10 @@ class RequestController < ApplicationController raise "internal error, pre-auth filter should have caught this" if !@info_request.user_can_view?(authenticated_user) @attachment = IncomingMessage.get_attachment_by_url_part_number(@incoming_message.get_attachments_for_display, @part_number) - raise "attachment not found part number " + @part_number.to_s + " incoming_message " + @incoming_message.id.to_s if @attachment.nil? + raise ActiveRecord::RecordNotFound.new("attachment not found part number " + @part_number.to_s + " incoming_message " + @incoming_message.id.to_s) if @attachment.nil? # check filename in URL matches that in database (use a censor rule if you want to change a filename) - raise "please use same filename as original file has, display: '" + @attachment.display_filename + "' old_display: '" + @attachment.old_display_filename + "' original: '" + @original_filename + "'" if @attachment.display_filename != @original_filename && @attachment.old_display_filename != @original_filename + raise ActiveRecord::RecordNotFound.new("please use same filename as original file has, display: '" + @attachment.display_filename + "' old_display: '" + @attachment.old_display_filename + "' original: '" + @original_filename + "'") if @attachment.display_filename != @original_filename && @attachment.old_display_filename != @original_filename @attachment_url = get_attachment_url(:id => @incoming_message.info_request_id, :incoming_message_id => @incoming_message.id, :part => @part_number, @@ -743,5 +749,79 @@ class RequestController < ApplicationController return end end + + # Type ahead search + def search_typeahead + # Since acts_as_xapian doesn't support the Partial match flag, we work around it + # by making the last work a wildcard, which is quite the same + query = params[:q] + '*' + + query = query.split(' ').join(' OR ') # XXX: HACK for OR instead of default AND! + @xapian_requests = perform_search([InfoRequestEvent], query, 'relevant', 'request_collapse', 5) + + render :partial => "request/search_ahead.rhtml" + end + + def download_entire_request + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + info_request = InfoRequest.find_by_url_title(params[:url_title]) + if info_request.nil? + raise ActiveRecord::RecordNotFound.new("Request not found") + end + if authenticated?( + :web => _("To download the zip file"), + :email => _("Then you can download a zip file of {{info_request_title}}.",:info_request_title=>info_request.title), + :email_subject => _("Log in to download a zip file of {{info_request_title}}",:info_request_title=>info_request.title) + ) + updated = Digest::SHA1.hexdigest(info_request.get_last_event.created_at.to_s + info_request.updated_at.to_s) + @url_path = "/download/#{updated[0..1]}/#{updated}/#{params[:url_title]}.zip" + file_path = File.join(File.dirname(__FILE__), '../../cache/zips', @url_path) + if !File.exists?(file_path) + FileUtils.mkdir_p(File.dirname(file_path)) + Zip::ZipFile.open(file_path, Zip::ZipFile::CREATE) { |zipfile| + convert_command = MySociety::Config.get("HTML_TO_PDF_COMMAND") + done = false + if File.exists?(convert_command) + domain = MySociety::Config.get("DOMAIN") + url = "http://#{domain}#{request_url(info_request)}?print_stylesheet=1" + tempfile = Tempfile.new('foihtml2pdf') + output = AlaveteliExternalCommand.run(convert_command, url, tempfile.path) + if !output.nil? + zipfile.get_output_stream("correspondence.pdf") { |f| + f.puts(File.open(tempfile.path).read) + } + done = true + else + logger.error("Could not convert info request #{info_request.id} to PDF with command '#{convert_command} #{url} #{tempfile.path}'") + end + tempfile.close + else + logger.warn("No HTML -> PDF converter found at #{convert_command}") + end + if !done + @info_request = info_request + @info_request_events = info_request.info_request_events + template = File.read(File.join(File.dirname(__FILE__), "..", "views", "request", "simple_correspondence.rhtml")) + output = ERB.new(template).result(binding) + zipfile.get_output_stream("correspondence.txt") { |f| + f.puts(output) + } + end + for message in info_request.incoming_messages + attachments = message.get_attachments_for_display + for attachment in attachments + zipfile.get_output_stream(attachment.display_filename) { |f| + f.puts(attachment.body) + } + end + end + } + File.chmod(0644, file_path) + end + redirect_to @url_path + end + end + end end diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb new file mode 100644 index 000000000..6fb20336e --- /dev/null +++ b/app/controllers/services_controller.rb @@ -0,0 +1,32 @@ +# controllers/application.rb: +# Parent class of all controllers in FOI site. Filters added to this controller +# apply to all controllers in the application. Likewise, all the methods added +# will be available for all controllers. +# +# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. +# Email: francis@mysociety.org; WWW: http://www.mysociety.org/ +# +# $Id: application.rb,v 1.59 2009-09-17 13:01:56 francis Exp $ + +require 'open-uri' + +class ServicesController < ApplicationController + def other_country_message + text = "" + iso_country_code = MySociety::Config.get('ISO_COUNTRY_CODE').downcase + if country_from_ip.downcase != iso_country_code + found_country = WorldFOIWebsites.by_code(country_from_ip) + found_country_name = !found_country.nil? && found_country[:country_name] + if found_country_name + text = _("Hello! You can make Freedom of Information requests within {{country_name}} at {{link_to_website}}", :country_name => found_country_name, :link_to_website => "<a href=\"#{found_country[:url]}\">#{found_country[:name]}</a>") + else + current_country = WorldFOIWebsites.by_code(iso_country_code)[:country_name] + text = _("Hello! We have an <a href=\"/help/alaveteli?country_name=#{CGI.escape(current_country)}\">important message</a> for visitors outside {{country_name}}", :country_name => current_country) + end + end + if !text.empty? + text += ' <span class="close-button">X</span>' + end + render :text => text, :content_type => "text/plain" # XXX workaround the HTML validation in test suite + end +end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index d3c42c7f1..96dbfba74 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -8,6 +8,8 @@ class UserController < ApplicationController + layout :select_layout + protect_from_forgery :only => [ :contact, :set_profile_photo, :signchangeemail, @@ -24,7 +26,7 @@ class UserController < ApplicationController @display_user = User.find(:first, :conditions => [ "url_name = ? and email_confirmed = ?", params[:url_name], true ]) if not @display_user - raise "user not found, url_name=" + params[:url_name] + raise ActiveRecord::RecordNotFound.new("user not found, url_name=" + params[:url_name]) end @same_name_users = User.find(:all, :conditions => [ "name ilike ? and email_confirmed = ? and id <> ?", @display_user.name, true, @display_user.id ], :order => "created_at") @@ -33,9 +35,16 @@ class UserController < ApplicationController # Use search query for this so can collapse and paginate easily # XXX really should just use SQL query here rather than Xapian. begin - @xapian_requests = perform_search([InfoRequestEvent], 'requested_by:' + @display_user.url_name, 'newest', 'request_collapse') - @xapian_comments = perform_search([InfoRequestEvent], 'commented_by:' + @display_user.url_name, 'newest', nil) - + requests_query = 'requested_by:' + @display_user.url_name + comments_query = 'commented_by:' + @display_user.url_name + if !params[:user_query].nil? + requests_query += " " + params[:user_query] + comments_query += " " + params[:user_query] + @match_phrase = _("{{search_results}} matching '{{query}}'", :search_results => "", :query => params[:user_query]) + end + @xapian_requests = perform_search([InfoRequestEvent], requests_query, 'newest', 'request_collapse') + @xapian_comments = perform_search([InfoRequestEvent], comments_query, 'newest', nil) + if (@page > 1) @page_desc = " (page " + @page.to_s + ")" else @@ -71,7 +80,7 @@ class UserController < ApplicationController # Login form def signin work_out_post_redirect - + @request_from_foreign_country = country_from_ip != MySociety::Config.get('ISO_COUNTRY_CODE', 'GB') # make sure we have cookies if session.instance_variable_get(:@dbman) if not session.instance_variable_get(:@dbman).instance_variable_get(:@original) @@ -106,7 +115,12 @@ class UserController < ApplicationController session[:user_id] = @user_signin.id session[:user_circumstance] = nil session[:remember_me] = params[:remember_me] ? true : false - do_post_redirect @post_redirect + + if is_modal_dialog + render :action => 'signin_successful' + else + do_post_redirect @post_redirect + end else send_confirmation_mail @user_signin end @@ -118,10 +132,15 @@ class UserController < ApplicationController # Create new account form def signup work_out_post_redirect - + @request_from_foreign_country = country_from_ip != MySociety::Config.get('ISO_COUNTRY_CODE', 'GB') # Make the user and try to save it @user_signup = User.new(params[:user_signup]) - if !@user_signup.valid? + error = false + if @request_from_foreign_country && !verify_recaptcha + flash.now[:error] = _("There was an error with the words you entered, please try again.") + error = true + end + if error || !@user_signup.valid? # Show the form render :action => 'sign' else @@ -133,7 +152,6 @@ class UserController < ApplicationController # New unconfirmed user @user_signup.email_confirmed = false @user_signup.save! - send_confirmation_mail @user_signup return end @@ -454,7 +472,7 @@ class UserController < ApplicationController def get_profile_photo @display_user = User.find(:first, :conditions => [ "url_name = ? and email_confirmed = ?", params[:url_name], true ]) if !@display_user - raise "user not found, url_name=" + params[:url_name] + raise ActiveRecord::RecordNotFound.new("user not found, url_name=" + params[:url_name]) end if !@display_user.profile_photo raise "user has no profile photo, url_name=" + params[:url_name] @@ -500,6 +518,15 @@ class UserController < ApplicationController private + def is_modal_dialog + (params[:modal].to_i != 0) + end + + # when logging in through a modal iframe, don't display chrome around the content + def select_layout + is_modal_dialog ? 'no_chrome' : 'default' + end + # Decide where we are going to redirect back to after signin/signup, and record that def work_out_post_redirect # Redirect to front page later if nothing else specified |