aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin_request_controller.rb10
-rw-r--r--app/models/info_request.rb37
-rw-r--r--db/migrate/101_add_hash_to_info_request.rb22
-rw-r--r--spec/controllers/admin_request_controller_spec.rb11
-rw-r--r--spec/fixtures/info_requests.yml6
-rw-r--r--spec/models/info_request_spec.rb34
6 files changed, 98 insertions, 22 deletions
diff --git a/app/controllers/admin_request_controller.rb b/app/controllers/admin_request_controller.rb
index a617b06df..2b471400b 100644
--- a/app/controllers/admin_request_controller.rb
+++ b/app/controllers/admin_request_controller.rb
@@ -293,15 +293,7 @@ class AdminRequestController < AdminController
end
# 2. Match the email address in the message without matching the hash
- @info_requests = []
- addresses =
- (@raw_email.incoming_message.mail.to || []) +
- (@raw_email.incoming_message.mail.cc || []) +
- (@raw_email.incoming_message.mail.envelope_to || [])
- addresses.uniq!
- for address in addresses
- @info_requests += InfoRequest.guess_by_incoming_email(address)
- end
+ @info_requests = InfoRequest.guess_by_incoming_email(@raw_email.incoming_message)
# 3. Give a reason why it's in the holding pen
last_event = @raw_email.incoming_message.info_request.get_last_event
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 158e6319e..419546c99 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -17,7 +17,6 @@
# allow_new_responses_from :string(255) default("anybody"), not null
# handle_rejected_responses :string(255) default("bounce"), not null
#
-
# models/info_request.rb:
# A Freedom of Information request.
#
@@ -309,13 +308,20 @@ public
# Return list of info requests which *might* be right given email address
# e.g. For the id-hash email addresses, don't match the hash.
- def InfoRequest.guess_by_incoming_email(incoming_email)
- id, hash = InfoRequest._extract_id_hash_from_email(incoming_email)
- begin
- return [InfoRequest.find(id)]
- rescue ActiveRecord::RecordNotFound
- return []
+ def InfoRequest.guess_by_incoming_email(incoming_message)
+ guesses = []
+ # 1. Try to guess based on the email address(es)
+ addresses =
+ (incoming_message.mail.to || []) +
+ (incoming_message.mail.cc || []) +
+ (incoming_message.mail.envelope_to || [])
+ addresses.uniq!
+ for address in addresses
+ id, hash = InfoRequest._extract_id_hash_from_email(address)
+ guesses.push(InfoRequest.find_by_id(id))
+ guesses.push(InfoRequest.find_by_idhash(hash))
end
+ return guesses.select{|x| !x.nil?}.uniq
end
# Internal function used by find_by_magic_email and guess_by_incoming_email
@@ -326,7 +332,7 @@ public
# The optional bounce- dates from when we used to have separate emails for the envelope from.
# (that was abandoned because councils would send hand written responses to them, not just
# bounce messages)
- incoming_email =~ /request-(?:bounce-)?(\d+)-([a-z0-9]+)/
+ incoming_email =~ /request-(?:bounce-)?([a-z0-9]+)-([a-z0-9]+)/
id = $1.to_i
hash = $2
@@ -678,6 +684,7 @@ public
end
end
return nil
+
end
def get_last_response_event
for e in self.info_request_events.reverse
@@ -838,15 +845,25 @@ public
def InfoRequest.magic_email_for_id(prefix_part, id)
magic_email = MySociety::Config.get("INCOMING_EMAIL_PREFIX", "")
magic_email += prefix_part + id.to_s
- magic_email += "-" + Digest::SHA1.hexdigest(id.to_s + MySociety::Config.get("INCOMING_EMAIL_SECRET", 'dummysecret'))[0,8]
+ magic_email += "-" + InfoRequest.hash_from_id(id)
magic_email += "@" + MySociety::Config.get("INCOMING_EMAIL_DOMAIN", "localhost")
return magic_email
end
+ before_validation :compute_idhash
+
+ def compute_idhash
+ self.idhash = InfoRequest.hash_from_id(self.id)
+ end
+
+ def InfoRequest.hash_from_id(id)
+ return Digest::SHA1.hexdigest(id.to_s + MySociety::Config.get("INCOMING_EMAIL_SECRET", 'dummysecret'))[0,8]
+ end
+
# Called by find_by_incoming_email - and used to be called by separate
# function for envelope from address, until we abandoned it.
def InfoRequest.find_by_magic_email(id, hash)
- expected_hash = Digest::SHA1.hexdigest(id.to_s + MySociety::Config.get("INCOMING_EMAIL_SECRET", 'dummysecret'))[0,8]
+ expected_hash = InfoRequest.hash_from_id(id)
#print "expected: " + expected_hash + "\nhash: " + hash + "\n"
if hash != expected_hash
return nil
diff --git a/db/migrate/101_add_hash_to_info_request.rb b/db/migrate/101_add_hash_to_info_request.rb
new file mode 100644
index 000000000..20608aac1
--- /dev/null
+++ b/db/migrate/101_add_hash_to_info_request.rb
@@ -0,0 +1,22 @@
+require 'digest/sha1'
+
+class AddHashToInfoRequest < ActiveRecord::Migration
+ def self.up
+ add_column :info_requests, :idhash, :string
+
+ # Create the missing events for requests already sent
+ InfoRequest.find(:all).each do |info_request|
+ info_request.idhash = Digest::SHA1.hexdigest(info_request.id.to_s + MySociety::Config.get("INCOMING_EMAIL_SECRET", 'dummysecret'))[0,8]
+ info_request.save!
+ puts info_request.idhash
+ end
+ change_column :info_requests, :idhash, :string, :null => false
+ puts InfoRequest.find_by_idhash
+ end
+ def self.down
+ remove_column :info_requests, :idhash
+ end
+end
+
+
+
diff --git a/spec/controllers/admin_request_controller_spec.rb b/spec/controllers/admin_request_controller_spec.rb
index 0b12fa97a..04e412e76 100644
--- a/spec/controllers/admin_request_controller_spec.rb
+++ b/spec/controllers/admin_request_controller_spec.rb
@@ -57,4 +57,15 @@ describe AdminRequestController, "when administering the holding pen" do
response.should have_text(/Only the authority can reply to this request/)
end
+ it "guesses a misdirected request" do
+ ir = info_requests(:fancy_dog_request)
+ ir.handle_rejected_responses = 'holding_pen'
+ ir.save!
+ mail_to = "request-#{ir.id}-asdfg@example.com"
+ receive_incoming_mail('incoming-request-plain.email', mail_to)
+ get :show_raw_email, :id => InfoRequest.holding_pen_request.get_last_response.raw_email.id
+ response.should have_text(/Could not identify the request/)
+ assigns[:info_requests][0].should == ir
+ end
+
end
diff --git a/spec/fixtures/info_requests.yml b/spec/fixtures/info_requests.yml
index bdeef4800..c1e3c1910 100644
--- a/spec/fixtures/info_requests.yml
+++ b/spec/fixtures/info_requests.yml
@@ -8,6 +8,7 @@ fancy_dog_request:
user_id: 1
described_state: waiting_response
awaiting_description: true
+ idhash: 50929748
naughty_chicken_request:
id: 103
title: How much public money is wasted on breeding naughty chickens?
@@ -17,6 +18,5 @@ naughty_chicken_request:
public_body_id: 2
user_id: 1
described_state: waiting_response
- awaiting_description: false
-
-
+ awaiting_description: false
+ idhash: e8d18c84
diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb
index d0b0e0e32..ba80256ab 100644
--- a/spec/models/info_request_spec.rb
+++ b/spec/models/info_request_spec.rb
@@ -2,6 +2,40 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe InfoRequest do
+ describe "guessing a request from an email" do
+ fixtures :info_requests, :public_bodies, :incoming_messages, :raw_emails
+
+ before do
+ @im = incoming_messages(:useless_incoming_message)
+ load_raw_emails_data(raw_emails)
+ end
+
+ it 'should compute a hash' do
+ @info_request = InfoRequest.new(:title => "testing",
+ :public_body => public_bodies(:geraldine_public_body),
+ :user_id => 1)
+ @info_request.save!
+ @info_request.idhash.should_not == nil
+ end
+
+ it 'should find a request based on an email with an intact id and a broken hash' do
+ ir = info_requests(:fancy_dog_request)
+ id = ir.id
+ @im.mail.to = "request-#{id}-asdfg@example.com"
+ guessed = InfoRequest.guess_by_incoming_email(@im)
+ guessed[0].idhash.should == ir.idhash
+ end
+
+ it 'should find a request based on an email with a broken id and an intact hash' do
+ ir = info_requests(:fancy_dog_request)
+ idhash = ir.idhash
+ @im.mail.to = "request-123ab-#{idhash}@example.com"
+ guessed = InfoRequest.guess_by_incoming_email(@im)
+ guessed[0].id.should == ir.id
+ end
+
+ end
+
describe "making up the URL title" do
before do
@info_request = InfoRequest.new