diff options
Diffstat (limited to 'app')
38 files changed, 528 insertions, 788 deletions
diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index ac12e97b2..c41d05c8d 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -14,7 +14,7 @@ class AdminPublicBodyController < AdminController def _lookup_query_internal @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do @query = params[:query] if @query == "" @query = nil @@ -75,7 +75,7 @@ class AdminPublicBodyController < AdminController def show @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do @public_body = PublicBody.find(params[:id]) render end @@ -87,7 +87,7 @@ class AdminPublicBodyController < AdminController end def create - PublicBody.with_locale(I18n.default_locale) do + I18n.with_locale(I18n.default_locale) do params[:public_body][:last_edit_editor] = admin_current_user() @public_body = PublicBody.new(params[:public_body]) if @public_body.save @@ -106,7 +106,7 @@ class AdminPublicBodyController < AdminController end def update - PublicBody.with_locale(I18n.default_locale) do + I18n.with_locale(I18n.default_locale) do params[:public_body][:last_edit_editor] = admin_current_user() @public_body = PublicBody.find(params[:id]) if @public_body.update_attributes(params[:public_body]) @@ -120,7 +120,7 @@ class AdminPublicBodyController < AdminController def destroy @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do public_body = PublicBody.find(params[:id]) if public_body.info_requests.size > 0 diff --git a/app/controllers/admin_request_controller.rb b/app/controllers/admin_request_controller.rb index 1de63be59..c7c8d4972 100644 --- a/app/controllers/admin_request_controller.rb +++ b/app/controllers/admin_request_controller.rb @@ -277,7 +277,7 @@ class AdminRequestController < AdminController if params[:incoming_message_id] incoming_message = IncomingMessage.find(params[:incoming_message_id]) - email = incoming_message.from_address + email = incoming_message.from_email name = incoming_message.safe_mail_from || info_request.public_body.name else email = info_request.public_body.request_email diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index aa5e85db3..15fb4f5f9 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -1,30 +1,30 @@ class ApiController < ApplicationController before_filter :check_api_key - + def show_request @request = InfoRequest.find(params[:id]) raise PermissionDenied if @request.public_body_id != @public_body.id - + @request_data = { :id => @request.id, :url => make_url("request", @request.url_title), :title => @request.title, - + :created_at => @request.created_at, :updated_at => @request.updated_at, - + :status => @request.calculate_status, - + :public_body_url => make_url("body", @request.public_body.url_name), :requestor_url => make_url("user", @request.user.url_name), :request_email => @request.incoming_email, - + :request_text => @request.last_event_forming_initial_request.outgoing_message.body, } - + render :json => @request_data end - + def create_request json = ActiveSupport::JSON.decode(params[:request_json]) request = InfoRequest.new( @@ -34,7 +34,7 @@ class ApiController < ApplicationController :external_user_name => json["external_user_name"], :external_url => json["external_url"] ) - + outgoing_message = OutgoingMessage.new( :status => 'ready', :message_type => 'initial_request', @@ -44,7 +44,7 @@ class ApiController < ApplicationController :info_request => request ) request.outgoing_messages << outgoing_message - + # Return an error if the request is invalid # (Can this ever happen?) if !request.valid? @@ -53,7 +53,7 @@ class ApiController < ApplicationController } return end - + # Save the request, and add the corresponding InfoRequestEvent request.save! request.log_event("sent", @@ -62,69 +62,69 @@ class ApiController < ApplicationController :outgoing_message_id => outgoing_message.id, :smtp_message_id => nil ) - + # Return the URL and ID number. render :json => { 'url' => make_url("request", request.url_title), 'id' => request.id } - + end - + def add_correspondence request = InfoRequest.find_by_id(params[:id]) if request.nil? render :json => { "errors" => ["Could not find request #{params[:id]}"] }, :status => 404 return end - + json = ActiveSupport::JSON.decode(params[:correspondence_json]) attachments = params[:attachments] - + direction = json["direction"] body = json["body"] sent_at_str = json["sent_at"] - + errors = [] - + if !request.is_external? render :json => { "errors" => ["Request #{params[:id]} cannot be updated using the API"] }, :status => 500 return end - + if request.public_body_id != @public_body.id render :json => { "errors" => ["You do not own request #{params[:id]}"] }, :status => 500 return end - + if !["request", "response"].include?(direction) errors << "The direction parameter must be 'request' or 'response'" end - + if body.nil? errors << "The 'body' is missing" elsif body.empty? errors << "The 'body' is empty" end - + begin sent_at = Time.iso8601(sent_at_str) rescue ArgumentError errors << "Failed to parse 'sent_at' field as ISO8601 time: #{sent_at_str}" end - + if direction == "request" && !attachments.nil? errors << "You cannot attach files to messages in the 'request' direction" end - + if !errors.empty? render :json => { "errors" => errors }, :status => 500 return end - + if direction == "request" # In the 'request' direction, i.e. what we (Alaveteli) regard as outgoing - + outgoing_message = OutgoingMessage.new( :info_request => request, :status => 'ready', @@ -154,19 +154,19 @@ class ApiController < ApplicationController :filename => filename ) end - + mail = RequestMailer.create_external_response(request, body, sent_at, attachment_hashes) request.receive(mail, mail.encoded, true) end render :json => { 'url' => make_url("request", request.url_title), - } + } end - + def body_request_events feed_type = params[:feed_type] raise PermissionDenied.new("#{@public_body.id} != #{params[:id]}") if @public_body.id != params[:id].to_i - + since_date_str = params[:since_date] if since_date_str.nil? @events = InfoRequestEvent.find_by_sql([ @@ -213,7 +213,7 @@ class ApiController < ApplicationController @event_data = [] @events.each do |event| break if event.id == @since_event_id - + request = event.info_request this_event = { :request_id => request.id, @@ -224,13 +224,13 @@ class ApiController < ApplicationController :request_email => request.incoming_email, :title => request.title, :body => event.outgoing_message.body, - + :user_name => request.user_name, } if request.user this_event[:user_url] = main_url(user_url(request.user)) end - + @event_data.push(this_event) end render :json => @event_data @@ -238,14 +238,14 @@ class ApiController < ApplicationController raise ActiveRecord::RecordNotFound.new("Unrecognised feed type: #{feed_type}") end end - + protected def check_api_key - raise "Missing required parameter 'k'" if params[:k].nil? + raise PermissionDenied.new("Missing required parameter 'k'") if params[:k].nil? @public_body = PublicBody.find_by_api_key(params[:k].gsub(' ', '+')) raise PermissionDenied if @public_body.nil? end - + private def make_url(*args) "http://" + Configuration::domain + "/" + args.join("/") diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f9649c868..3206df1d2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,9 +27,6 @@ class ApplicationController < ActionController::Base before_filter :set_vary_header before_filter :set_popup_banner - # scrub sensitive parameters from the logs - filter_parameter_logging :password - def set_vary_header response.headers['Vary'] = 'Cookie' end @@ -54,10 +51,15 @@ class ApplicationController < ActionController::Base end def set_gettext_locale + if Configuration::include_default_locale_in_urls == false + params_locale = params[:locale] ? params[:locale] : I18n.default_locale + else + params_locale = params[:locale] + end if Configuration::use_default_browser_language - requested_locale = params[:locale] || session[:locale] || cookies[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'] || I18n.default_locale + requested_locale = params_locale || session[:locale] || cookies[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'] || I18n.default_locale else - requested_locale = params[:locale] || session[:locale] || cookies[:locale] || I18n.default_locale + 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) @@ -69,9 +71,6 @@ class ApplicationController < ActionController::Base end end - # scrub sensitive parameters from the logs - filter_parameter_logging :password - helper_method :locale_from_params # Help work out which request causes RAM spike. @@ -149,19 +148,20 @@ class ApplicationController < ActionController::Base render :template => "general/exception_caught.rhtml", :status => @status end - # For development sites. - alias original_rescue_action_locally rescue_action_locally - def rescue_action_locally(exception) - # Make sure expiry time for session is set (before_filters are - # otherwise missed by this override) - session_remember_me + # FIXME: This was disabled during the Rails 3 upgrade as this is now handled by Rack + # # For development sites. + # alias original_rescue_action_locally rescue_action_locally + # def rescue_action_locally(exception) + # # Make sure expiry time for session is set (before_filters are + # # otherwise missed by this override) + # session_remember_me - # Make sure the locale is set correctly too - set_gettext_locale + # # Make sure the locale is set correctly too + # set_gettext_locale - # Display default, detailed error for developers - original_rescue_action_locally(exception) - end + # # Display default, detailed error for developers + # original_rescue_action_locally(exception) + # end def local_request? false @@ -240,7 +240,7 @@ class ApplicationController < ActionController::Base # Check the user is logged in def authenticated?(reason_params) unless session[:user_id] - post_redirect = PostRedirect.new(:uri => request.request_uri, :post_params => params, + post_redirect = PostRedirect.new(:uri => request.fullpath, :post_params => params, :reason_params => reason_params) post_redirect.save! # 'modal' controls whether the sign-in form will be displayed in the typical full-blown diff --git a/app/controllers/general_controller.rb b/app/controllers/general_controller.rb index 3ba636e29..faf34aa04 100644 --- a/app/controllers/general_controller.rb +++ b/app/controllers/general_controller.rb @@ -19,53 +19,51 @@ class GeneralController < ApplicationController # New, improved front page! def frontpage medium_cache - behavior_cache :tag => [session[:user_id], request.url] do - # get some example searches and public bodies to display - # either from config, or based on a (slow!) query if not set - body_short_names = Configuration::frontpage_publicbody_examples.split(/\s*;\s*/).map{|s| "'%s'" % s.gsub(/'/, "''") }.join(", ") - @locale = self.locale_from_params() - locale_condition = 'public_body_translations.locale = ?' - conditions = [locale_condition, @locale] - PublicBody.with_locale(@locale) do - if body_short_names.empty? - # This is too slow - @popular_bodies = PublicBody.visible.find(:all, - :order => "info_requests_count desc", - :limit => 32, - :conditions => conditions, - :joins => :translations - ) - else - conditions[0] += " and public_bodies.url_name in (" + body_short_names + ")" - @popular_bodies = PublicBody.find(:all, - :conditions => conditions, - :joins => :translations) - end + # get some example searches and public bodies to display + # either from config, or based on a (slow!) query if not set + body_short_names = Configuration::frontpage_publicbody_examples.split(/\s*;\s*/).map{|s| "'%s'" % s.gsub(/'/, "''") }.join(", ") + @locale = self.locale_from_params() + locale_condition = 'public_body_translations.locale = ?' + conditions = [locale_condition, @locale] + I18n.with_locale(@locale) do + if body_short_names.empty? + # This is too slow + @popular_bodies = PublicBody.visible.find(:all, + :order => "info_requests_count desc", + :limit => 32, + :conditions => conditions, + :joins => :translations + ) + else + conditions[0] += " and public_bodies.url_name in (" + body_short_names + ")" + @popular_bodies = PublicBody.find(:all, + :conditions => conditions, + :joins => :translations) end - # Get some successful requests - begin - query = 'variety:response (status:successful OR status:partially_successful)' - sortby = "newest" - max_count = 5 - xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_title_collapse', max_count) - @request_events = xapian_object.results.map { |r| r[:model] } - - # If there are not yet enough successful requests, fill out the list with - # other requests - if @request_events.count < max_count - @request_events_all_successful = false - 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 - # Overall we still want the list sorted with the newest first - @request_events.sort!{|e1,e2| e2.created_at <=> e1.created_at} - else - @request_events_all_successful = true - end - rescue - @request_events = [] + end + # Get some successful requests + begin + query = 'variety:response (status:successful OR status:partially_successful)' + sortby = "newest" + max_count = 5 + xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_title_collapse', max_count) + @request_events = xapian_object.results.map { |r| r[:model] } + + # If there are not yet enough successful requests, fill out the list with + # other requests + if @request_events.count < max_count + @request_events_all_successful = false + 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 + # Overall we still want the list sorted with the newest first + @request_events.sort!{|e1,e2| e2.created_at <=> e1.created_at} + else + @request_events_all_successful = true end + rescue + @request_events = [] end end diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index 8a4a65820..5265706bf 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -16,7 +16,7 @@ class PublicBodyController < ApplicationController return end @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name]) raise ActiveRecord::RecordNotFound.new("None found") if @public_body.nil? if @public_body.url_name.nil? @@ -71,7 +71,7 @@ class PublicBodyController < ApplicationController @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 + I18n.with_locale(self.locale_from_params()) do if params[:submitted_view_email] if verify_recaptcha flash.discard(:error) @@ -129,7 +129,7 @@ class PublicBodyController < ApplicationController @description = _("in the category ‘{{category_name}}’", :category_name=>category_name) end end - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do @public_bodies = PublicBody.paginate( :order => "public_body_translations.name", :page => params[:page], :per_page => 100, :conditions => conditions, diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index e82491bbe..17d2d9428 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -52,7 +52,7 @@ class RequestController < ApplicationController medium_cache end @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do # Look up by old style numeric identifiers if params[:url_title].match(/^[0-9]+$/) @@ -99,15 +99,13 @@ class RequestController < ApplicationController # Sidebar stuff # ... requests that have similar imporant terms - behavior_cache :tag => ['similar', @info_request.id] do - begin - limit = 10 - @xapian_similar = ::ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events, - :limit => limit, :collapse_by_prefix => 'request_collapse') - @xapian_similar_more = (@xapian_similar.matches_estimated > limit) - rescue - @xapian_similar = nil - end + begin + limit = 10 + @xapian_similar = ::ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events, + :limit => limit, :collapse_by_prefix => 'request_collapse') + @xapian_similar_more = (@xapian_similar.matches_estimated > limit) + rescue + @xapian_similar = nil end # Track corresponding to this page @@ -173,13 +171,10 @@ class RequestController < ApplicationController query = make_query_from_params @title = _("View and search requests") sortby = "newest" - @cache_tag = Digest::MD5.hexdigest(query + @page.to_s + I18n.locale.to_s) - behavior_cache :tag => [@cache_tag] do - xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_collapse') - @list_results = xapian_object.results.map { |r| r[:model] } - @matches_estimated = xapian_object.matches_estimated - @show_no_more_than = (@matches_estimated > MAX_RESULTS) ? MAX_RESULTS : @matches_estimated - end + xapian_object = perform_search([InfoRequestEvent], query, sortby, 'request_collapse') + @list_results = xapian_object.results.map { |r| r[:model] } + @matches_estimated = xapian_object.matches_estimated + @show_no_more_than = (@matches_estimated > MAX_RESULTS) ? MAX_RESULTS : @matches_estimated @title = @title + " (page " + @page.to_s + ")" if (@page > 1) @track_thing = TrackThing.create_track_for_search_query(query) @@ -804,7 +799,7 @@ class RequestController < ApplicationController # FOI officers can upload a response def upload_response @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do @info_request = InfoRequest.find_by_url_title!(params[:url_title]) @reason_params = { @@ -861,7 +856,7 @@ class RequestController < ApplicationController def download_entire_request @locale = self.locale_from_params() - PublicBody.with_locale(@locale) do + I18n.with_locale(@locale) do info_request = InfoRequest.find_by_url_title!(params[:url_title]) if authenticated?( :web => _("To download the zip file"), diff --git a/app/models/application_mailer.rb b/app/models/application_mailer.rb index cdb279c3c..859e8a0e2 100644 --- a/app/models/application_mailer.rb +++ b/app/models/application_mailer.rb @@ -67,7 +67,8 @@ class ApplicationMailer < ActionMailer::Base return nil end - if ActionMailer::VERSION::MAJOR == 2 + # FIXME: This check was disabled temporarily during the Rails 3 upgrade + #if ActionMailer::VERSION::MAJOR == 2 # This method is a customised version of ActionMailer::Base.create! # modified to allow templates to be selected correctly for multipart @@ -142,9 +143,9 @@ class ApplicationMailer < ActionMailer::Base # build the mail object itself @mail = create_mail end - else - raise "ApplicationMailer.create! is obsolete - find another way to ensure that themes can override mail templates for multipart mails" - end + # else + # raise "ApplicationMailer.create! is obsolete - find another way to ensure that themes can override mail templates for multipart mails" + # end end diff --git a/app/models/censor_rule.rb b/app/models/censor_rule.rb index f40ab6fbb..ec66074b7 100644 --- a/app/models/censor_rule.rb +++ b/app/models/censor_rule.rb @@ -33,13 +33,15 @@ class CensorRule < ActiveRecord::Base validate :require_valid_regexp, :if => proc{ |rule| rule.regexp? == true } validates_presence_of :text - named_scope :global, {:conditions => {:info_request_id => nil, - :user_id => nil, - :public_body_id => nil}} + scope :global, {:conditions => {:info_request_id => nil, + :user_id => nil, + :public_body_id => nil}} def require_user_request_or_public_body if self.info_request.nil? && self.user.nil? && self.public_body.nil? - errors.add("Censor must apply to an info request a user or a body; ") + [:info_request, :user, :public_body].each do |a| + errors.add(a, "Rule must apply to an info request, a user or a body") + end end end diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb index a40898aef..2f8a9ab04 100644 --- a/app/models/foi_attachment.rb +++ b/app/models/foi_attachment.rb @@ -38,7 +38,7 @@ class FoiAttachment < ActiveRecord::Base BODY_MAX_DELAY = 5 def directory - rails_env = ENV['RAILS_ENV'] + rails_env = Rails.env if rails_env.nil? || rails_env.empty? raise "$RAILS_ENV is not set" end @@ -67,9 +67,22 @@ class FoiAttachment < ActiveRecord::Base file.write d } update_display_size! + encode_cached_body! @cached_body = d end + # If the original mail part had a charset, it's some kind of string, so assume that + # it should be handled as a string in the stated charset, not a bytearray, and then + # convert it our default encoding. For ruby 1.8 this is a noop. + def encode_cached_body! + if RUBY_VERSION.to_f >= 1.9 + if charset + @cached_body.force_encoding(charset) + @cached_body = @cached_body.encode(Encoding.default_internal, charset) + end + end + end + def body if @cached_body.nil? tries = 0 @@ -90,6 +103,7 @@ class FoiAttachment < ActiveRecord::Base self.incoming_message.parse_raw_email!(force) retry end + encode_cached_body! end return @cached_body end @@ -310,31 +324,41 @@ class FoiAttachment < ActiveRecord::Base # the extractions will also produce image files, which go in the # current directory, so change to the directory the function caller # wants everything in - Dir.chdir(dir) do - tempfile = Tempfile.new('foiextract', '.') - tempfile.print self.body - tempfile.flush - - html = nil - if self.content_type == 'application/pdf' - # We set a timeout here, because pdftohtml can spiral out of control - # on some PDF files and we don’t want to crash the whole server. - html = AlaveteliExternalCommand.run("pdftohtml", "-nodrm", "-zoom", "1.0", "-stdout", "-enc", "UTF-8", "-noframes", tempfile.path, :timeout => 30) - elsif self.content_type == 'application/rtf' - html = AlaveteliExternalCommand.run("unrtf", "--html", tempfile.path, :timeout => 120) - end - - if html.nil? - if self.has_google_docs_viewer? - html = '' # force error and using Google docs viewer + + html = nil + if ['application/pdf', 'application/rtf'].include?(self.content_type) + text = self.body + Dir.chdir(dir) do + if RUBY_VERSION.to_f >= 1.9 + tempfile = Tempfile.new('foiextract', '.', :encoding => text.encoding) else - raise "No HTML conversion available for type " + self.content_type + tempfile = Tempfile.new('foiextract', '.') end - end + tempfile.print text + tempfile.flush + - tempfile.close - tempfile.delete + if self.content_type == 'application/pdf' + # We set a timeout here, because pdftohtml can spiral out of control + # on some PDF files and we don't want to crash the whole server. + html = AlaveteliExternalCommand.run("pdftohtml", "-nodrm", "-zoom", "1.0", "-stdout", "-enc", "UTF-8", "-noframes", tempfile.path, :timeout => 30) + elsif self.content_type == 'application/rtf' + html = AlaveteliExternalCommand.run("unrtf", "--html", tempfile.path, :timeout => 120) + end + + tempfile.close + tempfile.delete + end end + if html.nil? + if self.has_google_docs_viewer? + html = '' # force error and using Google docs viewer + else + raise "No HTML conversion available for type " + self.content_type + end + end + + # We need to look at: # a) Any error code diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb index 98124b28e..ee8b92f11 100644 --- a/app/models/incoming_message.rb +++ b/app/models/incoming_message.rb @@ -70,41 +70,27 @@ class IncomingMessage < ActiveRecord::Base @mail end - def from_address - self.mail.from_addrs[0].address - end - def empty_from_field? self.mail.from_addrs.nil? || self.mail.from_addrs.size == 0 end def from_email - self.mail.from_addrs[0].spec + MailHandler.get_from_address(self.mail) end def addresses - ((self.mail.to || []) + - (self.mail.cc || []) + - (self.mail.envelope_to || [])).uniq + MailHandler.get_all_addresses(self.mail) end def message_id self.mail.message_id end - # Returns the name of the person the incoming message is from, or nil if - # there isn't one or if there is only an email address. XXX can probably - # remove from_name_if_present (which is a monkey patch) by just calling - # .from_addrs[0].name here instead? - # Return false if for some reason this is a message that we shouldn't let them reply to def _calculate_valid_to_reply_to # check validity of email - if empty_from_field? - return false - end email = self.from_email - if !MySociety::Validate.is_valid_email(email) + if email.nil? || !MySociety::Validate.is_valid_email(email) return false end @@ -114,13 +100,13 @@ class IncomingMessage < ActiveRecord::Base prefix = email prefix =~ /^(.*)@/ prefix = $1 - if !prefix.nil? && prefix.downcase.match(/^(postmaster|mailer-daemon|auto_reply|donotreply|no.reply)$/) + if !prefix.nil? && prefix.downcase.match(/^(postmaster|mailer-daemon|auto_reply|do.?not.?reply|no.reply)$/) return false end - if !self.mail['return-path'].nil? && self.mail['return-path'].addr == "<>" + if MailHandler.empty_return_path?(self.mail) return false end - if !self.mail['auto-submitted'].nil? + if !MailHandler.get_auto_submitted(self.mail).nil? return false end return true @@ -138,13 +124,10 @@ class IncomingMessage < ActiveRecord::Base 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 = MailHandler.get_from_name(self.mail) + if self.from_email self.mail_from_domain = PublicBody.extract_domain_from_email(self.from_email) - rescue NoMethodError + else self.mail_from_domain = "" end self.valid_to_reply_to = self._calculate_valid_to_reply_to @@ -190,54 +173,8 @@ class IncomingMessage < ActiveRecord::Base super end - # Number the attachments in depth first tree order, for use in URLs. - # XXX This fills in part.rfc822_attachment and part.url_part_number within - # all the parts of the email (see monkeypatches in lib/mail_handler/tmail_extensions and - # lib/mail_handler/mail_extensions for how these attributes are added). ensure_parts_counted - # must be called before using the attributes. - def ensure_parts_counted - @count_parts_count = 0 - _count_parts_recursive(self.mail) - # we carry on using these numeric ids for attachments uudecoded from within text parts - @count_first_uudecode_count = @count_parts_count - end - def _count_parts_recursive(part) - if part.multipart? - part.parts.each do |p| - _count_parts_recursive(p) - end - else - part_filename = MailHandler.get_part_file_name(part) - begin - if part.content_type == 'message/rfc822' - # An email attached as text - # e.g. http://www.whatdotheyknow.com/request/64/response/102 - part.rfc822_attachment = MailHandler.mail_from_raw_email(part.body, decode=false) - elsif part.content_type == 'application/vnd.ms-outlook' || part_filename && AlaveteliFileTypes.filename_to_mimetype(part_filename) == 'application/vnd.ms-outlook' - # An email attached as an Outlook file - # e.g. http://www.whatdotheyknow.com/request/chinese_names_for_british_politi - msg = Mapi::Msg.open(StringIO.new(part.body)) - part.rfc822_attachment = MailHandler.mail_from_raw_email(msg.to_mime.to_s, decode=false) - elsif part.content_type == 'application/ms-tnef' - # A set of attachments in a TNEF file - part.rfc822_attachment = MailHandler.mail_from_tnef(part.body) - end - rescue - # If attached mail doesn't parse, treat it as text part - part.rfc822_attachment = nil - else - unless part.rfc822_attachment.nil? - _count_parts_recursive(part.rfc822_attachment) - end - end - if part.rfc822_attachment.nil? - @count_parts_count += 1 - part.url_part_number = @count_parts_count - end - end - end # And look up by URL part number to get an attachment - # XXX relies on extract_attachments calling ensure_parts_counted + # XXX relies on extract_attachments calling MailHandler.ensure_parts_counted def self.get_attachment_by_url_part_number(attachments, found_url_part_number) attachments.each do |a| if a.url_part_number == found_url_part_number @@ -458,95 +395,6 @@ class IncomingMessage < ActiveRecord::Base return text end - # (This risks losing info if the unchosen alternative is the only one to contain - # useful info, but let's worry about that another time) - def get_attachment_leaves - force = true - return _get_attachment_leaves_recursive(self.mail(force)) - end - def _get_attachment_leaves_recursive(curr_mail, within_rfc822_attachment = nil) - leaves_found = [] - if curr_mail.multipart? - if curr_mail.parts.size == 0 - raise "no parts on multipart mail" - end - - if curr_mail.sub_type == 'alternative' - # Choose best part from alternatives - best_part = nil - # Take the last text/plain one, or else the first one - curr_mail.parts.each do |m| - if not best_part - best_part = m - elsif m.content_type == 'text/plain' - best_part = m - end - end - # Take an HTML one as even higher priority. (They tend - # to render better than text/plain, e.g. don't wrap links here: - # http://www.whatdotheyknow.com/request/amount_and_cost_of_freedom_of_in#incoming-72238 ) - curr_mail.parts.each do |m| - if m.content_type == 'text/html' - best_part = m - end - end - leaves_found += _get_attachment_leaves_recursive(best_part, within_rfc822_attachment) - else - # Add all parts - curr_mail.parts.each do |m| - leaves_found += _get_attachment_leaves_recursive(m, within_rfc822_attachment) - end - end - else - # XXX Yuck. this section alters various content_type's. That puts - # it into conflict with ensure_parts_counted which it has to be - # called both before and after. It will fail with cases of - # attachments of attachments etc. - charset = curr_mail.charset # save this, because overwriting content_type also resets charset - # Don't allow nil content_types - if curr_mail.content_type.nil? - curr_mail.content_type = 'application/octet-stream' - end - # PDFs often come with this mime type, fix it up for view code - if curr_mail.content_type == 'application/octet-stream' - part_file_name = MailHandler.get_part_file_name(curr_mail) - calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(part_file_name, curr_mail.body) - if calc_mime - curr_mail.content_type = calc_mime - end - end - - # Use standard content types for Word documents etc. - curr_mail.content_type = normalise_content_type(curr_mail.content_type) - if curr_mail.content_type == 'message/rfc822' - ensure_parts_counted # fills in rfc822_attachment variable - if curr_mail.rfc822_attachment.nil? - # Attached mail didn't parse, so treat as text - curr_mail.content_type = 'text/plain' - end - end - if curr_mail.content_type == 'application/vnd.ms-outlook' || curr_mail.content_type == 'application/ms-tnef' - ensure_parts_counted # fills in rfc822_attachment variable - if curr_mail.rfc822_attachment.nil? - # Attached mail didn't parse, so treat as binary - curr_mail.content_type = 'application/octet-stream' - end - end - # If the part is an attachment of email - if curr_mail.content_type == 'message/rfc822' || curr_mail.content_type == 'application/vnd.ms-outlook' || curr_mail.content_type == 'application/ms-tnef' - ensure_parts_counted # fills in rfc822_attachment variable - leaves_found += _get_attachment_leaves_recursive(curr_mail.rfc822_attachment, curr_mail.rfc822_attachment) - else - # Store leaf - curr_mail.within_rfc822_attachment = within_rfc822_attachment - leaves_found += [curr_mail] - end - # restore original charset - curr_mail.charset = charset - end - return leaves_found - end - # Removes anything cached about the object in the database, and saves def clear_in_database_caches! self.cached_attachment_text_clipped = nil @@ -609,7 +457,8 @@ class IncomingMessage < ActiveRecord::Base text = "[ Email has no body, please see attachments ]" source_charset = "utf-8" else - text = part.body # by default, TMail converts to UTF8 in this call + # by default, the body (coming from an foi_attachment) should have been converted to utf-8 + text = part.body source_charset = part.charset if part.content_type == 'text/html' # e.g. http://www.whatdotheyknow.com/request/35/response/177 @@ -617,42 +466,31 @@ class IncomingMessage < ActiveRecord::Base # convert to text routine. Could instead call a # sanitize HTML one. - # If the text isn't UTF8, it means TMail had a problem + # If the text isn't UTF8, it means we had a problem # converting it (invalid characters, etc), and we # should instead tell elinks to respect the source # charset use_charset = "utf-8" - begin - text = Iconv.conv('utf-8', 'utf-8', text) - rescue Iconv::IllegalSequence - use_charset = source_charset - end - text = self.class._get_attachment_text_internal_one_file(part.content_type, text, use_charset) - end - end - - # If TMail can't convert text, it just returns it, so we sanitise it. - begin - # Test if it's good UTF-8 - text = Iconv.conv('utf-8', 'utf-8', text) - rescue Iconv::IllegalSequence - # Text looks like unlabelled nonsense, - # strip out anything that isn't UTF-8 - begin - source_charset = 'utf-8' if source_charset.nil? - text = Iconv.conv('utf-8//IGNORE', source_charset, text) + - _("\n\n[ {{site_name}} note: The above text was badly encoded, and has had strange characters removed. ]", - :site_name => Configuration::site_name) - rescue Iconv::InvalidEncoding, Iconv::IllegalSequence - if source_charset != "utf-8" - source_charset = "utf-8" - retry + if RUBY_VERSION.to_f >= 1.9 + begin + text.encode('utf-8') + rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError + use_charset = source_charset + end + else + begin + text = Iconv.conv('utf-8', 'utf-8', text) + rescue Iconv::IllegalSequence + use_charset = source_charset + end end + text = MailHandler.get_attachment_text_one_file(part.content_type, text, use_charset) end end + # If text hasn't been converted, we sanitise it. + text = _sanitize_text(text) # Fix DOS style linefeeds to Unix style ones (or other later regexps won't work) - # Needed for e.g. http://www.whatdotheyknow.com/request/60/response/98 text = text.gsub(/\r\n/, "\n") # Compress extra spaces down to save space, and to stop regular expressions @@ -662,6 +500,51 @@ class IncomingMessage < ActiveRecord::Base return text end + + def _sanitize_text(text) + if RUBY_VERSION.to_f >= 1.9 + begin + # Test if it's good UTF-8 + text.encode('utf-8') + rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError + source_charset = 'utf-8' if source_charset.nil? + # strip out anything that isn't UTF-8 + begin + text = text.encode("utf-8", :invalid => :replace, + :undef => :replace, + :replace => "") + + _("\n\n[ {{site_name}} note: The above text was badly encoded, and has had strange characters removed. ]", + :site_name => MySociety::Config.get('SITE_NAME', 'Alaveteli')) + rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError + if source_charset != "utf-8" + source_charset = "utf-8" + retry + end + end + end + else + begin + # Test if it's good UTF-8 + text = Iconv.conv('utf-8', 'utf-8', text) + rescue Iconv::IllegalSequence + # Text looks like unlabelled nonsense, + # strip out anything that isn't UTF-8 + begin + source_charset = 'utf-8' if source_charset.nil? + text = Iconv.conv('utf-8//IGNORE', source_charset, text) + + _("\n\n[ {{site_name}} note: The above text was badly encoded, and has had strange characters removed. ]", + :site_name => Configuration::site_name) + rescue Iconv::InvalidEncoding, Iconv::IllegalSequence + if source_charset != "utf-8" + source_charset = "utf-8" + retry + end + end + end + end + text + end + # Returns part which contains main body text, or nil if there isn't one def get_main_body_text_part leaves = self.foi_attachments @@ -715,7 +598,7 @@ class IncomingMessage < ActiveRecord::Base filename = uu.match(/^begin\s+[0-9]+\s+(.*)$/)[1] calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(filename, content) if calc_mime - calc_mime = normalise_content_type(calc_mime) + calc_mime = MailHandler.normalise_content_type(calc_mime) content_type = calc_mime else content_type = 'application/octet-stream' @@ -744,55 +627,15 @@ class IncomingMessage < ActiveRecord::Base end def extract_attachments! - leaves = get_attachment_leaves # XXX check where else this is called from - # XXX we have to call ensure_parts_counted after get_attachment_leaves - # which is really messy. - ensure_parts_counted + force = true + attachment_attributes = MailHandler.get_attachment_attributes(self.mail(force)) attachments = [] - for leaf in leaves - body = leaf.body - # As leaf.body causes MIME decoding which uses lots of RAM, do garbage collection here - # to prevent excess memory use. XXX not really sure if this helps reduce - # peak RAM use overall. Anyway, maybe there is something better to do than this. - GC.start - if leaf.within_rfc822_attachment - within_rfc822_subject = leaf.within_rfc822_attachment.subject - # Test to see if we are in the first part of the attached - # RFC822 message and it is text, if so add headers. - # XXX should probably use hunting algorithm to find main text part, rather than - # just expect it to be first. This will do for now though. - # Example request that needs this: - # http://www.whatdotheyknow.com/request/2923/response/7013/attach/2/Cycle%20Path%20Bank.txt - if leaf.within_rfc822_attachment == leaf && leaf.content_type == 'text/plain' - headers = "" - for header in [ 'Date', 'Subject', 'From', 'To', 'Cc' ] - if leaf.within_rfc822_attachment.header.include?(header.downcase) - header_value = leaf.within_rfc822_attachment.header[header.downcase] - # Example message which has a blank Date header: - # http://www.whatdotheyknow.com/request/30747/response/80253/attach/html/17/Common%20Purpose%20Advisory%20Group%20Meeting%20Tuesday%202nd%20March.txt.html - if !header_value.blank? - headers = headers + header + ": " + header_value.to_s + "\n" - end - end - end - # XXX call _convert_part_body_to_text here, but need to get charset somehow - # e.g. http://www.whatdotheyknow.com/request/1593/response/3088/attach/4/Freedom%20of%20Information%20request%20-%20car%20oval%20sticker:%20Article%2020,%20Convention%20on%20Road%20Traffic%201949.txt - body = headers + "\n" + body - - # This is quick way of getting all headers, but instead we only add some a) to - # make it more usable, b) as at least one authority accidentally leaked security - # information into a header. - #attachment.body = leaf.within_rfc822_attachment.port.to_s - end - end - hexdigest = Digest::MD5.hexdigest(body) - attachment = self.foi_attachments.find_or_create_by_hexdigest(:hexdigest => hexdigest) - attachment.update_attributes(:url_part_number => leaf.url_part_number, - :content_type => leaf.content_type, - :filename => MailHandler.get_part_file_name(leaf), - :charset => leaf.charset, - :within_rfc822_subject => within_rfc822_subject, - :body => body) + attachment_attributes.each do |attrs| + attachment = self.foi_attachments.find_or_create_by_hexdigest(attrs[:hexdigest]) + body = attrs.delete(:body) + attachment.update_attributes(attrs) + # Set the body separately as its handling can depend on the value of charset + attachment.body = body attachment.save! attachments << attachment.id end @@ -802,7 +645,7 @@ class IncomingMessage < ActiveRecord::Base # e.g. for https://secure.mysociety.org/admin/foi/request/show_raw_email/24550 if !main_part.nil? uudecoded_attachments = _uudecode_and_save_attachments(main_part.body) - c = @count_first_uudecode_count + c = self.mail.count_first_uudecode_count for uudecode_attachment in uudecoded_attachments c += 1 uudecode_attachment.url_part_number = c @@ -894,101 +737,15 @@ class IncomingMessage < ActiveRecord::Base return self.cached_attachment_text_clipped end - def IncomingMessage._get_attachment_text_internal_one_file(content_type, body, charset = 'utf-8') - # note re. charset: TMail always tries to convert email bodies - # to UTF8 by default, so normally it should already be that. - text = '' - # XXX - tell all these command line tools to return utf-8 - if content_type == 'text/plain' - text += body + "\n\n" - else - tempfile = Tempfile.new('foiextract') - tempfile.print body - tempfile.flush - if content_type == 'application/vnd.ms-word' - AlaveteliExternalCommand.run("wvText", tempfile.path, tempfile.path + ".txt") - # Try catdoc if we get into trouble (e.g. for InfoRequestEvent 2701) - if not File.exists?(tempfile.path + ".txt") - AlaveteliExternalCommand.run("catdoc", tempfile.path, :append_to => text) - else - text += File.read(tempfile.path + ".txt") + "\n\n" - File.unlink(tempfile.path + ".txt") - end - elsif content_type == 'application/rtf' - # catdoc on RTF prodcues less comments and extra bumf than --text option to unrtf - AlaveteliExternalCommand.run("catdoc", tempfile.path, :append_to => text) - elsif content_type == 'text/html' - # lynx wordwraps links in its output, which then don't - # get formatted properly by Alaveteli. We use elinks - # instead, which doesn't do that. - AlaveteliExternalCommand.run("elinks", "-eval", "set document.codepage.assume = \"#{charset}\"", "-eval", "set document.codepage.force_assumed = 1", "-dump-charset", "utf-8", "-force-html", "-dump", - tempfile.path, :append_to => text, :env => {"LANG" => "C"}) - elsif content_type == 'application/vnd.ms-excel' - # Bit crazy using /usr/bin/strings - but xls2csv, xlhtml and - # py_xls2txt only extract text from cells, not from floating - # notes. catdoc may be fooled by weird character sets, but will - # probably do for UK FOI requests. - AlaveteliExternalCommand.run("/usr/bin/strings", tempfile.path, :append_to => text) - elsif content_type == 'application/vnd.ms-powerpoint' - # ppthtml seems to catch more text, but only outputs HTML when - # we want text, so just use catppt for now - AlaveteliExternalCommand.run("catppt", tempfile.path, :append_to => text) - elsif content_type == 'application/pdf' - AlaveteliExternalCommand.run("pdftotext", tempfile.path, "-", :append_to => text) - elsif content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - # This is Microsoft's XML office document format. - # Just pull out the main XML file, and strip it of text. - xml = AlaveteliExternalCommand.run("/usr/bin/unzip", "-qq", "-c", tempfile.path, "word/document.xml") - if !xml.nil? - doc = REXML::Document.new(xml) - text += doc.each_element( './/text()' ){}.join(" ") - end - elsif content_type == 'application/zip' - # recurse into zip files - begin - zip_file = Zip::ZipFile.open(tempfile.path) - text += IncomingMessage._get_attachment_text_from_zip_file(zip_file) - zip_file.close() - rescue - $stderr.puts("Error processing zip file: #{$!.inspect}") - end - end - tempfile.close - end - - return text - end - def IncomingMessage._get_attachment_text_from_zip_file(zip_file) - text = "" - for entry in zip_file - if entry.file? - filename = entry.to_s - begin - body = entry.get_input_stream.read - rescue - # move to next attachment silently if there were problems - # XXX really should reduce this to specific exceptions? - # e.g. password protected - next - end - calc_mime = AlaveteliFileTypes.filename_to_mimetype(filename) - if calc_mime - content_type = calc_mime - else - content_type = 'application/octet-stream' - end - text += _get_attachment_text_internal_one_file(content_type, body) - end - end - return text - end def _get_attachment_text_internal # Extract text from each attachment text = '' attachments = self.get_attachments_for_display for attachment in attachments - text += IncomingMessage._get_attachment_text_internal_one_file(attachment.content_type, attachment.body, attachment.charset) + text += MailHandler.get_attachment_text_one_file(attachment.content_type, + attachment.body, + attachment.charset) end # Remove any bad characters text = Iconv.conv('utf-8//IGNORE', 'utf-8', text) @@ -1056,65 +813,11 @@ class IncomingMessage < ActiveRecord::Base return AlaveteliFileTypes.all_extensions.join(" ") end - # Return false if for some reason this is a message that we shouldn't let them reply to - def valid_to_reply_to? - # check validity of email - if empty_from_field? - return false - end - email = self.from_email - if !MySociety::Validate.is_valid_email(email) - return false - end - - # reject postmaster - authorities seem to nearly always not respond to - # email to postmaster, and it tends to only happen after delivery failure. - # likewise Mailer-Daemon, Auto_Reply... - prefix = email - prefix =~ /^(.*)@/ - prefix = $1 - if !prefix.nil? && prefix.downcase.match(/^(postmaster|mailer-daemon|auto_reply|do.?not.?reply|no.reply)$/) - return false - end - if !self.mail['return-path'].nil? && self.mail['return-path'].addr == "<>" - return false - end - if !self.mail['auto-submitted'].nil? - return false - end - return true - end - - def normalise_content_type(content_type) - # e.g. http://www.whatdotheyknow.com/request/93/response/250 - if content_type == 'application/excel' or content_type == 'application/msexcel' or content_type == 'application/x-ms-excel' - content_type = 'application/vnd.ms-excel' - end - if content_type == 'application/mspowerpoint' or content_type == 'application/x-ms-powerpoint' - content_type = 'application/vnd.ms-powerpoint' + def for_admin_column + self.class.content_columns.each do |column| + yield(column.human_name, self.send(column.name), column.type.to_s, column.name) end - if content_type == 'application/msword' or content_type == 'application/x-ms-word' - content_type = 'application/vnd.ms-word' - end - if content_type == 'application/x-zip-compressed' - content_type = 'application/zip' - end - - # e.g. http://www.whatdotheyknow.com/request/copy_of_current_swessex_scr_opt#incoming-9928 - if content_type == 'application/acrobat' - content_type = 'application/pdf' - end - - return content_type - end - - def for_admin_column - self.class.content_columns.each do |column| - yield(column.human_name, self.send(column.name), column.type.to_s, column.name) end - end - - private :normalise_content_type end diff --git a/app/models/info_request.rb b/app/models/info_request.rb index 194f8e105..08b331c26 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -27,7 +27,7 @@ require 'digest/sha1' class InfoRequest < ActiveRecord::Base include ActionView::Helpers::UrlHelper - include ActionController::UrlWriter + include Rails.application.routes.url_helpers strip_attributes! @@ -51,7 +51,7 @@ class InfoRequest < ActiveRecord::Base has_tag_string - named_scope :visible, :conditions => {:prominence => "normal"} + scope :visible, :conditions => {:prominence => "normal"} # user described state (also update in info_request_event, admin_request/edit.rhtml) validate :must_be_valid_state @@ -81,6 +81,11 @@ class InfoRequest < ActiveRecord::Base 'blackhole' # just dump them ] + # only check on create, so existing models with mixed case are allowed + validate :title_formatting, :on => :create + + after_initialize :set_defaults + def self.enumerate_states states = [ 'waiting_response', @@ -138,7 +143,7 @@ class InfoRequest < ActiveRecord::Base if external_user_name.nil? fake_slug = "anonymous" else - fake_slug = external_user_name.parameterize + fake_slug = MySociety::Format.simplify_url_part(external_user_name, 'external_user', 32) end (public_body.url_name || "") + "_" + fake_slug else @@ -156,31 +161,8 @@ class InfoRequest < ActiveRecord::Base rescue MissingSourceFile, NameError 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) - errors.add(:title, _('Please write the summary using a mixture of capital and lower case letters. This makes it easier for others to read.')) - end - if !self.title.nil? && title.size > 200 - errors.add(:title, _('Please keep the summary short, like in the subject of an email. You can use a phrase, rather than a full sentence.')) - end - if !self.title.nil? && self.title =~ /^(FOI|Freedom of Information)\s*requests?$/i - errors.add(:title, _('Please describe more what the request is about in the subject. There is no need to say it is an FOI request, we add that on anyway.')) - end - end - OLD_AGE_IN_DAYS = 21.days - def after_initialize - if self.described_state.nil? - self.described_state = 'waiting_response' - end - # FOI or EIR? - if !self.public_body.nil? && self.public_body.eir_only? - self.law_used = 'eir' - end - end - def visible_comments self.comments.find(:all, :conditions => 'visible') end @@ -434,11 +416,11 @@ public elsif self.allow_new_responses_from == 'anybody' allow = true elsif self.allow_new_responses_from == 'authority_only' - if email.from_addrs.nil? || email.from_addrs.size == 0 + sender_email = MailHandler.get_from_address(email) + if sender_email.nil? allow = false reason = _('Only the authority can reply to this request, but there is no "From" address to check against') else - sender_email = email.from_addrs[0].spec sender_domain = PublicBody.extract_domain_from_email(sender_email) reason = _("Only the authority can reply to this request, and I don't recognise the address this reply was sent from") allow = false @@ -1155,5 +1137,29 @@ public yield(column.human_name, self.send(column.name), column.type.to_s, column.name) end end + + private + + def set_defaults + if self.described_state.nil? + self.described_state = 'waiting_response' + end + # FOI or EIR? + if !self.public_body.nil? && self.public_body.eir_only? + self.law_used = 'eir' + end + end + + def title_formatting + if !self.title.nil? && !MySociety::Validate.uses_mixed_capitals(self.title, 10) + errors.add(:title, _('Please write the summary using a mixture of capital and lower case letters. This makes it easier for others to read.')) + end + if !self.title.nil? && title.size > 200 + errors.add(:title, _('Please keep the summary short, like in the subject of an email. You can use a phrase, rather than a full sentence.')) + end + if !self.title.nil? && self.title =~ /^(FOI|Freedom of Information)\s*requests?$/i + errors.add(:title, _('Please describe more what the request is about in the subject. There is no need to say it is an FOI request, we add that on anyway.')) + end + end end diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb index 441813e5f..23b5c904b 100644 --- a/app/models/outgoing_message.rb +++ b/app/models/outgoing_message.rb @@ -50,6 +50,8 @@ class OutgoingMessage < ActiveRecord::Base end end + after_initialize :set_default_letter + # How the default letter starts and ends def get_salutation ret = "" @@ -129,13 +131,6 @@ class OutgoingMessage < ActiveRecord::Base MySociety::Validate.contains_postcode?(self.body) end - # Set default letter - def after_initialize - if self.body.nil? - self.body = get_default_message - end - end - # Check have edited letter def validate if self.body.empty? || self.body =~ /\A#{get_salutation}\s+#{get_signoff}/ || self.body =~ /#{get_internal_review_insert_here_note}/ @@ -275,6 +270,14 @@ class OutgoingMessage < ActiveRecord::Base yield(column.human_name, self.send(column.name), column.type.to_s, column.name) end end + + private + + def set_default_letter + if self.body.nil? + self.body = get_default_message + end + end end diff --git a/app/models/post_redirect.rb b/app/models/post_redirect.rb index 31f08c21a..dfca936e2 100644 --- a/app/models/post_redirect.rb +++ b/app/models/post_redirect.rb @@ -32,6 +32,8 @@ class PostRedirect < ActiveRecord::Base # Optional, does a login confirm before redirect for use in email links. belongs_to :user + after_initialize :generate_token + # We store YAML version of POST parameters in the database def post_params=(params) self.post_params_yaml = params.to_yaml @@ -62,18 +64,6 @@ class PostRedirect < ActiveRecord::Base MySociety::Util.generate_token end - # Make the token - def after_initialize - # The token is used to return you to what you are doing after the login form. - if not self.token - self.token = PostRedirect.generate_random_token - end - # There is a separate token to use in the URL if we send a confirmation email. - if not self.email_token - self.email_token = PostRedirect.generate_random_token - end - end - # Used by (rspec) test code only def self.get_last_post_redirect # XXX yeuch - no other easy way of getting the token so we can check @@ -89,6 +79,18 @@ class PostRedirect < ActiveRecord::Base PostRedirect.delete_all "updated_at < (now() - interval '2 months')" end + private + + def generate_token + # The token is used to return you to what you are doing after the login form. + if not self.token + self.token = PostRedirect.generate_random_token + end + # There is a separate token to use in the URL if we send a confirmation email. + if not self.email_token + self.email_token = PostRedirect.generate_random_token + end + end end diff --git a/app/models/profile_photo.rb b/app/models/profile_photo.rb index 6e605651d..41cb298b3 100644 --- a/app/models/profile_photo.rb +++ b/app/models/profile_photo.rb @@ -23,29 +23,15 @@ class ProfilePhoto < ActiveRecord::Base belongs_to :user + validate :data_and_draft_checks + # deliberately don't strip_attributes, so keeps raw photo properly attr_accessor :x, :y, :w, :h - # convert binary data blob into ImageMagick image when assigned attr_accessor :image - def after_initialize - if data.nil? - self.image = nil - return - end - image_list = Magick::ImageList.new - begin - image_list.from_blob(data) - rescue Magick::ImageMagickError - self.image = nil - return - end - - self.image = image_list[0] # XXX perhaps take largest image or somesuch if there were multiple in the file? - self.convert_image - end + after_initialize :convert_data_to_image # make image valid format and size def convert_image @@ -81,7 +67,9 @@ class ProfilePhoto < ActiveRecord::Base end end - def validate + private + + def data_and_draft_checks if self.data.nil? errors.add(:data, N_("Please choose a file containing your photo.")) return @@ -108,6 +96,25 @@ class ProfilePhoto < ActiveRecord::Base raise "Internal error, real pictures must have a user" end end + + # Convert binary data blob into ImageMagick image when assigned + def convert_data_to_image + if data.nil? + self.image = nil + return + end + + image_list = Magick::ImageList.new + begin + image_list.from_blob(data) + rescue Magick::ImageMagickError + self.image = nil + return + end + + self.image = image_list[0] # XXX perhaps take largest image or somesuch if there were multiple in the file? + self.convert_image + end end diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 6f6b37ba8..b48c57228 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -43,7 +43,7 @@ class PublicBody < ActiveRecord::Base before_save :set_api_key, :set_default_publication_scheme # Every public body except for the internal admin one is visible - named_scope :visible, lambda { + scope :visible, lambda { { :conditions => "public_bodies.id <> #{PublicBody.internal_admin_body.id}" } @@ -104,28 +104,25 @@ class PublicBody < ActiveRecord::Base # like find_by_url_name but also search historic url_name if none found def self.find_by_url_name_with_historic(name) - locale = self.locale || I18n.locale - PublicBody.with_locale(locale) do - found = PublicBody.find(:all, - :conditions => ["public_body_translations.url_name=?", name], - :joins => :translations, - :readonly => false) - # If many bodies are found (usually because the url_name is the same across - # locales) return any of them - return found.first if found.size >= 1 - - # If none found, then search the history of short names - old = PublicBody::Version.find_all_by_url_name(name) - # Find unique public bodies in it - old = old.map { |x| x.public_body_id } - old = old.uniq - # Maybe return the first one, so we show something relevant, - # rather than throwing an error? - raise "Two bodies with the same historical URL name: #{name}" if old.size > 1 - return unless old.size == 1 - # does acts_as_versioned provide a method that returns the current version? - return PublicBody.find(old.first) - end + found = PublicBody.find(:all, + :conditions => ["public_body_translations.url_name=?", name], + :joins => :translations, + :readonly => false) + # If many bodies are found (usually because the url_name is the same across + # locales) return any of them + return found.first if found.size >= 1 + + # If none found, then search the history of short names + old = PublicBody::Version.find_all_by_url_name(name) + # Find unique public bodies in it + old = old.map { |x| x.public_body_id } + old = old.uniq + # Maybe return the first one, so we show something relevant, + # rather than throwing an error? + raise "Two bodies with the same historical URL name: #{name}" if old.size > 1 + return unless old.size == 1 + # does acts_as_versioned provide a method that returns the current version? + return PublicBody.find(old.first) end # Set the first letter, which is used for faster queries @@ -336,7 +333,7 @@ class PublicBody < ActiveRecord::Base # The "internal admin" is a special body for internal use. def PublicBody.internal_admin_body - PublicBody.with_locale(I18n.default_locale) do + I18n.with_locale(I18n.default_locale) do pb = PublicBody.find_by_url_name("internal_admin_authority") if pb.nil? pb = PublicBody.new( @@ -374,7 +371,7 @@ class PublicBody < ActiveRecord::Base # of updating them bodies_by_name = {} set_of_existing = Set.new() - PublicBody.with_locale(I18n.default_locale) do + I18n.with_locale(I18n.default_locale) do bodies = (tag.nil? || tag.empty?) ? PublicBody.find(:all) : PublicBody.find_by_tag(tag) for existing_body in bodies # Hide InternalAdminBody from import notes @@ -417,7 +414,7 @@ class PublicBody < ActiveRecord::Base if public_body = bodies_by_name[name] # Existing public body available_locales.each do |locale| - PublicBody.with_locale(locale) do + I18n.with_locale(locale) do changed = ActiveSupport::OrderedHash.new field_list.each do |field_name| localized_field_name = (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}" @@ -452,7 +449,7 @@ class PublicBody < ActiveRecord::Base else # New public body public_body = PublicBody.new(:name=>"", :short_name=>"", :request_email=>"") available_locales.each do |locale| - PublicBody.with_locale(locale) do + I18n.with_locale(locale) do changed = ActiveSupport::OrderedHash.new field_list.each do |field_name| localized_field_name = (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}" diff --git a/app/models/user.rb b/app/models/user.rb index 6e1e21481..490587c39 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -50,12 +50,17 @@ class User < ActiveRecord::Base 'super', ], :message => N_('Admin level is not included in list') + validate :email_and_name_are_valid + acts_as_xapian :texts => [ :name, :about_me ], :values => [ [ :created_at_numeric, 1, "created_at", :number ] # for sorting ], :terms => [ [ :variety, 'V', "variety" ] ], :if => :indexed_by_search? + + after_initialize :set_defaults + def created_at_numeric # format it here as no datetime support in Xapian's value ranges return self.created_at.strftime("%Y%m%d%H%M%S") @@ -65,17 +70,6 @@ class User < ActiveRecord::Base "user" end - def after_initialize - if self.admin_level.nil? - self.admin_level = 'none' - end - if self.new_record? - # make alert emails go out at a random time for each new user, so - # overall they are spread out throughout the day. - self.last_daily_track_email = User.random_time_in_last_day - end - end - # requested_by: and commented_by: search queries also need updating after save after_update :reindex_referencing_models def reindex_referencing_models @@ -108,15 +102,6 @@ class User < ActiveRecord::Base self.comments.find(:all, :conditions => 'visible') end - def validate - if self.email != "" && !MySociety::Validate.is_valid_email(self.email) - errors.add(:email, _("Please enter a valid email address")) - end - if MySociety::Validate.is_valid_email(self.name) - errors.add(:name, _("Please enter your name, not your email address, in the name field.")) - end - end - # Don't display any leading/trailing spaces # XXX we have strip_attributes! now, so perhaps this can be removed (might # be still needed for existing cases) @@ -148,14 +133,14 @@ class User < ActiveRecord::Base if user # There is user with email, check password if !user.has_this_password?(params[:password]) - user.errors.add_to_base(auth_fail_message) + user.errors.add(:base, auth_fail_message) end else # No user of same email, make one (that we don't save in the database) # for the forms code to use. user = User.new(params) # deliberately same message as above so as not to leak whether registered - user.errors.add_to_base(auth_fail_message) + user.errors.add(:base, auth_fail_message) end user end @@ -413,6 +398,26 @@ class User < ActiveRecord::Base self.salt = self.object_id.to_s + rand.to_s end + def set_defaults + if self.admin_level.nil? + self.admin_level = 'none' + end + if self.new_record? + # make alert emails go out at a random time for each new user, so + # overall they are spread out throughout the day. + self.last_daily_track_email = User.random_time_in_last_day + end + end + + def email_and_name_are_valid + if self.email != "" && !MySociety::Validate.is_valid_email(self.email) + errors.add(:email, _("Please enter a valid email address")) + end + if MySociety::Validate.is_valid_email(self.name) + errors.add(:name, _("Please enter your name, not your email address, in the name field.")) + end + end + ## Class methods def User.encrypted_password(password, salt) string_to_hash = password + salt # XXX need to add a secret here too? diff --git a/app/views/general/_frontpage_new_request.rhtml b/app/views/general/_frontpage_new_request.rhtml index fd4225069..499b60eb5 100644 --- a/app/views/general/_frontpage_new_request.rhtml +++ b/app/views/general/_frontpage_new_request.rhtml @@ -4,4 +4,4 @@ Information<br/> request</strong>") %> </h1> -<a class="link_button_green_large" href="/select_authority"><%= _("Start now »") %></a> +<a class="link_button_green_large" href="<%= select_authority_path %>"><%= _("Start now »") %></a> diff --git a/app/views/general/_frontpage_search_box.rhtml b/app/views/general/_frontpage_search_box.rhtml index 6de4eae98..d2718b3a3 100644 --- a/app/views/general/_frontpage_search_box.rhtml +++ b/app/views/general/_frontpage_search_box.rhtml @@ -4,7 +4,7 @@ <strong>{{number_of_authorities}} authorities</strong>", :number_of_requests => InfoRequest.visible.count, :number_of_authorities => PublicBody.visible.count) %> </h2> -<form id="search_form" method="post" action="/search"> +<form id="search_form" method="post" action="<%= search_redirect_path %>"> <div> <input id="query" type="text" size="30" name="query"> <input type="submit" value="<%= _('Search') %>"> diff --git a/app/views/general/frontpage.rhtml b/app/views/general/frontpage.rhtml index acc7f4095..bf5261d15 100644 --- a/app/views/general/frontpage.rhtml +++ b/app/views/general/frontpage.rhtml @@ -1,4 +1,4 @@ -<% view_cache :ttl => 5.minutes.to_i, :tag => I18n.locale do %> +<% # TODO: Cache for 5 minutes %> <div id="frontpage_splash"> <div id="left_column"> <%= render :partial => "frontpage_new_request" %> @@ -17,4 +17,3 @@ <%= render :partial => "frontpage_bodies_list" %> <%= render :partial => "frontpage_requests_list" %> </div> -<% end %> diff --git a/app/views/help/_sidebar.rhtml b/app/views/help/_sidebar.rhtml index 783d35983..2b7ed5647 100644 --- a/app/views/help/_sidebar.rhtml +++ b/app/views/help/_sidebar.rhtml @@ -1,19 +1,19 @@ <div id="right_column_flip"> <h2>Help pages</h2> <ul class="no_bullets"> - <li><%= link_to_unless_current "Introduction", "/help/about" %></li> - <li><%= link_to_unless_current "Making requests", "/help/requesting" %></li> - <li><%= link_to_unless_current "Your privacy", "/help/privacy" %></li> - <li><%= link_to_unless_current "FOI officers", "/help/officers" %></li> - <li><%= link_to_unless_current "About the software", "/help/alaveteli" %></li> - <li><%= link_to_unless_current "Credits", "/help/credits" %></li> - <li><%= link_to_unless_current "Programmers API", "/help/api" %></li> - <li><%= link_to_unless_current "Advanced search", "/advancedsearch" %></li> + <li><%= link_to_unless_current "Introduction", help_about_path %></li> + <li><%= link_to_unless_current "Making requests", help_requesting_path %></li> + <li><%= link_to_unless_current "Your privacy", help_privacy_path %></li> + <li><%= link_to_unless_current "FOI officers", help_officers_path %></li> + <li><%= link_to_unless_current "About the software", help_alaveteli_path %></li> + <li><%= link_to_unless_current "Credits", help_credits_path %></li> + <li><%= link_to_unless_current "Programmers API", help_api_path %></li> + <li><%= link_to_unless_current "Advanced search", advanced_search_path %></li> </ul> <h2 id="contact">Contact us</h2> <p>If your question isn't answered here, or you just wanted to let us know - something about the site, <a href="/help/contact">contact us</a>. + something about the site, <a href="<%= help_contact_path %>">contact us</a>. </p> </div> diff --git a/app/views/help/about.rhtml b/app/views/help/about.rhtml index 9f75cac8b..477f0e750 100644 --- a/app/views/help/about.rhtml +++ b/app/views/help/about.rhtml @@ -41,13 +41,13 @@ </dd> <dt id="updates">How can I keep up with news about WhatDoTheyKnow?<a href="#updates">#</a> </dt> - <dd>We have a <a href="/blog">blog</a> and a <a href="https://twitter.com/whatdotheyknow">twitter feed</a>. + <dd>We have a <a href="<%= blog_path %>">blog</a> and a <a href="https://twitter.com/whatdotheyknow">twitter feed</a>. </dd> </dl> - <p><strong>Next</strong>, read about <a href="/help/requesting">making requests</a> --> + <p><strong>Next</strong>, read about <a href="<%= help_requesting_path %>">making requests</a> --> <div id="hash_link_padding"></div> </div> diff --git a/app/views/help/api.rhtml b/app/views/help/api.rhtml index facddce41..da6253f87 100644 --- a/app/views/help/api.rhtml +++ b/app/views/help/api.rhtml @@ -19,7 +19,7 @@ <dt>Linking to new requests</dt> <dd> <p>To encourage your users to make links to a particular public authority, use URLs of the form - <%= link_to new_request_to_body_url(:url_name => "liverpool_city_council") , new_request_to_body_url(:url_name => "liverpool_city_council") %>. + <%= link_to new_request_to_body_url(:url_name => "liverpool_city_council") , new_request_to_body_url(:url_name => "liverpool_city_council") %>. These are the parameters you can add to those URLs, either in the URL or from a form. <ul> @@ -34,7 +34,7 @@ <dd> <p>There are Atom feeds on most pages which list FOI requests, which you can use to get updates and links in XML format. Find the URL of the Atom feed in - one of these ways: + one of these ways: <ul> <li>Look for the <img src="/images/feed-16.png" alt=""> RSS feed links.</li> <li>Examine the <tt><link rel="alternate" type="application/atom+xml"></tt> tag in the head of the HTML. </li> @@ -43,7 +43,7 @@ <p>In particular, even complicated search queries have Atom feeds. You can do all sorts of things with them, such as query by authority, by file - type, by date range, or by status. See the <a href="/search">advanced search + type, by date range, or by status. See the <a href="<%= advanced_search_path %>">advanced search tips</a> for details. </dd> @@ -62,7 +62,7 @@ information about the list of events in the feed. </p> </dd> - + <dt>Spreadsheet of all authorities</dt> <dd> <p> @@ -73,7 +73,7 @@ </dd> </dl> - <p>Please <a href="/help/contact">contact us</a> if you need an API feature that isn't there yet. It's + <p>Please <a href="<%= help_contact_path %>">contact us</a> if you need an API feature that isn't there yet. It's very much a work in progress, and we do add things when people ask us to.</p> <div id="hash_link_padding"></div> diff --git a/app/views/help/contact.rhtml b/app/views/help/contact.rhtml index 37df68f49..385c24a62 100644 --- a/app/views/help/contact.rhtml +++ b/app/views/help/contact.rhtml @@ -9,13 +9,13 @@ <% if !flash[:notice] %> <h2>Contact an authority to get official information</h2> <ul> - <li><a href="/new">Go here</a> to make a request, in public, for information + <li><a href="<%= new_request_path %>">Go here</a> to make a request, in public, for information from public authorities.</li> <li> Asking for private information about yourself? Please read our - <a href="/help/requesting#data_protection">help page</a>. + <a href="<%= help_requesting_path(:anchor => 'data_protection') %>">help page</a>. </li> </ul> @@ -25,10 +25,10 @@ <% if !flash[:notice] %> <ul> <li> - Please read the <a href="/help/about">help page</a> first, as it may - answer your question quicker. + Please read the <a href="<%= help_about_path %>">help page</a> first, as it may + answer your question quicker. </li> - + <li>We'd love to hear how you've found using this site. Either fill in this form, or send an email to <a href="mailto:<%=@contact_email%>"><%=@contact_email%></a> @@ -46,7 +46,7 @@ <p> <label class="form_label" for="contact_name">Your name:</label> <%= f.text_field :name, :size => 20 %> - (or <%= link_to "sign in", signin_url(:r => request.request_uri) %>) + (or <%= link_to "sign in", signin_url(:r => request.fullpath) %>) </p> <p> @@ -56,25 +56,25 @@ <% end %> <p> - <label class="form_label" for="contact_subject">Subject:</label> + <label class="form_label" for="contact_subject">Subject:</label> <%= f.text_field :subject, :size => 50 %> </p> <p> - <label class="form_label" for="contact_message">Message to website:</label> + <label class="form_label" for="contact_message">Message to website:</label> <%= f.text_area :message, :rows => 10, :cols => 60 %> </p> <% if !@last_request.nil? %> <p> - <label class="form_label" for="contact_message">Include link to request:</label> + <label class="form_label" for="contact_message">Include link to request:</label> <%=request_link(@last_request) %> <%= submit_tag "remove", :name => 'remove' %> </p> <% end %> <% if !@last_body.nil? %> <p> - <label class="form_label" for="contact_message">Include link to authority:</label> + <label class="form_label" for="contact_message">Include link to authority:</label> <%=public_body_link(@last_body) %> <%= submit_tag "remove", :name => 'remove' %> </p> diff --git a/app/views/help/officers.rhtml b/app/views/help/officers.rhtml index 3defec62f..b13e225fe 100644 --- a/app/views/help/officers.rhtml +++ b/app/views/help/officers.rhtml @@ -19,13 +19,13 @@ </p> <p>If you have privacy or other concerns, please read the answers below. You might also like to read the <a - href="/help/about">introduction to WhatDoTheyKnow</a> to find out more about what + href="<%= help_about_path %>">introduction to WhatDoTheyKnow</a> to find out more about what the site does from the point of view of a user. You can also search the site to find the authority that you work for, and view the status of any requests made using the site. <p>Finally, we welcome comments and - thoughts from FOI officers, please <a href="/help/contact">get in touch</a>. + thoughts from FOI officers, please <a href="<%= help_contact_path %>">get in touch</a>. </p> </dd> @@ -75,13 +75,13 @@ the authority by email. Any delivery failure messages will automatically appear on the site. You can check the address we're using with the "View FOI email address" link which appears on the page for the authority. <a - href="/help/contact">Contact us</a> if there is a better address we can + href="<%= help_contact_path %>">Contact us</a> if there is a better address we can use.</p> <p>Requests are sometimes not delivered because they are quietly removed by "spam filters" in the IT department of the authority. Authorities can make - sure this doesn't happen by asking their IT departments to "whitelist" + sure this doesn't happen by asking their IT departments to "whitelist" any email from <strong>@whatdotheyknow.com</strong>. - If you <a href="/help/contact">ask us</a> we will resend any request, + If you <a href="<%= help_contact_path %>">ask us</a> we will resend any request, and/or give technical details of delivery so an IT department can chase up what happened to the message. </p> @@ -159,7 +159,7 @@ </li> </ul> - <p>If you're getting really nerdy about all this, read the <a href="http://www.ico.gov.uk/upload/documents/library/freedom_of_information/detailed_specialist_guides/timeforcompliance.pdf">detailed ICO guidance</a>. + <p>If you're getting really nerdy about all this, read the <a href="http://www.ico.gov.uk/upload/documents/library/freedom_of_information/detailed_specialist_guides/timeforcompliance.pdf">detailed ICO guidance</a>. Meanwhile, remember that the law says authorities must respond <strong>promptly</strong>. That's really what matters.</p> @@ -173,14 +173,14 @@ extension when applying a <strong>public interest test</strong>. Information Commissioner guidance says that it should only be used in "exceptionally complex" cases - (<a href="http://www.ico.gov.uk/upload/documents/library/freedom_of_information/detailed_specialist_guides/foi_good_practice_guidance_4.pdf">FOI Good Practice Guidance No. 4</a>). + (<a href="http://www.ico.gov.uk/upload/documents/library/freedom_of_information/detailed_specialist_guides/foi_good_practice_guidance_4.pdf">FOI Good Practice Guidance No. 4</a>). WhatDoTheyKnow doesn't specifically handle this case, which is why we use the phrase "should normally have responded by" when the 20 working day time is - exceeded. + exceeded. </p> <p>The same guidance says that, even in exceptionally complex cases, no - Freedom of Information request should take more than <strong>40 working days</strong> + Freedom of Information request should take more than <strong>40 working days</strong> to answer. WhatDoTheyKnow displays requests which are overdue by that much with stronger wording to indicate they are definitely late. </p> @@ -191,7 +191,7 @@ of 40 working days even with the extension (the House of Lords <a href="http://www.publicwhip.org.uk/division.php?date=2000-10-17&number=1&house=lords">voted to remove</a> provision for such a time limit during the initial passage - of the UK Act through Parliament). + of the UK Act through Parliament). </p> </dd> @@ -199,7 +199,7 @@ <dd>Instead of email, you can respond to a request directly from your web browser, including uploading a file. To do this, choose "respond to request" at - the bottom of the request's page. <a href="/help/contact">Contact us</a> if it + the bottom of the request's page. <a href="<%= help_contact_path %>">Contact us</a> if it is too big for even that (more than, say, 50Mb). </dd> @@ -207,17 +207,17 @@ <dd>We consider what officers or servants do in the course of their employment to be public information. We will only remove content in exceptional - circumstances, see our <a href="/help/privacy#takedown">take down policy</a>. + circumstances, see our <a href="<%= help_privacy_path(:anchor => 'takedown') %>">take down policy</a>. </dd> <dt id="mobiles">Do you publish email addresses or mobile phone numbers? <a href="#mobiles">#</a> </dt> <dd><p>To prevent spam, we automatically remove most emails and some mobile numbers from - responses to requests. Please <a href="/help/contact">contact us</a> if we've - missed one. + responses to requests. Please <a href="<%= help_contact_path %>">contact us</a> if we've + missed one. For technical reasons we don't always remove them from attachments, such as certain PDFs.</p> <p>If you need to know what an address was that we've removed, please <a - href="/help/contact">get in touch with us</a>. Occasionally, an email address + href="<%= help_contact_path %>">get in touch with us</a>. Occasionally, an email address forms an important part of a response and we will post it up in an obscured form in an annotation. </dd> @@ -225,10 +225,10 @@ <dt id="copyright"><a name="commercial"></a>What is your policy on copyright of documents?<a href="#copyright">#</a> </dt> <dd>Our Freedom of Information law is "applicant blind", so anyone in the - world can request the same document and get a copy of it. + world can request the same document and get a copy of it. If you think our making a document available on the internet infringes your - copyright, you may <a href="/help/contact">contact us</a> and ask us + copyright, you may <a href="<%= help_contact_path %>">contact us</a> and ask us to take it down. However, to save tax payers' money by preventing duplicate requests, and for good public relations, we'd advise you not to do that. </dd> @@ -238,8 +238,8 @@ </dl> - <p><strong>If you haven't already</strong>, read <a href="/help/about">the introduction</a> --> - <br><strong>Otherwise</strong>, the <a href="/help/credits">credits</a> or the <a href="/help/api">programmers API</a> --> + <p><strong>If you haven't already</strong>, read <a href="<%= help_about_path %>">the introduction</a> --> + <br><strong>Otherwise</strong>, the <a href="<%= help_credits_path %>">credits</a> or the <a href="<%= help_api_path %>">programmers API</a> --> <div id="hash_link_padding"></div> </div> diff --git a/app/views/help/privacy.rhtml b/app/views/help/privacy.rhtml index bec0c8c23..8e5293892 100644 --- a/app/views/help/privacy.rhtml +++ b/app/views/help/privacy.rhtml @@ -10,7 +10,7 @@ <dd><p>We will not disclose your email address to anyone unless we are obliged to by law, or you ask us to. This includes the public authority that you are sending a - request to. They only get to see an email address + request to. They only get to see an email address @whatdotheyknow.com which is specific to that request. </p> <p>If you send a message to another user on the site, then it will reveal your email address to them. You will be told that this is going to happen.</p> @@ -35,7 +35,7 @@ Your name is tangled up with your request, so has to be published as well. It is only fair, as we're going to publish the name of the civil servant who writes the response to your request. Using your real name also helps people - get in touch with you to assist you with your research or to campaign with you. + get in touch with you to assist you with your research or to campaign with you. </p> <p>By law, you must use your real name for the request to be a valid Freedom of Information request. See the next question for alternatives if you do not want @@ -66,16 +66,16 @@ Information Commissioner later about the handling of your request. <ul> <li>Use a different form of your name. The guidance says that "Mr Arthur Thomas Roberts" can make a valid request as "Arthur Roberts", -"A. T. Roberts", or "Mr Roberts", but <strong>not</strong> as "Arthur" or "A.T.R.". +"A. T. Roberts", or "Mr Roberts", but <strong>not</strong> as "Arthur" or "A.T.R.". </li> <li>Women may use their maiden name.</li> <li>In most cases, you may use any name by which you are "widely known and/or is regularly used". <li>Use the name of an organisation, the name of a company, the trading name of a company, or the trading name of a sole trader. -<li>Ask someone else to make the request on your behalf. +<li>Ask someone else to make the request on your behalf. <li>You may, if you are really stuck, ask us to make the request on -your behalf. Please <a href="/help/contact">contact us</a> with +your behalf. Please <a href="<%= help_contact_path %>">contact us</a> with a good reason why you cannot make the request yourself and cannot ask a friend to. We don't have the resources to do this for everyone. </ul> @@ -88,19 +88,19 @@ ask a friend to. We don't have the resources to do this for everyone. <dd> <p>If a public authority asks you for your full, physical address, reply to them saying -that section 8.1.b of the FOI Act asks for an "address for correspondence", -and that the email address you are using is sufficient. +that section 8.1.b of the FOI Act asks for an "address for correspondence", +and that the email address you are using is sufficient. </p> <p> The Ministry of Justice has <a href="http://www.justice.gov.uk/guidance/foi-procedural-what.htm">guidance on this</a> – <em>"As well as hard copy written correspondence, requests that are -transmitted electronically (for example, in emails) are acceptable +transmitted electronically (for example, in emails) are acceptable ... If a request is received by email and no postal address is given, the email address should be treated as the return address." </em> </p> -<p>As if that isn't enough, the Information Commissioner's +<p>As if that isn't enough, the Information Commissioner's <a href="http://www.ico.gov.uk/upload/documents/library/freedom_of_information/practical_application/foi_hints_for_practitioners_handing_foi_and_eir_requests_2008_final.pdf">Hints for Practitioners</a> say <em>"Any correspondence could include a request for information. If it is written (this includes e-mail), legible, gives the name of the applicant, an address for reply (which could be electronic), and includes a description of the information required, then it will fall within the scope of the legislation."</em> </p> @@ -141,10 +141,10 @@ see the section on <a href="#real_name">pseudonyms</a>.</p> <dt id="takedown">Can you take down personal information about me? <a href="#takedown">#</a> </dt> -<dd> +<dd> <p>If you see any personal information about you on the site which you'd like -us to remove or hide, then please <a href="/help/contact">let us know</a>. +us to remove or hide, then please <a href="<%= help_contact_path %>">let us know</a>. Specify exactly what information you believe to be problematic and why, and where it appears on the site.</p> @@ -165,8 +165,8 @@ which outweighs the public interest, and must demonstrate that efforts have been made to conceal the name on the organisation's own website.</p> <p>For all other requests we apply a public interest test to decide -whether information should be removed. -<a href="http://www.statutelaw.gov.uk/content.aspx?ActiveTextDocId=3190650"> Section 32</a> +whether information should be removed. +<a href="http://www.statutelaw.gov.uk/content.aspx?ActiveTextDocId=3190650"> Section 32</a> of the Data Protection Act 1998 permits us to do this, as the material we publish is journalistic. We cannot easily edit many types of attachments (such as PDFs, or Microsoft Word or Excel files), so we will usually ask @@ -177,7 +177,7 @@ that authorities resend these with the personal information removed.</p> </dl> -<p><strong>Learn more</strong> from the help for <a href="/help/officers">FOI officers</a> --> +<p><strong>Learn more</strong> from the help for <a href="<%= help_officers_path %>">FOI officers</a> --> <div id="hash_link_padding"></div> </div> diff --git a/app/views/help/requesting.rhtml b/app/views/help/requesting.rhtml index af8f2e45d..e7cfdd199 100644 --- a/app/views/help/requesting.rhtml +++ b/app/views/help/requesting.rhtml @@ -20,7 +20,7 @@ <li>Don't worry excessively about getting the right authority. If you get it wrong, they ought to advise you who to make the request to instead. </li> - <li>If you've got a thorny case, please <a href="/help/contact">contact us</a> for help.</li> + <li>If you've got a thorny case, please <a href="<%= help_contact_path %>">contact us</a> for help.</li> </ul> </dd> @@ -30,7 +30,7 @@ <dt id="missing_body">You're missing the public authority that I want to request from! <a href="#missing_body">#</a> </dt> <dd> - <p>Please <a href="/help/contact">contact us</a> with the name of the public authority and, + <p>Please <a href="<%= help_contact_path %>">contact us</a> with the name of the public authority and, if you can find it, their contact email address for Freedom of Information requests. </p> <p>If you'd like to help add a whole category of public authority to the site, we'd love @@ -47,11 +47,11 @@ <ul> <li> Those formally subject to the FOI Act</li> - <li> Those formally subject to the Environmental Regulations (a less well + <li> Those formally subject to the Environmental Regulations (a less well defined group)</li> <li> Those which voluntarily comply with the FOI Act</li> <li> Those which aren't subject to the Act but we think should be, on grounds - such as them having significant public responsibilities. + such as them having significant public responsibilities. </li> </ul> @@ -132,7 +132,7 @@ <p>Even if they are not prompt, in nearly all cases they must respond within 20 working days. If you had to clarify your request, or they are a school, or one or two other cases, then they may have more time - (<a href="/help/officers#days">full details</a>). + (<a href="<%= help_officers_path(:anchor => 'days') %>">full details</a>). <p>WhatDoTheyKnow will email you if you don't get a timely response. You can then send the public authority a message to remind them, and tell them if they @@ -158,24 +158,24 @@ checking that they received the request. It was sent to them by email. </li> <li>If they have not received it, the problem is most likely due to - "spam filters". Refer the authority to the measures in the answer - '<a href="/help/officers#spam_problems">I can see a request on WhatDoTheyKnow, but we never got it by email!</a>' - in the FOI officers section of this help. + "spam filters". Refer the authority to the measures in the answer + '<a href="<%= help_officers_path(:anchor => 'spam_problems') %>">I can see a request on WhatDoTheyKnow, but we never got it by email!</a>' + in the FOI officers section of this help. </li> <li>If you're still having no luck, then you can ask for an internal review, and then complain to the Information Commissioner about the authority. - Read our page '<a href="/help/unhappy">Unhappy about the response you got?</a>'. + Read our page '<a href="<%= help_general_path(:action => 'unhappy') %>">Unhappy about the response you got?</a>'. </ul> </dd> <dt id="not_satifised">What if I'm not satisfied with the response? <a href="#not_satifised">#</a> </dt> <dd>If you didn't get the information you asked for, or you didn't get it in time, - then read our page '<a href="/help/unhappy">Unhappy about the response you got?</a>'. + then read our page '<a href="<%= help_general_path(:action => 'unhappy') %>">Unhappy about the response you got?</a>'. </dd> <dt id="reuse">It says I can't re-use the information I got!<a href="#reuse">#</a> </dt> <dd> - <p>Authorities often add legal boilerplate about the + <p>Authorities often add legal boilerplate about the "<a href="http://www.opsi.gov.uk/si/si2005/20051515">Re-Use of Public Sector Information Regulations 2005</a>", which at first glance implies you may not be able do anything with the information. @@ -184,7 +184,7 @@ <p>You can, of course, write articles about the information or summarise it, or quote parts of it. We also think you should feel free to republish the information in full, just as we do, even though in theory you might not be - allowed to do so. See <a href="/help/officers#copyright">our policy on copyright</a>.</p> + allowed to do so. See <a href="<%= help_officers_path(:anchor => 'copyright') %>">our policy on copyright</a>.</p> </dd> @@ -199,7 +199,7 @@ the process is very similar. There are differences around time limits for compliance. See the <a href="http://www.itspublicknowledge.info/nmsruntime/saveasdialog.asp?lID=1858&sID=321">Scottish - Information Commissioner's guidance</a> for details.</p> + Information Commissioner's guidance</a> for details.</p> </dd> <dt id="data_protection">Can I request information about myself? <a href="#data_protection">#</a> </dt> @@ -216,7 +216,7 @@ website) explains how to do this.</p> <p>If you see that somebody has included personal information, perhaps - unwittingly, in a request, please <a href="/help/contact">contact us</a> + unwittingly, in a request, please <a href="<%= help_contact_path %>">contact us</a> immediately so we can remove it.</p> </dd> @@ -228,7 +228,7 @@ to read. </p> <p>You should contact the public authority directly if you would like to make a request in private. If you're interested in buying a system which helps - you manage FOI requests in secret, then <a href="/help/contact">contact us</a>. + you manage FOI requests in secret, then <a href="<%= help_contact_path %>">contact us</a>. </p> </dd> @@ -237,7 +237,7 @@ <dd> <p>Some public authorities, such as <a href="http://www.whatdotheyknow.com/body/south_east_water">South East Water</a>, don't come under the Freedom of Information Act, but do come under another law called - the Environmental Information Regulations (EIR). + the Environmental Information Regulations (EIR). </p> <p>It's a very similar law, so you make a request @@ -250,7 +250,7 @@ <p>You can, of course, request environmental information from other authorities. Just make a Freedom of Information (FOI) request as normal. The authority has a duty to work out if the Environmental Information Regulations - (EIR) is the more appropriate legislation to reply under. + (EIR) is the more appropriate legislation to reply under. </p> </dd> @@ -275,7 +275,7 @@ <dt id="moderation">How do you moderate request annotations? <a href="#moderation">#</a> </dt> - <dd> + <dd> <p>Annotations on WhatDoTheyKnow are to help people get the information they want, or to give them pointers to places they can go to help them act on it. We reserve the right to remove anything else. @@ -286,7 +286,7 @@ </dl> - <p><strong>Next</strong>, read about <a href="/help/privacy">your privacy</a> --> + <p><strong>Next</strong>, read about <a href="<%= help_privacy_path %>">your privacy</a> --> <div id="hash_link_padding"></div> </div> diff --git a/app/views/help/unhappy.rhtml b/app/views/help/unhappy.rhtml index 4f3c67b9e..2b00341c2 100644 --- a/app/views/help/unhappy.rhtml +++ b/app/views/help/unhappy.rhtml @@ -2,7 +2,7 @@ <% if !@info_request.nil? %> -<h1>Unhappy about the response you got +<h1>Unhappy about the response you got to your request '<%=request_link(@info_request) %>'? </h1> <% else %> @@ -58,10 +58,10 @@ authority, then <a href="http://www.itspublicknowledge.info/YourRights/HowToApp to the Scottish Information Commissioner</a>. </p> -<p>To make it easier to send the relevant information to the +<p>To make it easier to send the relevant information to the Information Commissioner, either <% if !@info_request.nil? %> - include a link to your request + include a link to your request <strong><%=h main_url(request_url(@info_request)) %></strong> <% else %> include a link to your request on <%= site_name %> @@ -86,8 +86,8 @@ get the information by <strong>other means...</strong></p> <ul> <li>Make a <strong>new FOI request</strong> for summary information, or for -documentation relating indirectly to matters in your refused request. -<a href="/help/contact">Ask us for ideas</a> if you're stuck.</li> +documentation relating indirectly to matters in your refused request. +<a href="<%= help_contact_path %>">Ask us for ideas</a> if you're stuck.</li> <li>If any <strong>other public authorities</strong> or publicly owned companies are involved, then make FOI requests to them.</li> <li>Write to <strong>your MP</strong> or other politician using <a @@ -95,13 +95,13 @@ href="http://www.writetothem.com">WriteToThem</a> and ask for their help finding the answer. MPs can write directly to ministers or departments, and can ask written questions in the House of Commons. Councillors in local authorities can talk directly to council officers.</li> -<li>Ask <strong>other researchers</strong> who are interested in a similar +<li>Ask <strong>other researchers</strong> who are interested in a similar issue to yours for ideas. You can sometimes find them by browsing this site; contact any registered user from their page. There may be an Internet forum or group that they hang out in. If it is a local matter, use <a -href="http://www.groupsnearyou.com">GroupsNearYou</a> to find such a +href="http://www.groupsnearyou.com">GroupsNearYou</a> to find such a forum.</li> -<li><strong>Start a pledge</strong> on <a href="http://www.pledgebank.com">PledgeBank</a> to get +<li><strong>Start a pledge</strong> on <a href="http://www.pledgebank.com">PledgeBank</a> to get others to act together with you. For example, you could arrange a meeting with staff from the authority. Or you could form a small local campaigns group. </ul> diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml index 8c4ae588b..28d099984 100644 --- a/app/views/layouts/default.rhtml +++ b/app/views/layouts/default.rhtml @@ -32,7 +32,7 @@ <% end %> <% end %> <% if @has_json %> - <link rel="alternate" type="application/json" title="JSON version of this page" href="<%=h main_url(request.request_uri, '.json') %>"> + <link rel="alternate" type="application/json" title="JSON version of this page" href="<%=h main_url(request.fullpath, '.json') %>"> <% end %> <% if @no_crawl %> @@ -69,9 +69,9 @@ <% if !@popup_banner.blank? %> <div id="everypage" class="jshide"> - <p style="float:right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;"><%= _('Close') %></a></p> + <p class="popup-close"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;"><%= _('Close') %></a></p> <%= @popup_banner %> - <p style="text-align: right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;"><%= _('Close') %></a></p> + <p class="popup-close"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;"><%= _('Close') %></a></p> </div> <% end %> @@ -92,15 +92,15 @@ <% end %> - <%= link_to _("Sign out"), signout_url(:r => request.request_uri) %> + <%= link_to _("Sign out"), signout_url(:r => request.fullpath) %> <% else %> - <%= link_to _("Sign in or sign up"), signin_url(:r => request.request_uri) %> + <%= link_to _("Sign in or sign up"), signin_url(:r => request.fullpath) %> <% end %> </div> <% end %> <div id="navigation_search"> - <form id="navigation_search_form" method="post" action="/search"> + <form id="navigation_search_form" method="post" action="<%= search_redirect_path %>"> <p> <%= text_field_tag 'query', params[:query], { :size => 40, :id => "navigation_search_query" } %> <input id="navigation_search_button" type="submit" value="search"> diff --git a/app/views/request/_describe_state.rhtml b/app/views/request/_describe_state.rhtml index 5b6004e81..f70e5ed8b 100644 --- a/app/views/request/_describe_state.rhtml +++ b/app/views/request/_describe_state.rhtml @@ -108,7 +108,7 @@ <%= _('We don\'t know whether the most recent response to this request contains information or not – - if you are {{user_link}} please <a href="{{url}}">sign in</a> and let everyone know.',:user_link=>user_link(@info_request.user), :url=>signin_url(:r => request.request_uri)) %> + if you are {{user_link}} please <a href="{{url}}">sign in</a> and let everyone know.',:user_link=>user_link(@info_request.user), :url=>signin_url(:r => request.fullpath)) %> <% end %> <% end %> diff --git a/app/views/request/_hidden_correspondence.rhtml b/app/views/request/_hidden_correspondence.rhtml index 0873b312f..a5e680385 100644 --- a/app/views/request/_hidden_correspondence.rhtml +++ b/app/views/request/_hidden_correspondence.rhtml @@ -8,20 +8,20 @@ <div class="correspondence" id="incoming-<%=incoming_message.id.to_s%>"> <p> <%= raw(_('This response has been hidden. See annotations to find out why. - If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]) %> + If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.fullpath)]) %> </p> </div> <% elsif [ 'sent', 'followup_sent', 'resent', 'followup_resent' ].include?(info_request_event.event_type) %> <div class="correspondence" id="outgoing-<%=outgoing_message.id.to_s%>"> <p> <%= raw(_('This outgoing message has been hidden. See annotations to - find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]) %> + find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.fullpath)]) %> </p> </div> <% elsif info_request_event.event_type == 'comment' %> <div class="comment_in_request" id="comment-<%=comment.id.to_s%>"> <p><%= raw(_('This comment has been hidden. See annotations to - find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.request_uri)]) %> + find out why. If you are the requester, then you may <a href="%s">sign in</a> to view the response.') % [signin_url(:r => request.fullpath)]) %> </p> </div> <% end %> diff --git a/app/views/request/_sidebar.rhtml b/app/views/request/_sidebar.rhtml index b669278f9..d349bee14 100644 --- a/app/views/request/_sidebar.rhtml +++ b/app/views/request/_sidebar.rhtml @@ -46,8 +46,8 @@ <%= render :partial => 'request/next_actions' %> - <% view_cache :ttl => 1.day.to_i, :tag => ['similar', @info_request.id, I18n.locale] do %> - <% if !@xapian_similar.nil? && @xapian_similar.results.size > 0 %> + <% # TODO: Cache for 1 day %> + <% if !@xapian_similar.nil? && @xapian_similar.results.size > 0 %> <h2><%= _('Similar requests')%></h2> <% for result in @xapian_similar.results %> <%= render :partial => 'request/request_listing_short_via_event', :locals => { :event => result[:model], :info_request => result[:model].info_request } %> @@ -56,8 +56,7 @@ <p><%= link_to _("More similar requests"), request_similar_url(@info_request) %></p> <% end %> <!-- Important terms: <%= @xapian_similar.important_terms.join(" ") %> --> - <% end %> - <% end %> + <% end %> <p><%= link_to _('Event history details'), request_details_url(@info_request) %></p> diff --git a/app/views/request/hidden.rhtml b/app/views/request/hidden.rhtml index 2d038a663..41b2ff7e4 100644 --- a/app/views/request/hidden.rhtml +++ b/app/views/request/hidden.rhtml @@ -12,7 +12,7 @@ various reasons why we might have done this, sorry we can\'t be more specific he </p> <% if @info_request.prominence == 'requester_only' %> <p> - <%= raw(_('If you are the requester, then you may <a href="%s">sign in</a> to view the request.') % [signin_url(:r => request.request_uri)]) %> + <%= raw(_('If you are the requester, then you may <a href="%s">sign in</a> to view the request.') % [signin_url(:r => request.fullpath)]) %> </p> <% end %> diff --git a/app/views/request/list.rhtml b/app/views/request/list.rhtml index 7cbd982f1..062b77c3e 100644 --- a/app/views/request/list.rhtml +++ b/app/views/request/list.rhtml @@ -14,22 +14,21 @@ <div style="clear:both"></div> <div class="results_section"> - <% view_cache :ttl => 5.minutes.to_i, :tag => [@cache_tag] do %> - <% if @list_results.empty? %> - <p> <%= _('No requests of this sort yet.')%></p> - <% else %> - <h2 class="foi_results"><%= _('{{count}} FOI requests found', :count => @matches_estimated) %></h2> - <div class="results_block"> - <% for result in @list_results%> - <% if result.class.to_s == 'InfoRequestEvent' %> - <%= render :partial => 'request/request_listing_via_event', :locals => { :event => result, :info_request => result.info_request } %> - <% else %> - <p><strong><%= _('Unexpected search result type') %> <%=result.class.to_s%></strong></p> - <% end %> - <% end %> - </div> - <% end %> + <% # TODO: Cache for 5 minutes %> + <% if @list_results.empty? %> + <p> <%= _('No requests of this sort yet.')%></p> + <% else %> + <h2 class="foi_results"><%= _('{{count}} FOI requests found', :count => @matches_estimated) %></h2> + <div class="results_block"> + <% for result in @list_results%> + <% if result.class.to_s == 'InfoRequestEvent' %> + <%= render :partial => 'request/request_listing_via_event', :locals => { :event => result, :info_request => result.info_request } %> + <% else %> + <p><strong><%= _('Unexpected search result type') %> <%=result.class.to_s%></strong></p> + <% end %> + <% end %> + </div> + <% end %> - <%= will_paginate WillPaginate::Collection.new(@page, @per_page, @show_no_more_than) %> - <% end %> + <%= will_paginate WillPaginate::Collection.new(@page, @per_page, @show_no_more_than) %> </div> diff --git a/app/views/request/new_please_describe.rhtml b/app/views/request/new_please_describe.rhtml index ff27405b8..6a193e70d 100644 --- a/app/views/request/new_please_describe.rhtml +++ b/app/views/request/new_please_describe.rhtml @@ -13,7 +13,7 @@ if they are successful yet or not.') %> </ul> <p> - <%= raw(_('When you\'re done, <strong>come back here</strong>, <a href="%s">reload this page</a> and file your new request.') % [request.request_uri]) %> + <%= raw(_('When you\'re done, <strong>come back here</strong>, <a href="%s">reload this page</a> and file your new request.') % [request.fullpath]) %> </p> <p> diff --git a/app/views/request/show.rhtml b/app/views/request/show.rhtml index 0cae3a9aa..fa75a6529 100644 --- a/app/views/request/show.rhtml +++ b/app/views/request/show.rhtml @@ -106,7 +106,7 @@ <%= _('The request is <strong>waiting for clarification</strong>.') %> <% if !@info_request.is_external? %> <%= _('If you are {{user_link}}, please',:user_link=>user_link_for_request(@info_request)) %> - <%= link_to _("sign in"), signin_url(:r => request.request_uri) %> <%= _('to send a follow up message.') %> + <%= link_to _("sign in"), signin_url(:r => request.fullpath) %> <%= _('to send a follow up message.') %> <% end %> <% end %> <% elsif @status == 'gone_postal' %> diff --git a/app/views/track/_tracking_links.rhtml b/app/views/track/_tracking_links.rhtml index 06e87ac74..ee18ec475 100644 --- a/app/views/track/_tracking_links.rhtml +++ b/app/views/track/_tracking_links.rhtml @@ -9,7 +9,7 @@ <% elsif existing_track %> <p><%= track_thing.params[:verb_on_page_already] %></p> <div class="feed_link feed_link_<%=location%>"> - <%= link_to _("Unsubscribe"), {:controller => 'track', :action => 'update', :track_id => existing_track.id, :track_medium => "delete", :r => request.request_uri}, :class => "link_button_green" %> + <%= link_to _("Unsubscribe"), {:controller => 'track', :action => 'update', :track_id => existing_track.id, :track_medium => "delete", :r => request.fullpath}, :class => "link_button_green" %> </div> <% elsif track_thing %> <div class="feed_link feed_link_<%=location%>"> diff --git a/app/views/user/show.rhtml b/app/views/user/show.rhtml index 31ea2a70b..e8e59b541 100644 --- a/app/views/user/show.rhtml +++ b/app/views/user/show.rhtml @@ -97,7 +97,7 @@ <% if not @is_you %> <p id="user_not_logged_in"> - <%= raw(_('<a href="%s">Sign in</a> to change password, subscriptions and more ({{user_name}} only)',:user_name=>h(@display_user.name)) % [signin_url(:r => request.request_uri)]) %> + <%= raw(_('<a href="%s">Sign in</a> to change password, subscriptions and more ({{user_name}} only)',:user_name=>h(@display_user.name)) % [signin_url(:r => request.fullpath)]) %> </p> <% end %> </div> @@ -186,7 +186,7 @@ <%=TrackThing.track_type_description(@track_things[0].track_type)%> <%= hidden_field_tag 'track_type', @track_things[0].track_type %> <%= hidden_field_tag 'user', @display_user.id %> - <%= hidden_field_tag 'r', request.request_uri %> + <%= hidden_field_tag 'r', request.fullpath %> <% if @track_things.size > 1 %> <%= submit_tag _('unsubscribe all') %> <% end %> @@ -200,7 +200,7 @@ <%=TrackThing.track_type_description(track_type)%> <%= hidden_field_tag 'track_type', track_type %> <%= hidden_field_tag 'user', @display_user.id %> - <%= hidden_field_tag 'r', request.request_uri %> + <%= hidden_field_tag 'r', request.fullpath %> <% if track_things.size > 1 %> <%= submit_tag _('unsubscribe all')%> <% end %> @@ -215,7 +215,7 @@ <div> <%= track_thing.params[:list_description] %> <%= hidden_field_tag 'track_medium', "delete", { :id => 'track_medium_' + track_thing.id.to_s } %> - <%= hidden_field_tag 'r', request.request_uri, { :id => 'r_' + track_thing.id.to_s } %> + <%= hidden_field_tag 'r', request.fullpath, { :id => 'r_' + track_thing.id.to_s } %> <%= submit_tag _('unsubscribe') %> </div> <% end %> |