diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/admin_public_body_controller.rb | 7 | ||||
-rw-r--r-- | app/controllers/general_controller.rb | 35 | ||||
-rw-r--r-- | app/controllers/public_body_controller.rb | 33 | ||||
-rw-r--r-- | app/controllers/request_controller.rb | 13 | ||||
-rw-r--r-- | app/controllers/user_controller.rb | 15 | ||||
-rw-r--r-- | app/helpers/application_helper.rb | 27 | ||||
-rw-r--r-- | app/models/change_email_validator.rb | 9 | ||||
-rw-r--r-- | app/models/exim_log.rb | 4 | ||||
-rw-r--r-- | app/models/incoming_message.rb | 384 | ||||
-rw-r--r-- | app/models/info_request.rb | 1 | ||||
-rw-r--r-- | app/models/public_body.rb | 40 | ||||
-rw-r--r-- | app/models/request_mailer.rb | 28 | ||||
-rw-r--r-- | app/models/track_mailer.rb | 29 | ||||
-rw-r--r-- | app/views/comment/_comment_form.rhtml | 1 | ||||
-rw-r--r-- | app/views/general/frontpage.rhtml | 4 | ||||
-rw-r--r-- | app/views/general/search.rhtml | 23 | ||||
-rw-r--r-- | app/views/layouts/admin.rhtml | 3 | ||||
-rw-r--r-- | app/views/layouts/default.rhtml | 2 | ||||
-rw-r--r-- | app/views/public_body/show.rhtml | 2 | ||||
-rw-r--r-- | app/views/request/_followup.rhtml | 5 | ||||
-rw-r--r-- | app/views/request/new.rhtml | 4 | ||||
-rw-r--r-- | app/views/track_mailer/event_digest.rhtml | 2 |
22 files changed, 305 insertions, 366 deletions
diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index 98d4c1044..f88b25572 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -77,6 +77,7 @@ class AdminPublicBodyController < AdminController @locale = self.locale_from_params() PublicBody.with_locale(@locale) do @public_body = PublicBody.find(params[:id]) + render end end @@ -84,6 +85,7 @@ class AdminPublicBodyController < AdminController @locale = self.locale_from_params() PublicBody.with_locale(@locale) do @public_body = PublicBody.new + render end end @@ -106,6 +108,7 @@ class AdminPublicBodyController < AdminController PublicBody.with_locale(@locale) do @public_body = PublicBody.find(params[:id]) @public_body.last_edit_comment = "" + render end end @@ -136,9 +139,9 @@ class AdminPublicBodyController < AdminController public_body.tag_string = "" public_body.destroy + flash[:notice] = "PublicBody was successfully destroyed." + redirect_to admin_url('body/list') end - flash[:notice] = "PublicBody was successfully destroyed." - redirect_to admin_url('body/list') end def import_csv diff --git a/app/controllers/general_controller.rb b/app/controllers/general_controller.rb index bdbcfcdd4..21f3edbb1 100644 --- a/app/controllers/general_controller.rb +++ b/app/controllers/general_controller.rb @@ -20,19 +20,35 @@ class GeneralController < ApplicationController # New, improved front page! def frontpage - # This is too slow + + behavior_cache 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 = MySociety::Config.get('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 - @popular_bodies = PublicBody.find(:all, - :select => "public_bodies.*, (select count(*) from info_requests where info_requests.public_body_id = public_bodies.id) as c", - :order => "c desc", - :limit => 32, - :conditions => conditions, - :joins => :translations - ) - end + if body_short_names.empty? + # This is too slow + @popular_bodies = PublicBody.find(:all, + :select => "public_bodies.*, (select count(*) from info_requests where info_requests.public_body_id = public_bodies.id) as c", + :order => "c desc", + :limit => 32, + :conditions => conditions, + :joins => :translations + ) + else + @popular_bodies = PublicBody.find(:all, + :conditions => conditions + ["url_name in (" + body_short_names + ")"], + :joins => :translations) + end + end + @search_examples = MySociety::Config.get('FRONTPAGE_SEARCH_EXAMPLES', '').split(/\s*;\s*/) + if @search_examples.empty? + @search_examples = @popular_bodies.map { |body| body.name } + end # Get some successful requests # begin query = 'variety:response (status:successful OR status:partially_successful)' @@ -44,6 +60,7 @@ class GeneralController < ApplicationController rescue @successful_request_events = [] end + end end # Display WhatDoTheyKnow category from mySociety blog diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index e31b52f9d..c74959b17 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -20,11 +20,16 @@ class PublicBodyController < ApplicationController PublicBody.with_locale(@locale) do @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name]) raise "None found" if @public_body.nil? # XXX proper 404 - return redirect_to :back if @public_body.url_name.nil? - # If found by historic name, redirect to new name - redirect_to show_public_body_url(:url_name => @public_body.url_name) if - @public_body.url_name != params[:url_name] - + if @public_body.url_name.nil? + redirect_to :back + return + end + # If found by historic name, or alternate locale name, redirect to new name + if @public_body.url_name != params[:url_name] + redirect_to show_public_body_url(:url_name => @public_body.url_name) + return + end + set_last_body(@public_body) top_url = main_url("/") @@ -51,9 +56,10 @@ class PublicBodyController < ApplicationController @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ] respond_to do |format| - format.html { @has_json = true } + format.html { @has_json = true; render :template => "public_body/show"} format.json { render :json => @public_body.json_for_api } end + end end @@ -99,13 +105,6 @@ class PublicBodyController < ApplicationController and has_tag_string_tags.model = \'PublicBody\' and has_tag_string_tags.name = ?) > 0', @locale, @tag] end - PublicBody.with_locale(@locale) do - @public_bodies = PublicBody.paginate( - :order => "public_body_translations.name", :page => params[:page], :per_page => 1000, # fit all councils on one page - :conditions => conditions, - :joins => :translations - ) - end if @tag.size == 1 @description = _("beginning with") + " '" + @tag + "'" else @@ -114,6 +113,14 @@ class PublicBodyController < ApplicationController @description = @tag end end + PublicBody.with_locale(@locale) do + @public_bodies = PublicBody.paginate( + :order => "public_body_translations.name", :page => params[:page], :per_page => 1000, # fit all councils on one page + :conditions => conditions, + :joins => :translations + ) + render :template => "public_body/list" + end end # Used so URLs like /local/islington work, for use e.g. writing to a local paper. diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 8987768e6..b17717002 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -6,6 +6,8 @@ # # $Id: request_controller.rb,v 1.192 2009-10-19 19:26:40 francis Exp $ +require 'alaveteli_file_types' + class RequestController < ApplicationController before_filter :check_read_only, :only => [ :new, :show_response, :describe_state, :upload_response ] protect_from_forgery :only => [ :new, :show_response, :describe_state, :upload_response ] # See ActionController::RequestForgeryProtection for details @@ -52,7 +54,7 @@ class RequestController < ApplicationController @last_info_request_event_id = @info_request.last_event_id_needing_description @new_responses_count = @info_request.events_needing_description.select {|i| i.event_type == 'response'}.size - +1 # Sidebar stuff # ... requests that have similar imporant terms behavior_cache :tag => ['similar', @info_request.id] do @@ -74,10 +76,10 @@ class RequestController < ApplicationController @last_response = @info_request.get_last_response respond_to do |format| - format.html { @has_json = true } + format.html { @has_json = true; render :template => 'request/show'} format.json { render :json => @info_request.json_for_api(true) } end - end + end end # Extra info about a request, such as event history @@ -592,8 +594,7 @@ class RequestController < ApplicationController if foi_fragment_cache_exists?(key_path) cached = foi_fragment_cache_read(key_path) - IncomingMessage # load global filename_to_mimetype XXX should move filename_to_mimetype to proper namespace - response.content_type = filename_to_mimetype(params[:file_name].join("/")) or 'application/octet-stream' + response.content_type = AlaveteliFileTypes.filename_to_mimetype(params[:file_name].join("/")) || 'application/octet-stream' render_for_text(cached) return end @@ -615,7 +616,7 @@ class RequestController < ApplicationController @incoming_message.binary_mask_stuff!(@attachment.body, @attachment.content_type) # we don't use @attachment.content_type here, as we want same mime type when cached in cache_attachments above - response.content_type = filename_to_mimetype(params[:file_name].join("/")) or 'application/octet-stream' + response.content_type = AlaveteliFileTypes.filename_to_mimetype(params[:file_name].join("/")) || 'application/octet-stream' render :text => @attachment.body end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 823366957..2e3f6c9e0 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -257,7 +257,10 @@ class UserController < ApplicationController return end - @signchangeemail = ChangeEmailValidator.new(params[:signchangeemail]) + # validate taking into account the user_circumstance + validator_params = params[:signchangeemail].clone + validator_params[:user_circumstance] = session[:user_circumstance] + @signchangeemail = ChangeEmailValidator.new(validator_params) @signchangeemail.logged_in_user = @user if !@signchangeemail.valid? @@ -279,8 +282,11 @@ class UserController < ApplicationController # if not already, send a confirmation link to the new email address which logs # them into the old email's user account, but with special user_circumstance if (not session[:user_circumstance]) or (session[:user_circumstance] != "change_email") - post_redirect = PostRedirect.new(:uri => signchangeemail_url(), :post_params => params, - :circumstance => "change_email" # special login that lets you change your email + # don't store the password in the db + params[:signchangeemail].delete(:password) + post_redirect = PostRedirect.new(:uri => signchangeemail_url(), + :post_params => params, + :circumstance => "change_email" # special login that lets you change your email ) post_redirect.user = @user post_redirect.save! @@ -297,6 +303,9 @@ class UserController < ApplicationController # circumstance is 'change_email', so can actually change the email @user.email = @signchangeemail.new_email @user.save! + + # Now clear the circumstance + session[:user_circumstance] = nil flash[:notice] = _("You have now changed your email address used on {{site_name}}",:site_name=>site_name) redirect_to user_url(@user) end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a9474ef0f..e46404a72 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,22 +19,29 @@ module ApplicationHelper objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact count = objects.inject(0) {|sum, object| sum + object.errors.count } unless count.zero? - html = {} - [:id, :class].each do |key| - if options.include?(key) - value = options[key] - html[key] = value unless value.blank? - else - html[key] = 'errorExplanation' - end + html = {} + [:id, :class].each do |key| + if options.include?(key) + value = options[key] + html[key] = value unless value.blank? + else + html[key] = 'errorExplanation' + end + end + + error_messages = [] + for object in objects + object.errors.each do |attr, message| + error_messages << content_tag(:li, message) + end end - error_messages = objects.map {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } } + content_tag(:div, content_tag(:ul, error_messages), html ) else - '' + '' end end diff --git a/app/models/change_email_validator.rb b/app/models/change_email_validator.rb index 515747b22..f7ec6d17e 100644 --- a/app/models/change_email_validator.rb +++ b/app/models/change_email_validator.rb @@ -22,12 +22,17 @@ class ChangeEmailValidator < ActiveRecord::BaseWithoutTable column :old_email, :string column :new_email, :string column :password, :string + column :user_circumstance, :string attr_accessor :logged_in_user validates_presence_of :old_email, :message => N_("Please enter your old email address") validates_presence_of :new_email, :message => N_("Please enter your new email address") - validates_presence_of :password, :message => N_("Please enter your password") + validates_presence_of :password, :message => N_("Please enter your password"), :unless => :changing_email + + def changing_email() + self.user_circumstance == 'change_email' + end def validate if !self.old_email.blank? && !MySociety::Validate.is_valid_email(self.old_email) @@ -37,7 +42,7 @@ class ChangeEmailValidator < ActiveRecord::BaseWithoutTable if !errors[:old_email] if self.old_email.downcase != self.logged_in_user.email.downcase errors.add(:old_email, _("Old email address isn't the same as the address of the account you are logged in with")) - elsif !self.logged_in_user.has_this_password?(self.password) + elsif (!self.changing_email) && (!self.logged_in_user.has_this_password?(self.password)) if !errors[:password] errors.add(:password, _("Password is not correct")) end diff --git a/app/models/exim_log.rb b/app/models/exim_log.rb index 6bdcdf9c2..80535ab41 100644 --- a/app/models/exim_log.rb +++ b/app/models/exim_log.rb @@ -68,7 +68,6 @@ class EximLog < ActiveRecord::Base for email in emails info_request = InfoRequest.find_by_incoming_email(email) if !info_request.nil? - #STDERR.puts "adding log for " + info_request.url_title + " from " + file_name + " line " + line exim_log = EximLog.new exim_log.info_request = info_request exim_log.exim_log_done = done @@ -112,14 +111,13 @@ class EximLog < ActiveRecord::Base raise "unexpected parsing of exim line" end - #STDERR.puts "check_recent_requests_have_been_sent test: " + exim_log.line # debugging found = true end end if !found # It's very important the envelope from is set for avoiding spam filter reasons - this # effectively acts as a check for that. - STDERR.puts("failed to find request sending Exim line for request id " + ir.id.to_s + " " + ir.url_title + " (check envelope from is being set to request address in Ruby, and load-exim-logs crontab is working)") # *** don't comment out this STDERR line, it is the point of the function! + $stderr.puts("failed to find request sending Exim line for request id " + ir.id.to_s + " " + ir.url_title + " (check envelope from is being set to request address in Ruby, and load-exim-logs crontab is working)") # *** don't comment out this STDERR line, it is the point of the function! ok = false end end diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb index c808dc6a1..4d3c08df3 100644 --- a/app/models/incoming_message.rb +++ b/app/models/incoming_message.rb @@ -28,10 +28,11 @@ # Move some of the (e.g. quoting) functions here into rblib, as they feel # general not specific to IncomingMessage. +require 'alaveteli_file_types' +require 'external_command' require 'htmlentities' require 'rexml/document' require 'zip/zip' -require 'mahoro' require 'mapi/msg' require 'mapi/convert' @@ -44,128 +45,17 @@ module TMail end end -# To add an image, create a file with appropriate name corresponding to the -# mime type in public/images e.g. icon_image_tiff_large.png -$file_extension_to_mime_type = { - "txt" => 'text/plain', - "pdf" => 'application/pdf', - "rtf" => 'application/rtf', - "doc" => 'application/vnd.ms-word', - "docx" => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - "xls" => 'application/vnd.ms-excel', - "xlsx" => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - "ppt" => 'application/vnd.ms-powerpoint', - "pptx" => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - "oft" => 'application/vnd.ms-outlook', - "msg" => 'application/vnd.ms-outlook', - "tnef" => 'application/ms-tnef', - "tif" => 'image/tiff', - "gif" => 'image/gif', - "jpg" => 'image/jpeg', # XXX add jpeg - "png" => 'image/png', - "bmp" => 'image/bmp', - "html" => 'text/html', # XXX add htm - "vcf" => 'text/x-vcard', - "zip" => 'application/zip', - "delivery-status" => 'message/delivery-status' -} -# XXX doesn't have way of choosing default for inverse map - might want to add -# one when you need it -$file_extension_to_mime_type_rev = $file_extension_to_mime_type.invert - -# See binary_mask_stuff function below. It just test for inclusion -# in this hash, not the value of the right hand side. -$do_not_binary_mask = { - 'image/tiff' => 1, - 'image/gif' => 1, - 'image/jpeg' => 1, - 'image/png' => 1, - 'image/bmp' => 1, - 'application/zip' => 1, -} - -# Given file name and its content, return most likely type -def filename_and_content_to_mimetype(filename, content) - # Try filename - ret = filename_to_mimetype(filename) - if !ret.nil? - return ret - end - - # Otherwise look inside the file to work out the type. - # Mahoro is a Ruby binding for libmagic. - m = Mahoro.new(Mahoro::MIME) - mahoro_type = m.buffer(content) - mahoro_type.strip! - #STDERR.puts("mahoro", mahoro_type, "xxxok") - # XXX we shouldn't have to check empty? here, but Mahoro sometimes returns a blank line :( - # e.g. for InfoRequestEvent 17930 - if mahoro_type.nil? || mahoro_type.empty? - return nil - end - # text/plain types sometimes come with a charset - mahoro_type.match(/^(.*);/) - if $1 - mahoro_type = $1 - end - # see if looks like a content type, or has something in it that does - # and return that - # mahoro returns junk "\012- application/msword" as mime type. - mahoro_type.match(/([a-z0-9.-]+\/[a-z0-9.-]+)/) - if $1 - return $1 - end - # otherwise we got junk back from mahoro - return nil -end - -# XXX clearly this shouldn't be a global function, or the above global vars. -def filename_to_mimetype(filename) - if !filename - return nil - end - if filename.match(/\.([^.]+)$/i) - lext = $1.downcase - if $file_extension_to_mime_type.include?(lext) - return $file_extension_to_mime_type[lext] - end - end - return nil -end - -def mimetype_to_extension(mime) - if $file_extension_to_mime_type_rev.include?(mime) - return $file_extension_to_mime_type_rev[mime] - end - return nil -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' - 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 +# This is the type which is used to send data about attachments to the view +class FOIAttachment + attr_accessor :body + attr_accessor :content_type + attr_accessor :filename + attr_accessor :url_part_number + attr_accessor :within_rfc822_subject # we use the subject as the filename for email attachments -# List of DSN codes taken from RFC 3463 -# http://tools.ietf.org/html/rfc3463 -$dsn_to_message = { + # List of DSN codes taken from RFC 3463 + # http://tools.ietf.org/html/rfc3463 + DsnToMessage = { 'X.1.0' => 'Other address status', 'X.1.1' => 'Bad destination mailbox address', 'X.1.2' => 'Bad destination system address', @@ -213,15 +103,7 @@ $dsn_to_message = { 'X.7.5' => 'Cryptographic failure', 'X.7.6' => 'Cryptographic algorithm not supported', 'X.7.7' => 'Message integrity failure' -} - -# This is the type which is used to send data about attachments to the view -class FOIAttachment - attr_accessor :body - attr_accessor :content_type - attr_accessor :filename - attr_accessor :url_part_number - attr_accessor :within_rfc822_subject # we use the subject as the filename for email attachments + } # Returns HTML, of extra comment to put by attachment def extra_note @@ -235,8 +117,8 @@ class FOIAttachment dsn_part = 'X.' + $2 dsn_message = "" - if $dsn_to_message.include?(dsn_part) - dsn_message = " (" + $dsn_to_message[dsn_part] + ")" + if DsnToMessage.include?(dsn_part) + dsn_message = " (" + DsnToMessage[dsn_part] + ")" end return "<br><em>DSN: " + dsn + dsn_message + "</em>" @@ -279,7 +161,7 @@ class FOIAttachment end def _internal_display_filename - calc_ext = mimetype_to_extension(@content_type) + calc_ext = AlaveteliFileTypes.mimetype_to_extension(@content_type) if @filename # Put right extension on if missing @@ -312,65 +194,54 @@ class FOIAttachment end # Whether this type can be shown in the Google Docs Viewer. - # PDF, PowerPoint and TIFF are listed on https://docs.google.com/viewer - # .doc and .docx were added later http://gmailblog.blogspot.com/2010/06/view-doc-attachments-right-in-your.html - # .xls appears to work fine too + # The full list of supported types can be found at + # https://docs.google.com/support/bin/answer.py?hl=en&answer=1189935 def has_google_docs_viewer? - if self.content_type == 'application/vnd.ms-word' - return true - elsif self.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - return true - elsif self.content_type == 'application/pdf' - return true - elsif self.content_type == 'image/tiff' - return true - elsif self.content_type == 'application/vnd.ms-powerpoint' - return true - elsif self.content_type == 'application/vnd.ms-excel' - return true - end + return !! { + "application/pdf" => true, # .pdf + "image/tiff" => true, # .tiff + + "application/vnd.ms-word" => true, # .doc + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" => true, # .docx + + "application/vnd.ms-powerpoint" => true, # .ppt + "application/vnd.openxmlformats-officedocument.presentationml.presentation" => true, # .pptx + + "application/vnd.ms-excel" => true, # .xls + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" => true, # .xlsx + + } [self.content_type] end # Whether this type has a "View as HTML" def has_body_as_html? - if self.content_type == 'text/plain' - return true - elsif self.content_type == 'application/vnd.ms-word' - return true - elsif self.content_type == 'application/vnd.ms-excel' - return true - elsif self.content_type == 'application/pdf' - return true - elsif self.content_type == 'application/rtf' - return true - end - # We use the same "View as HTML" link to embed the Google Doc Viewer - # (when it can't do a conversion locally) - if self.has_google_docs_viewer? - return true - end - return false + return ( + !!{ + "text/plain" => true, + "application/rtf" => true, + }[self.content_type] or + self.has_google_docs_viewer? + ) end # Name of type of attachment type - only valid for things that has_body_as_html? def name_of_content_type - if self.content_type == 'text/plain' - return "Text file" - elsif self.content_type == 'application/vnd.ms-word' - return "Word document" - elsif self.content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - return "Word document - XML" - elsif self.content_type == 'application/vnd.ms-excel' - return "Excel spreadsheet" - elsif self.content_type == 'application/pdf' - return "PDF file" - elsif self.content_type == 'application/rtf' - return "RTF file" - elsif self.content_type == 'application/vnd.ms-powerpoint' - return "PowerPoint presentation" - elsif self.content_type == 'image/tiff' - return "TIFF image" - end + return { + "text/plain" => "Text file", + 'application/rtf' => "RTF file", + + 'application/pdf' => "PDF file", + 'image/tiff' => "TIFF image", + + 'application/vnd.ms-word' => "Word document", + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => "Word document", + + 'application/vnd.ms-powerpoint' => "PowerPoint presentation", + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => "PowerPoint presentation", + + 'application/vnd.ms-excel' => "Excel spreadsheet", + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => "Excel spreadsheet", + }[self.content_type] end # For "View as HTML" of attachment @@ -395,20 +266,6 @@ class FOIAttachment tempfile.print self.body tempfile.flush - # Use google docs for the view for these - hanging server - # if self.content_type == 'application/vnd.ms-word' - # # XXX do something with PNG files this spits out so they view too :) - # system("/usr/bin/wvHtml --charset=UTF-8 " + tempfile.path + " " + tempfile.path + ".html") - # html = File.read(tempfile.path + ".html") - # File.unlink(tempfile.path + ".html") -# elsif self.content_type == 'application/vnd.ms-excel' -# # Don't colorise, e.g. otherwise this one comes out with white -# # text which is nasty: -# # http://www.whatdotheyknow.com/request/30485/response/74705/attach/html/2/Empty%20premises%20Sefton.xls.html -# IO.popen("/usr/bin/xlhtml -nc -a " + tempfile.path + "", "r") do |child| -# html = child.read() -# wrapper_id = "wrapper_xlhtml" -# end if self.content_type == 'application/pdf' IO.popen("/usr/bin/pdftohtml -nodrm -zoom 1.0 -stdout -enc UTF-8 -noframes " + tempfile.path + "", "r") do |child| html = child.read() @@ -455,6 +312,7 @@ class FOIAttachment end + class IncomingMessage < ActiveRecord::Base belongs_to :info_request validates_presence_of :info_request @@ -467,6 +325,17 @@ class IncomingMessage < ActiveRecord::Base belongs_to :raw_email + # See binary_mask_stuff function below. It just test for inclusion + # in this hash, not the value of the right hand side. + DoNotBinaryMask = { + 'image/tiff' => 1, + 'image/gif' => 1, + 'image/jpeg' => 1, + 'image/png' => 1, + 'image/bmp' => 1, + 'application/zip' => 1, + } + # Return the structured TMail::Mail object # Documentation at http://i.loveruby.net/en/projects/tmail/doc/ def mail @@ -513,7 +382,7 @@ class IncomingMessage < ActiveRecord::Base # An email attached as text # e.g. http://www.whatdotheyknow.com/request/64/response/102 part.rfc822_attachment = TMail::Mail.parse(part.body) - elsif part.content_type == 'application/vnd.ms-outlook' || part_filename && filename_to_mimetype(part_filename) == 'application/vnd.ms-outlook' + 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)) @@ -571,7 +440,7 @@ class IncomingMessage < ActiveRecord::Base # See if content type is one that we mask - things like zip files and # images may get broken if we try to. We err on the side of masking too # much, as many unknown types will really be text. - if $do_not_binary_mask.include?(content_type) + if DoNotBinaryMask.include?(content_type) return end @@ -800,7 +669,6 @@ class IncomingMessage < ActiveRecord::Base return _get_attachment_leaves_recursive(self.mail) end def _get_attachment_leaves_recursive(curr_mail, within_rfc822_attachment = nil) - # STDERR.puts "_get_attachment_leaves_recursive", curr_mail.content_type, curr_mail.sub_type, curr_mail.multipart?, "\n" leaves_found = [] if curr_mail.multipart? if curr_mail.parts.size == 0 @@ -846,7 +714,7 @@ class IncomingMessage < ActiveRecord::Base # PDFs often come with this mime type, fix it up for view code if curr_mail.content_type == 'application/octet-stream' part_file_name = self._get_censored_part_file_name(curr_mail) - calc_mime = filename_and_content_to_mimetype(part_file_name, curr_mail.body) + calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(part_file_name, curr_mail.body) if calc_mime curr_mail.content_type = calc_mime end @@ -949,7 +817,7 @@ class IncomingMessage < ActiveRecord::Base # e.g. http://www.whatdotheyknow.com/request/35/response/177 # XXX This is a bit of a hack as it is calling a convert to text routine. # Could instead call a sanitize HTML one. - text = IncomingMessage._get_attachment_text_internal_one_file(part.content_type, text) + text = self.class._get_attachment_text_internal_one_file(part.content_type, text) end end @@ -1027,7 +895,7 @@ class IncomingMessage < ActiveRecord::Base # ... or if none, consider first part p = leaves[0] # if it is a known type then don't use it, return no body (nil) - if mimetype_to_extension(p.content_type) + if AlaveteliFileTypes.mimetype_to_extension(p.content_type) # this is guess of case where there are only attachments, no body text # e.g. http://www.whatdotheyknow.com/request/cost_benefit_analysis_for_real_n return nil @@ -1067,7 +935,7 @@ class IncomingMessage < ActiveRecord::Base attachment.body = content attachment.filename = uu.match(/^begin\s+[0-9]+\s+(.*)$/)[1] self.info_request.apply_censor_rules_to_text!(attachment.filename) - calc_mime = filename_and_content_to_mimetype(attachment.filename, attachment.body) + calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(attachment.filename, attachment.body) if calc_mime calc_mime = normalise_content_type(calc_mime) attachment.content_type = calc_mime @@ -1238,54 +1106,42 @@ class IncomingMessage < ActiveRecord::Base tempfile.print body tempfile.flush if content_type == 'application/vnd.ms-word' - system("/usr/bin/wvText " + tempfile.path + " " + tempfile.path + ".txt") + external_command("/usr/bin/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") - IO.popen("/usr/bin/catdoc " + tempfile.path, "r") do |child| - text += child.read() + "\n\n" - end + external_command("/usr/bin/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 - IO.popen("/usr/bin/catdoc " + tempfile.path, "r") do |child| - text += child.read() + "\n\n" - end + external_command("/usr/bin/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 WhatDoTheyKnow. We use elinks instead, which doesn't do that. - IO.popen("/usr/bin/elinks -dump-charset utf-8 -force-html -dump " + tempfile.path, "r") do |child| - text += child.read() + "\n\n" - end + external_command("/usr/bin/elinks", "-dump-charset", "utf-8", "-force-html", "-dump", + tempfile.path, :append_to => text) 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. - IO.popen("/usr/bin/strings " + tempfile.path, "r") do |child| - text += child.read() + "\n\n" - end + external_command("/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 - IO.popen("/usr/bin/catppt " + tempfile.path, "r") do |child| - text += child.read() + "\n\n" - end + external_command("/usr/bin/catppt", tempfile.path, :append_to => text) elsif content_type == 'application/pdf' - IO.popen("/usr/bin/pdftotext " + tempfile.path + " -", "r") do |child| - text += child.read() + "\n\n" - end + external_command("/usr/bin/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 = '' - IO.popen("/usr/bin/unzip -qq -c " + tempfile.path + " word/document.xml", "r") do |child| - xml += child.read() + "\n\n" + xml = external_command("/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 - doc = REXML::Document.new(xml) - text += doc.each_element( './/text()' ){}.join(" ") elsif content_type == 'application/zip' # recurse into zip files zip_file = Zip::ZipFile.open(tempfile.path) @@ -1300,15 +1156,14 @@ class IncomingMessage < ActiveRecord::Base # e.g. password protected next end - calc_mime = filename_to_mimetype(filename) + calc_mime = AlaveteliFileTypes.filename_to_mimetype(filename) if calc_mime content_type = calc_mime else content_type = 'application/octet-stream' end - #STDERR.puts("doing file " + filename + " content type " + content_type) - text += IncomingMessage._get_attachment_text_internal_one_file(content_type, body) + text += _get_attachment_text_internal_one_file(content_type, body) end end end @@ -1383,9 +1238,9 @@ class IncomingMessage < ActiveRecord::Base for incoming_message in IncomingMessage.find(:all) for attachment in incoming_message.get_attachments_for_display raise "internal error incoming_message " + incoming_message.id.to_s if attachment.content_type.nil? - if mimetype_to_extension(attachment.content_type).nil? - STDERR.puts "Unknown type for /request/" + incoming_message.info_request.id.to_s + "#incoming-"+incoming_message.id.to_s - STDERR.puts " " + attachment.filename.to_s + " " + attachment.content_type.to_s + if AlaveteliFileTypes.mimetype_to_extension(attachment.content_type).nil? + $stderr.puts "Unknown type for /request/" + incoming_message.info_request.id.to_s + "#incoming-"+incoming_message.id.to_s + $stderr.puts " " + attachment.filename.to_s + " " + attachment.content_type.to_s end end end @@ -1398,15 +1253,15 @@ class IncomingMessage < ActiveRecord::Base def get_present_file_extensions ret = {} for attachment in self.get_attachments_for_display - ext = mimetype_to_extension(attachment.content_type) + ext = AlaveteliFileTypes.mimetype_to_extension(attachment.content_type) ext = File.extname(attachment.filename).gsub(/^[.]/, "") if ext.nil? && !attachment.filename.nil? ret[ext] = 1 if !ext.nil? end return ret.keys.join(" ") end # Return space separated list of all file extensions known - def IncomingMessage.get_all_file_extentions - return $file_extension_to_mime_type.keys.join(" ") + def IncomingMessage.get_all_file_extensions + return AlaveteliFileTypes.all_extensions.join(" ") end # Return false if for some reason this is a message that we shouldn't let them reply to @@ -1432,6 +1287,59 @@ class IncomingMessage < ActiveRecord::Base 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' + 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 + private :normalise_content_type + + def self.external_command(program_name, *args) + # Run an external program, and return its output. + # Standard error is suppressed unless the program + # fails (i.e. returns a non-zero exit status). + opts = {} + if !args.empty? && args[-1].is_a?(Hash) + opts = args.pop + end + + xc = ExternalCommand.new(program_name, *args) + if opts.has_key? :append_to + xc.out = opts[:append_to] + end + xc.run() + if xc.status != 0 + # Error + $stderr.puts("Error from #{program_name} #{args.join(' ')}:") + $stderr.print(xc.err) + return nil + else + if opts.has_key? :append_to + opts[:append_to] << "\n\n" + else + return xc.out + end + end + end + private_class_method :external_command end diff --git a/app/models/info_request.rb b/app/models/info_request.rb index 4e669e5cd..a36b140b8 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -535,7 +535,6 @@ public if curr_state.nil? if !event.described_state.nil? curr_state = event.described_state - #STDERR.puts "curr_state " + curr_state end end diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 3d2b180b8..b68722b81 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -46,28 +46,34 @@ class PublicBody < ActiveRecord::Base translates :name, :short_name, :request_email, :url_name, :notes, :first_letter, :publication_scheme + # Make sure publication_scheme gets the correct default value. + # (This would work automatically, were publication_scheme not a translated attribute) + def after_initialize + self.publication_scheme = "" if self.publication_scheme.nil? + end + # like find_by_url_name but also search historic url_name if none found def self.find_by_url_name_with_historic(name) @localer = I18n.locale.to_s PublicBody.with_locale(@locale) do found = PublicBody.find(:all, - :conditions => ["public_body_translations.url_name='#{name}' AND public_body_translations.locale = '#{@localer}'"], - :joins => :translations) - return found.first if found.size == 1 - # Shouldn't we just make url_name unique? - raise "Two bodies with the same URL name: #{name}" 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 + :conditions => ["public_body_translations.url_name='#{name}' AND public_body_translations.locale = '#{@localer}'"], + :joins => :translations) + return found.first if found.size == 1 + # Shouldn't we just make url_name unique? + raise "Two bodies with the same URL name: #{name}" 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 end diff --git a/app/models/request_mailer.rb b/app/models/request_mailer.rb index 910f38cbe..e73b153b9 100644 --- a/app/models/request_mailer.rb +++ b/app/models/request_mailer.rb @@ -6,6 +6,8 @@ # # $Id: request_mailer.rb,v 1.89 2009-10-04 21:53:54 francis Exp $ +require 'alaveteli_file_types' + class RequestMailer < ApplicationMailer # Used when an FOI officer uploads a response from their web browser - this is @@ -18,13 +20,7 @@ class RequestMailer < ApplicationMailer :body => body } if !attachment_name.nil? && !attachment_content.nil? - IncomingMessage # load global filename_to_mimetype XXX should move filename_to_mimetype to proper namespace - calc_mime = filename_to_mimetype(attachment_name) - if calc_mime - content_type = calc_mime - else - content_type = 'application/octet-stream' - end + content_type = AlaveteliFileTypes.filename_to_mimetype(attachment_name) || 'application/octet-stream' attachment :content_type => content_type, :body => attachment_content, @@ -230,7 +226,6 @@ class RequestMailer < ApplicationMailer # Send email alerts for overdue requests def self.alert_overdue_requests() - #STDERR.puts "alert_overdue_requests" info_requests = InfoRequest.find(:all, :conditions => [ "described_state = 'waiting_response' and awaiting_description = ?", false ], :include => [ :user ] ) for info_request in info_requests alert_event_id = info_request.last_event_forming_initial_request.id @@ -248,7 +243,6 @@ class RequestMailer < ApplicationMailer sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = ? and user_id = ? and info_request_id = ? and info_request_event_id = ?", alert_type, info_request.user_id, info_request.id, alert_event_id]) if sent_already.nil? # Alert not yet sent for this user, so send it - #STDERR.puts "sending overdue alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s + " event " + alert_event_id store_sent = UserInfoRequestSentAlert.new store_sent.info_request = info_request store_sent.user = info_request.user @@ -266,7 +260,6 @@ class RequestMailer < ApplicationMailer end end store_sent.save! - #STDERR.puts "sent " + info_request.user.email end end end @@ -280,7 +273,6 @@ class RequestMailer < ApplicationMailer self.alert_new_response_reminders_internal(24, 'new_response_reminder_3') end def self.alert_new_response_reminders_internal(days_since, type_code) - #STDERR.puts "alert_new_response_reminders_internal days:" + days_since.to_s + " type: " + type_code info_requests = InfoRequest.find_old_unclassified(:order => 'info_requests.id', :include => [:user], :age_in_days => days_since) @@ -295,7 +287,6 @@ class RequestMailer < ApplicationMailer sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = ? and user_id = ? and info_request_id = ? and info_request_event_id = ?", type_code, info_request.user_id, info_request.id, alert_event_id]) if sent_already.nil? # Alert not yet sent for this user - #STDERR.puts "sending " + type_code + " alert to info_request " + info_request.url_title + " user " + info_request.user.url_name + " event " + alert_event_id.to_s store_sent = UserInfoRequestSentAlert.new store_sent.info_request = info_request store_sent.user = info_request.user @@ -304,7 +295,6 @@ class RequestMailer < ApplicationMailer # XXX uses same template for reminder 1 and reminder 2 right now. RequestMailer.deliver_new_response_reminder_alert(info_request, last_response_message) store_sent.save! - #STDERR.puts "sent " + info_request.user.email end end end @@ -312,7 +302,6 @@ class RequestMailer < ApplicationMailer # Send email alerts for requests which need clarification. Goes out 3 days # after last update of event. def self.alert_not_clarified_request() - #STDERR.puts "alert_not_clarified_request" info_requests = InfoRequest.find(:all, :conditions => [ "awaiting_description = ? and described_state = 'waiting_clarification' and info_requests.updated_at < ?", false, Time.now() - 3.days ], :include => [ :user ], :order => "info_requests.id" ) for info_request in info_requests alert_event_id = info_request.get_last_response_event_id @@ -324,7 +313,6 @@ class RequestMailer < ApplicationMailer sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = 'not_clarified_1' and user_id = ? and info_request_id = ? and info_request_event_id = ?", info_request.user_id, info_request.id, alert_event_id]) if sent_already.nil? # Alert not yet sent for this user - #STDERR.puts "sending clarification reminder alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s + " event " + alert_event_id.to_s store_sent = UserInfoRequestSentAlert.new store_sent.info_request = info_request store_sent.user = info_request.user @@ -336,14 +324,12 @@ class RequestMailer < ApplicationMailer RequestMailer.deliver_not_clarified_alert(info_request, last_response_message) end store_sent.save! - #STDERR.puts "sent " + info_request.user.email end end end # Send email alert to request submitter for new comments on the request. def self.alert_comment_on_request() - #STDERR.puts "alert_comment_on_request" # We only check comments made in the last month - this means if the # cron jobs broke for more than a month events would be lost, but no @@ -359,22 +345,18 @@ class RequestMailer < ApplicationMailer info_requests = InfoRequest.find(:all, :conditions => [ "(select id from info_request_events where event_type = 'comment' and info_request_events.info_request_id = info_requests.id and created_at > ? limit 1) is not null", Time.now() - 1.month ], :include => [ { :info_request_events => :user_info_request_sent_alerts } ], :order => "info_requests.id, info_request_events.created_at" ) for info_request in info_requests - #STDERR.puts "considering request " + info_request.id.to_s # Count number of new comments to alert on earliest_unalerted_comment_event = nil last_comment_event = nil count = 0 for e in info_request.info_request_events.reverse - #STDERR.puts "event " + e.id.to_s + " type " + e.event_type # alert on comments, which were not made by the user who originally made the request if e.event_type == 'comment' && e.comment.user_id != info_request.user_id last_comment_event = e if last_comment_event.nil? alerted_for = e.user_info_request_sent_alerts.find(:first, :conditions => [ "alert_type = 'comment_1' and user_id = ?", info_request.user_id]) - #STDERR.puts "is comment by other user, alerted_for " + alerted_for.to_s + " comment user " + e.comment.user_id.to_s + " request user " + info_request.user_id.to_s + " body: " + e.comment.body if alerted_for.nil? - # STDERR.puts "nil!" count = count + 1 earliest_unalerted_comment_event = e else @@ -382,7 +364,6 @@ class RequestMailer < ApplicationMailer end end end - #STDERR.puts "earliest_unalerted_comment_event " + earliest_unalerted_comment_event.to_s # Alert needs sending if there are new comments if count > 0 @@ -392,16 +373,13 @@ class RequestMailer < ApplicationMailer store_sent.alert_type = 'comment_1' store_sent.info_request_event_id = last_comment_event.id if count > 1 - #STDERR.puts "sending multiple comment on request alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s + " count " + count.to_s + " earliest " + earliest_unalerted_comment_event.id.to_s RequestMailer.deliver_comment_on_alert_plural(info_request, count, earliest_unalerted_comment_event.comment) elsif count == 1 - #STDERR.puts "sending comment on request alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s + " event " + last_comment_event.id.to_s RequestMailer.deliver_comment_on_alert(info_request, last_comment_event.comment) else raise "internal error" end store_sent.save! - #STDERR.puts "sent " + info_request.user.email end end end diff --git a/app/models/track_mailer.rb b/app/models/track_mailer.rb index 6c9d9949b..1b37709b9 100644 --- a/app/models/track_mailer.rb +++ b/app/models/track_mailer.rb @@ -32,14 +32,13 @@ class TrackMailer < ApplicationMailer def self.alert_tracks now = Time.now() users = User.find(:all, :conditions => [ "last_daily_track_email < ?", now - 1.day ]) + if users.empty? + return false + end for user in users - #STDERR.puts Time.now.to_s + " user " + user.url_name - email_about_things = [] track_things = TrackThing.find(:all, :conditions => [ "tracking_user_id = ? and track_medium = ?", user.id, 'email_daily' ]) for track_thing in track_things - #STDERR.puts Time.now.to_s + " track " + track_thing.track_query - # What have we alerted on already? # # We only use track_things_sent_emails records which are less than 14 days old. @@ -81,15 +80,6 @@ class TrackMailer < ApplicationMailer # If we have anything to send, then send everything for the user in one mail if email_about_things.size > 0 - # Debugging - # STDERR.puts "sending email alert for user " + user.url_name - # for track_thing, alert_results, xapian_object in email_about_things - # STDERR.puts " tracking " + track_thing.track_query - # for result in alert_results.reverse - # STDERR.puts " result " + result[:model].class.to_s + " id " + result[:model].id.to_s - # end - # end - # Send the email TrackMailer.deliver_event_digest(user, email_about_things) end @@ -111,6 +101,19 @@ class TrackMailer < ApplicationMailer user.no_xapian_reindex = true user.save! end + return true + end + + def self.alert_tracks_loop + # Run alert_tracks in an endless loop, sleeping when there is nothing to do + while true + sleep_seconds = 1 + while !alert_tracks + sleep sleep_seconds + sleep_seconds *= 2 + sleep_seconds = 300 if sleep_seconds > 300 + end + end end end diff --git a/app/views/comment/_comment_form.rhtml b/app/views/comment/_comment_form.rhtml index 8ca30324c..d430f25c8 100644 --- a/app/views/comment/_comment_form.rhtml +++ b/app/views/comment/_comment_form.rhtml @@ -1,7 +1,6 @@ <% form_for(:comment, @comment, :url => { :controller => "comment", :action => "new", :type => "request" }, :html => { :id => 'comment_form' } ) do |f| %> <p> <%= f.text_area :body, :rows => 10, :cols => 55 %> - <br><script type="text/javascript">document.write('<input name="doSpell" type="button" value="Check spelling" onClick="openSpellChecker(document.getElementById(\'comment_form\').body);"/> (optional)')</script> </p> <% if !TrackThing.find_by_existing_track(@user, track_thing) && (!@user || @info_request.user != @user) %> diff --git a/app/views/general/frontpage.rhtml b/app/views/general/frontpage.rhtml index 032a8b222..f1bee3ba1 100644 --- a/app/views/general/frontpage.rhtml +++ b/app/views/general/frontpage.rhtml @@ -16,8 +16,8 @@ <%= submit_tag _('Search') %> <br> <%= _('e.g.') %> - <% @popular_bodies.each_with_index do |body, i| %> - <%=link_to body.name, search_url(body.name, 'bodies')%><% if i < 2 %>, <% else %>. <% break %><% end %> + <% @search_examples.each_with_index do |name, i| %> + <%=link_to name, search_url(name, 'bodies')%><% if i < 2 %>, <% else %>. <% break %><% end %> <% end %> <br> diff --git a/app/views/general/search.rhtml b/app/views/general/search.rhtml index 876d54270..a4680c0f6 100644 --- a/app/views/general/search.rhtml +++ b/app/views/general/search.rhtml @@ -4,7 +4,7 @@ <% @title = _("Search Freedom of Information requests, public authorities and users") %> <h1><%=@title%></h1> <% elsif @total_hits == 0 %> - <%= _("Nothing found for '{{search_terms}}'", :search_terms => h(@query)) %> + <%= _("Nothing found for ‘{{search_terms}}’", :search_terms => h(@query)) %> <% else %> <% @title = _("Results page {{page_number}}", :page_number => @page.to_s) %> <% end%> @@ -67,7 +67,11 @@ <% end %> <% if @xapian_bodies.results.size > 0 %> - <h1><%= _('Public authorities {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}', :start_count => ((@page-1)*@bodies_per_page+1).to_s, :end_count => [@page*@bodies_per_page, @xapian_bodies.matches_estimated].min.to_s, :total_count => @xapian_bodies.matches_estimated.to_s, :user_search_query => h(@query)) %></h1> + <% if @xapian_bodies.results.size == 1 && @page == 1 %> + <h1><%= _('One public authority matching ‘{{user_search_query}}’', :user_search_query => h(@query)) %></h1> + <% else %> + <h1><%= _('Public authorities {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}', :start_count => ((@page-1)*@bodies_per_page+1).to_s, :end_count => [@page*@bodies_per_page, @xapian_bodies.matches_estimated].min.to_s, :total_count => @xapian_bodies.matches_estimated.to_s, :user_search_query => h(@query)) %></h1> + <% end %> <% for result in @xapian_bodies.results %> <%= render :partial => 'public_body/body_listing_single', :locals => { :public_body => result[:model] } %> @@ -77,7 +81,11 @@ <% end %> <% if @xapian_users.results.size > 0 %> - <h1><%= _("People {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}", :start_count => ((@page-1)*@users_per_page+1).to_s, :end_count => [@page*@users_per_page, @xapian_users.matches_estimated].min.to_s, :total_count => @xapian_users.matches_estimated.to_s, :user_search_query => h(@query)) %></h1> + <% if @xapian_users.results.size == 1 && @page == 1 %> + <h1><%= _("One person matching ‘{{user_search_query}}’", :user_search_query => h(@query)) %></h1> + <% else %> + <h1><%= _("People {{start_count}} to {{end_count}} of {{total_count}} for ‘{{user_search_query}}’", :start_count => ((@page-1)*@users_per_page+1).to_s, :end_count => [@page*@users_per_page, @xapian_users.matches_estimated].min.to_s, :total_count => @xapian_users.matches_estimated.to_s, :user_search_query => h(@query)) %></h1> + <% end %> <% for result in @xapian_users.results %> <%= render :partial => 'user/user_listing_single', :locals => { :display_user => result[:model] } %> @@ -87,7 +95,11 @@ <% end %> <% if @xapian_requests.results.size > 0 %> - <h1><%= _("FOI requests {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}", :start_count => ((@page-1)*@requests_per_page+1).to_s, :end_count => [@page*@requests_per_page, @xapian_requests.matches_estimated].min.to_s, :total_count => @xapian_requests.matches_estimated.to_s, :user_search_query => h(@query)) %></h1> + <% if @xapian_requests.results.size == 1 && @page == 1 %> + <h1><%= _("One FOI request matching ‘{{user_search_query}}’", :user_search_query => h(@query)) %></h1> + <% else %> + <h1><%= _("FOI requests {{start_count}} to {{end_count}} of {{total_count}} for ‘{{user_search_query}}’", :start_count => ((@page-1)*@requests_per_page+1).to_s, :end_count => [@page*@requests_per_page, @xapian_requests.matches_estimated].min.to_s, :total_count => @xapian_requests.matches_estimated.to_s, :user_search_query => h(@query)) %></h1> + <% end %> <% if @track_thing %> <%= render :partial => 'track/tracking_links', :locals => { :track_thing => @track_thing, :own_request => false, :location => 'main' } %> @@ -117,7 +129,7 @@ <li><%= _('<strong><code>requested_by:julian_todd</code></strong> to search requests made by Julian Todd, typing the name as in the URL.') %></li> <li><%= _('<strong><code>commented_by:tony_bowden</code></strong> to search annotations made by Tony Bowden, typing the name as in the URL.')%></li> <li><%= _('<strong><code>request:</code></strong> to restrict to a specific request, typing the title as in the URL.')%> - <li><%= _('<strong><code>filetype:pdf</code></strong> to find all responses with PDF attachments. Or try these: <code>{{list_of_file_extensions}}</code>', :list_of_file_extensions => IncomingMessage.get_all_file_extentions)%></li> + <li><%= _('<strong><code>filetype:pdf</code></strong> to find all responses with PDF attachments. Or try these: <code>{{list_of_file_extensions}}</code>', :list_of_file_extensions => IncomingMessage.get_all_file_extensions)%></li> <li><%= _('Type <strong><code>01/01/2008..14/01/2008</code></strong> to only show things that happened in the first two weeks of January.')%></li> <li><%= _('<strong><code>tag:charity</code></strong> to find all public bodies or requests with a given tag. You can include multiple tags, and tag values, e.g. <code>tag:openlylocal AND tag:financial_transaction:335633</code>. Note that by default any of the tags @@ -126,7 +138,6 @@ </ul> <h2 id="statuses"><%= _('Table of statuses') %></h2> - <h3>XXX this should be automatically generated</h3> <table class="status_table"> <tr><td><strong><%=search_link('status:waiting_response')%></strong></td><td> Waiting for the public authority to reply </td></tr> <tr><td><strong><%=search_link('status:not_held')%></strong></td><td> The public authority does not have the information requested </td></tr> diff --git a/app/views/layouts/admin.rhtml b/app/views/layouts/admin.rhtml index a209715e1..5fe75fc97 100644 --- a/app/views/layouts/admin.rhtml +++ b/app/views/layouts/admin.rhtml @@ -8,12 +8,11 @@ <body> <p> - <strong><%= link_to 'WhatDoTheyKnow', main_url('/') %> admin:</strong> + <strong><%= link_to 'Alaveteli', main_url('/') %> admin:</strong> <%= link_to 'Summary', admin_general_index_path %> | <%= link_to 'Timeline', admin_timeline_path %> | <%= link_to 'Stats', admin_stats_path %> | <%= link_to 'Debug', admin_debug_path %> - | <%= link_to 'Wiki', "https://secure.mysociety.org/intranet/ProductionSites/WhatDoTheyKnow/WebHome" %> <strong>View:</strong> <%= link_to 'Authorities', admin_body_list_path %> | <%= link_to 'Requests', admin_request_list_path %> diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml index 8b6ce4f1a..c193d0c1b 100644 --- a/app/views/layouts/default.rhtml +++ b/app/views/layouts/default.rhtml @@ -1,8 +1,6 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="<%= I18n.locale %>"> <head> - <script type="text/javascript" src="/jslib/spell/spellChecker.js"></script> - <% if @profile_photo_javascript %> <script type="text/javascript" src="/javascripts/jquery.js"></script> <script type="text/javascript" src="/javascripts/jquery.Jcrop.js"></script> diff --git a/app/views/public_body/show.rhtml b/app/views/public_body/show.rhtml index d3c299140..dce7ca4f8 100644 --- a/app/views/public_body/show.rhtml +++ b/app/views/public_body/show.rhtml @@ -11,7 +11,6 @@ <% end %> <% if @public_body.has_tag?("charity") %> <% for tag_value in @public_body.get_tag_values("charity") %> - XXX UK-specific <% if tag_value.match(/^SC/) %> <%= link_to _('Charity registration'), "http://www.oscr.org.uk/CharityIndexDetails.aspx?id=" + tag_value %><br> <% else %> @@ -68,7 +67,6 @@ <% if @xapian_requests.results.empty? %> <% if @public_body.eir_only? %> <h2><%= _('Environmental Information Regulations requests made using this site') %></h2> - <h4><%= _('XXX this section needs localising re EIR as these are specific to UK law') %></h4> <p>Nobody has made any Environmental Information Regulations requests to <%=h(@public_body.name)%> using this site yet.</p> <% else %> <h2><%= _('Freedom of Information requests made using this site')%></h2> diff --git a/app/views/request/_followup.rhtml b/app/views/request/_followup.rhtml index 393233682..8c279d234 100644 --- a/app/views/request/_followup.rhtml +++ b/app/views/request/_followup.rhtml @@ -53,7 +53,6 @@ <% form_for(:outgoing_message, @outgoing_message, :html => { :id => 'followup_form' }, :url => incoming_message.nil? ? show_response_no_followup_url(:id => @info_request.id) : show_response_url(:id => @info_request.id, :incoming_message_id => incoming_message.id)) do |o| %> <p> <%= o.text_area :body, :rows => 15, :cols => 55 %> - <br><script type="text/javascript">document.write('<input name="doSpell" type="button" value="Check spelling" onClick="openSpellChecker(document.getElementById(\'followup_form\').body);"/> (optional)')</script> </p> <% if @internal_review %> @@ -62,9 +61,9 @@ <h3><%= _('What are you doing?') %></h3> <% if !@outgoing_message.errors[:what_doing_dummy].nil? %> - <div class="fieldWithErrors"> + <div class="fieldWithErrors"> <% else %> - <div> + <div> <% end %> <!-- <div> diff --git a/app/views/request/new.rhtml b/app/views/request/new.rhtml index 5925ca3fb..a97116aa3 100644 --- a/app/views/request/new.rhtml +++ b/app/views/request/new.rhtml @@ -110,10 +110,6 @@ <%= o.text_area :body, :rows => 20, :cols => 60 %> </p> <% end %> - - <div class="form_button"> - <script type="text/javascript">document.write('<input name="doSpell" type="button" value="Check spelling" onClick="openSpellChecker(document.getElementById(\'write_form\').body);"/> (optional)')</script> - </div> <% if !@user %> <p class="form_note"> diff --git a/app/views/track_mailer/event_digest.rhtml b/app/views/track_mailer/event_digest.rhtml index e40dd5d3f..df27a5cbd 100644 --- a/app/views/track_mailer/event_digest.rhtml +++ b/app/views/track_mailer/event_digest.rhtml @@ -57,8 +57,6 @@ main_text += "\n" end - #STDERR.puts main_text - #STDERR.puts @unsubscribe_url %><%=main_text%>Alter your subscription ======================= |