diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/actionmailer_patches.rb | 15 | ||||
-rw-r--r-- | lib/alaveteli_external_command.rb | 6 | ||||
-rw-r--r-- | lib/i18n_fixes.rb | 2 | ||||
-rw-r--r-- | lib/mail_handler/mail_handler.rb | 2 | ||||
-rw-r--r-- | lib/quiet_opener.rb | 37 | ||||
-rw-r--r-- | lib/tasks/import.rake | 12 | ||||
-rw-r--r-- | lib/tasks/themes.rake | 138 | ||||
-rw-r--r-- | lib/tasks/translation.rake | 7 | ||||
-rw-r--r-- | lib/world_foi_websites.rb | 15 | ||||
-rw-r--r-- | lib/xapian_queries.rb | 85 |
10 files changed, 224 insertions, 95 deletions
diff --git a/lib/actionmailer_patches.rb b/lib/actionmailer_patches.rb deleted file mode 100644 index 600d3c8cc..000000000 --- a/lib/actionmailer_patches.rb +++ /dev/null @@ -1,15 +0,0 @@ -# Monkey patch for CVE-2013-4389 -# derived from http://seclists.org/oss-sec/2013/q4/118 to fix -# a possible DoS vulnerability in the log subscriber component of -# Action Mailer. - -require 'action_mailer' -module ActionMailer - class LogSubscriber < ActiveSupport::LogSubscriber - def deliver(event) - recipients = Array.wrap(event.payload[:to]).join(', ') - info("\nSent mail to #{recipients} (#{event.duration.round(1)}ms)") - debug(event.payload[:mail]) - end - end -end diff --git a/lib/alaveteli_external_command.rb b/lib/alaveteli_external_command.rb index fbdee8a62..086a461c8 100644 --- a/lib/alaveteli_external_command.rb +++ b/lib/alaveteli_external_command.rb @@ -44,7 +44,11 @@ module AlaveteliExternalCommand end xc.run(opts[:stdin_string] || "", opts[:env] || {}) - if xc.status != 0 + if !xc.exited + # Crash or timeout + $stderr.puts("#{program_name} #{args.join(' ')}:exited abnormally") + return nil + elsif xc.status != 0 # Error $stderr.puts("Error from #{program_name} #{args.join(' ')}:") $stderr.print(xc.err) diff --git a/lib/i18n_fixes.rb b/lib/i18n_fixes.rb index 9f0849e75..64c370477 100644 --- a/lib/i18n_fixes.rb +++ b/lib/i18n_fixes.rb @@ -35,7 +35,7 @@ def gettext_interpolate(string, values) pattern, key = $1, $1.to_sym if !values.include?(key) - raise I18n::MissingInterpolationArgument.new(pattern, string) + raise I18n::MissingInterpolationArgument.new(pattern, string, values) else v = values[key].to_s if safe && !v.html_safe? diff --git a/lib/mail_handler/mail_handler.rb b/lib/mail_handler/mail_handler.rb index 918f91180..53033d440 100644 --- a/lib/mail_handler/mail_handler.rb +++ b/lib/mail_handler/mail_handler.rb @@ -59,7 +59,7 @@ module MailHandler end # e.g. http://www.whatdotheyknow.com/request/copy_of_current_swessex_scr_opt#incoming-9928 - if content_type == 'application/acrobat' + if content_type == 'application/acrobat' or content_type == 'document/pdf' content_type = 'application/pdf' end diff --git a/lib/quiet_opener.rb b/lib/quiet_opener.rb index ae6605c43..16ea27b8e 100644 --- a/lib/quiet_opener.rb +++ b/lib/quiet_opener.rb @@ -1,6 +1,8 @@ require 'open-uri' require 'net-purge' -require 'net/http/local' +if RUBY_VERSION.to_f < 2.0 + require 'net/http/local' +end def quietly_try_to_open(url) begin @@ -12,17 +14,36 @@ def quietly_try_to_open(url) return result end +# On Ruby versions before 2.0, we need to use the net-http-local gem +# to force the use of 127.0.0.1 as the local interface for the +# connection. However, at the time of writing this gem doesn't work +# on Ruby 2.0 and it's not necessary with that Ruby version - one can +# supply a :local_host option to Net::HTTP:start. So, this helper +# function is to abstract away that difference, and can be used as you +# would Net::HTTP.start(host) when passed a block. +def http_from_localhost(host) + if RUBY_VERSION.to_f >= 2.0 + Net::HTTP.start(host, :local_host => '127.0.0.1') do |http| + yield http + end + else + Net::HTTP.bind '127.0.0.1' do + Net::HTTP.start(host) do |http| + yield http + end + end + end +end + def quietly_try_to_purge(host, url) begin result = "" result_body = "" - Net::HTTP.bind '127.0.0.1' do - Net::HTTP.start(host) {|http| - request = Net::HTTP::Purge.new(url) - response = http.request(request) - result = response.code - result_body = response.body - } + http_from_localhost(host) do |http| + request = Net::HTTP::Purge.new(url) + response = http.request(request) + result = response.code + result_body = response.body end rescue OpenURI::HTTPError, SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET, Errno::ENETUNREACH Rails.logger.warn("PURGE: Unable to reach host #{host}") diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index 0e8397fde..c8183c745 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -54,12 +54,12 @@ namespace :import do STDERR.puts "Now importing the public bodies..." # Now it's (probably) safe to try to import: - errors, notes = PublicBody.import_csv(tmp_csv.path, - tag='', - tag_behaviour='replace', - dryrun, - editor="#{ENV['USER']} (Unix user)", - I18n.available_locales) do |row_number, fields| + errors, notes = PublicBody.import_csv_from_file(tmp_csv.path, + tag='', + tag_behaviour='replace', + dryrun, + editor="#{ENV['USER']} (Unix user)", + I18n.available_locales) do |row_number, fields| percent_complete = (100 * row_number.to_f / number_of_rows).to_i STDERR.print "#{row_number} out of #{number_of_rows} " STDERR.puts "(#{percent_complete}% complete)" diff --git a/lib/tasks/themes.rake b/lib/tasks/themes.rake index 65b142a63..4a864d141 100644 --- a/lib/tasks/themes.rake +++ b/lib/tasks/themes.rake @@ -1,104 +1,123 @@ +require Rails.root.join('commonlib', 'rblib', 'git') + namespace :themes do - def plugin_dir + # Alias the module so we don't need the MySociety prefix here + Git = MySociety::Git + + def all_themes_dir File.join(Rails.root,"lib","themes") end def theme_dir(theme_name) - File.join(plugin_dir, theme_name) + File.join(all_themes_dir, theme_name) end - def old_theme_dir(theme_name) + def old_all_themes_dir(theme_name) File.join(Rails.root, "vendor", "plugins", theme_name) end def possible_theme_dirs(theme_name) - [theme_dir(theme_name), old_theme_dir(theme_name)] - end - - def checkout(commitish) - puts "Checking out #{commitish}" if verbose - system "git checkout #{commitish}" + [theme_dir(theme_name), old_all_themes_dir(theme_name)] end - def checkout_tag(version) - checkout usage_tag(version) - end - - def checkout_remote_branch(branch) - checkout "origin/#{branch}" + def installed?(theme_name) + possible_theme_dirs(theme_name).any? { |dir| File.directory? dir } end def usage_tag(version) "use-with-alaveteli-#{version}" end - def install_theme_using_git(name, uri, verbose=false, options={}) - install_path = theme_dir(name) - Dir.chdir(plugin_dir) do - clone_command = "git clone #{uri} #{name}" - if system(clone_command) - Dir.chdir install_path do - # First try to checkout a specific branch of the theme - tag_checked_out = checkout_remote_branch(AlaveteliConfiguration::theme_branch) if AlaveteliConfiguration::theme_branch - if !tag_checked_out - # try to checkout a tag exactly matching ALAVETELI VERSION - tag_checked_out = checkout_tag(ALAVETELI_VERSION) - end - if ! tag_checked_out - # if we're on a hotfix release (four sequence elements or more), - # look for a usage tag matching the minor release (three sequence elements) - # and check that out if found - if hotfix_version = /^(\d+\.\d+\.\d+)(\.\d+)+/.match(ALAVETELI_VERSION) - base_version = hotfix_version[1] - tag_checked_out = checkout_tag(base_version) - end - end - if ! tag_checked_out - puts "No specific tag for this version: using HEAD" if verbose - end - puts "removing: .git .gitignore" if verbose - rm_rf %w(.git .gitignore) - end - else - rm_rf install_path - raise "#{clone_command} failed! Stopping." - end - end - end - def uninstall(theme_name, verbose=false) possible_theme_dirs(theme_name).each do |dir| if File.directory?(dir) run_hook(theme_name, 'uninstall', verbose) - puts "Removing '#{dir}'" if verbose - rm_r dir - else - puts "Plugin doesn't exist: #{dir}" end end end def run_hook(theme_name, hook_name, verbose=false) - hook_file = File.join(theme_dir(theme_name), "#{hook_name}.rb") + directory = theme_dir(theme_name) + hook_file = File.join(directory, "#{hook_name}.rb") if File.exist? hook_file - puts "Running #{hook_name} hook for #{theme_name}" if verbose + puts "Running #{hook_name} hook in #{directory}" if verbose load hook_file end end - def installed?(theme_name) - possible_theme_dirs(theme_name).any? { |dir| File.directory? dir } + def move_old_theme(old_theme_directory) + puts "There was an old-style theme at #{old_theme_directory}" if verbose + moved_directory = "#{old_theme_directory}-moved" + begin + File.rename old_theme_directory, moved_directory + rescue Errno::ENOTEMPTY, Errno::EEXIST + raise "Tried to move #{old_theme_directory} out of the way, " \ + "but #{moved_directory} already existed" + end + end + + def committishes_to_try + result = [] + theme_branch = AlaveteliConfiguration::theme_branch + result.push "origin/#{theme_branch}" if theme_branch + result.push usage_tag(ALAVETELI_VERSION) + hotfix_match = /^(\d+\.\d+\.\d+)(\.\d+)+/.match(ALAVETELI_VERSION) + result.push usage_tag(hotfix_match[1]) if hotfix_match + result + end + + def checkout_best_option(theme_name) + theme_directory = theme_dir theme_name + all_failed = true + committishes_to_try.each do |committish| + if Git.committish_exists? theme_directory, committish + puts "Checking out #{committish}" if verbose + Git.checkout theme_directory, committish + all_failed = false + break + else + puts "Failed to find #{committish}; skipping..." if verbose + end + end + puts "Falling to using HEAD instead" if all_failed and verbose end def install_theme(theme_url, verbose, deprecated=false) - FileUtils.mkdir_p plugin_dir + FileUtils.mkdir_p all_themes_dir deprecation_string = deprecated ? " using deprecated THEME_URL" : "" theme_name = theme_url_to_theme_name theme_url puts "Installing theme #{theme_name}#{deprecation_string} from #{theme_url}" + # Make sure any uninstall hooks have been run: uninstall(theme_name, verbose) if installed?(theme_name) - install_theme_using_git(theme_name, theme_url, verbose) + theme_directory = theme_dir theme_name + # Is there an old-style theme directory there? If so, move it + # out of the way so that there's no risk that work is lost: + if File.directory? theme_directory + unless Git.non_bare_repository? theme_directory + move_old_theme theme_directory + end + end + # If there isn't a directory there already, clone it into place: + unless File.directory? theme_directory + unless system "git", "clone", theme_url, theme_directory + raise "Cloning from #{theme_url} to #{theme_directory} failed" + end + end + # Set the URL for origin in case it has changed, and fetch from there: + Git.remote_set_url theme_directory, 'origin', theme_url + Git.fetch theme_directory, 'origin' + # Check that checking-out a new commit will be safe: + unless Git.status_clean theme_directory + raise "There were uncommitted changes in #{theme_directory}" + end + unless Git.is_HEAD_pushed? theme_directory + raise "The current work in #{theme_directory} is unpushed" + end + # Now try to checkout various commits in order of preference: + checkout_best_option theme_name + # Finally run the install hooks: run_hook(theme_name, 'install', verbose) run_hook(theme_name, 'post_install', verbose) end @@ -112,4 +131,5 @@ namespace :themes do install_theme(AlaveteliConfiguration::theme_url, verbose, deprecated=true) end end + end diff --git a/lib/tasks/translation.rake b/lib/tasks/translation.rake index 6458d9268..b1f9d0b71 100644 --- a/lib/tasks/translation.rake +++ b/lib/tasks/translation.rake @@ -66,9 +66,10 @@ namespace :translation do 'Hello!') write_email(user_contact_email, 'Contact email (user to user)', output_file) - admin_contact_email = ContactMailer.from_admin_message(info_request.user, - 'A test message', - 'Hello!') + admin_contact_email = ContactMailer.from_admin_message(info_request.user.name, + info_request.user.email, + 'A test message', + 'Hello!') write_email(admin_contact_email, 'Contact email (admin to user)', output_file) # request mailer diff --git a/lib/world_foi_websites.rb b/lib/world_foi_websites.rb index c3f3655df..50976c897 100644 --- a/lib/world_foi_websites.rb +++ b/lib/world_foi_websites.rb @@ -53,7 +53,20 @@ class WorldFOIWebsites {:name => "Informace pro Vsechny", :country_name => "Česká republika", :country_iso_code => "CZ", - :url => "http://www.infoprovsechny.cz"} + :url => "http://www.infoprovsechny.cz"}, + {:name => "¿Qué Sabés?", + :country_name => "Uruguay", + :country_iso_code => "UY", + :url => "http://www.quesabes.org/"}, + {:name => "Nu Vă Supărați", + :country_name => "România", + :country_iso_code => "RO", + :url => "http://nuvasuparati.info/"}, + {:name => "Marsoum41", + :country_name => "تونس", + :country_iso_code => "TN", + :url => "http://www.marsoum41.org"} + ] return world_foi_websites end diff --git a/lib/xapian_queries.rb b/lib/xapian_queries.rb new file mode 100644 index 000000000..b3599740a --- /dev/null +++ b/lib/xapian_queries.rb @@ -0,0 +1,85 @@ +module XapianQueries + + # These methods take some filter criteria expressed in a hash and convert them + # into a xapian query referencing the terms and values stored by InfoRequestEvent. + # Note that the params are request params and may contain irrelevant keys + + def get_request_variety_from_params(params) + query = "" + sortby = "newest" + varieties = [] + if params[:request_variety] && !(query =~ /variety:/) + if params[:request_variety].include? "sent" + varieties -= ['variety:sent', 'variety:followup_sent', 'variety:response', 'variety:comment'] + varieties << ['variety:sent', 'variety:followup_sent'] + end + if params[:request_variety].include? "response" + varieties << ['variety:response'] + end + if params[:request_variety].include? "comment" + varieties << ['variety:comment'] + end + end + if !varieties.empty? + query = " (#{varieties.join(' OR ')})" + end + return query + end + + def get_status_from_params(params) + query = "" + if params[:latest_status] + statuses = [] + if params[:latest_status].class == String + params[:latest_status] = [params[:latest_status]] + end + if params[:latest_status].include?("recent") || params[:latest_status].include?("all") + query += " (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)" + end + if params[:latest_status].include? "successful" + statuses << ['latest_status:successful', 'latest_status:partially_successful'] + end + if params[:latest_status].include? "unsuccessful" + statuses << ['latest_status:rejected', 'latest_status:not_held'] + end + if params[:latest_status].include? "awaiting" + statuses << ['latest_status:waiting_response', 'latest_status:waiting_clarification', 'waiting_classification:true', 'latest_status:internal_review','latest_status:gone_postal', 'latest_status:error_message', 'latest_status:requires_admin'] + end + if params[:latest_status].include? "internal_review" + statuses << ['status:internal_review'] + end + if params[:latest_status].include? "other" + statuses << ['latest_status:gone_postal', 'latest_status:error_message', 'latest_status:requires_admin', 'latest_status:user_withdrawn'] + end + if params[:latest_status].include? "gone_postal" + statuses << ['latest_status:gone_postal'] + end + if !statuses.empty? + query = " (#{statuses.join(' OR ')})" + end + end + return query + end + + def get_date_range_from_params(params) + query = "" + if params.has_key?(:request_date_after) && !params.has_key?(:request_date_before) + params[:request_date_before] = Time.now.strftime("%d/%m/%Y") + query += " #{params[:request_date_after]}..#{params[:request_date_before]}" + elsif !params.has_key?(:request_date_after) && params.has_key?(:request_date_before) + params[:request_date_after] = "01/01/2001" + end + if params.has_key?(:request_date_after) + query = " #{params[:request_date_after]}..#{params[:request_date_before]}" + end + return query + end + + def make_query_from_params(params) + query = params[:query] || "" if query.nil? + query += get_date_range_from_params(params) + query += get_request_variety_from_params(params) + query += get_status_from_params(params) + return query + end +end |