aboutsummaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin_public_body_controller_spec.rb83
-rw-r--r--spec/controllers/admin_request_controller_spec.rb18
-rw-r--r--spec/controllers/admin_track_controller_spec.rb1
-rw-r--r--spec/controllers/admin_user_controller_spec.rb1
-rw-r--r--spec/controllers/application_controller_spec.rb49
-rw-r--r--spec/controllers/comment_controller_spec.rb1
-rw-r--r--spec/controllers/general_controller_spec.rb97
-rw-r--r--spec/controllers/public_body_controller_spec.rb82
-rw-r--r--spec/controllers/request_controller_spec.rb432
-rw-r--r--spec/controllers/request_game_controller_spec.rb4
-rw-r--r--spec/controllers/track_controller_spec.rb16
-rw-r--r--spec/controllers/user_controller_spec.rb87
-rw-r--r--spec/fixtures/comments.yml9
-rw-r--r--spec/fixtures/files/incoming-request-pdf-attachment.email543
-rw-r--r--spec/fixtures/files/quoted-subject-iso8859-1.email462
-rw-r--r--spec/fixtures/files/raw_emails/1.email (renamed from spec/fixtures/files/useless_raw_email.email)0
-rw-r--r--spec/fixtures/files/raw_emails/2.email20
-rw-r--r--spec/fixtures/files/raw_emails/3.email19
-rw-r--r--spec/fixtures/files/raw_emails/4.email17
-rw-r--r--spec/fixtures/files/raw_emails/5.email17
-rw-r--r--spec/fixtures/files/track-response-abcmail-oof.email80
-rw-r--r--spec/fixtures/files/track-response-outlook-oof.email587
-rw-r--r--spec/fixtures/has_tag_string_tags.yml36
-rw-r--r--spec/fixtures/incoming_messages.yml36
-rw-r--r--spec/fixtures/info_request_events.yml123
-rw-r--r--spec/fixtures/info_requests.yml60
-rw-r--r--spec/fixtures/outgoing_messages.yml52
-rw-r--r--spec/fixtures/public_bodies.yml41
-rw-r--r--spec/fixtures/public_body_translations.yml41
-rw-r--r--spec/fixtures/raw_emails.yml20
-rw-r--r--spec/fixtures/users.yml13
-rw-r--r--spec/helpers/link_to_helper_spec.rb19
-rw-r--r--spec/integration/errors_spec.rb29
-rw-r--r--spec/integration/search_request_spec.rb49
-rw-r--r--spec/integration/view_request_spec.rb17
-rw-r--r--spec/lib/sendmail_return_path_spec.rb1
-rw-r--r--spec/lib/tmail_extensions_spec.rb4
-rw-r--r--spec/models/foi_attachment_spec.rb35
-rw-r--r--spec/models/has_tag_string_tag_spec.rb1
-rw-r--r--spec/models/holiday_spec.rb1
-rw-r--r--spec/models/incoming_message_spec.rb80
-rw-r--r--spec/models/info_request_event_spec.rb16
-rw-r--r--spec/models/info_request_spec.rb9
-rw-r--r--spec/models/outgoing_mailer_spec.rb14
-rw-r--r--spec/models/outgoing_message_spec.rb2
-rw-r--r--spec/models/public_body_spec.rb44
-rw-r--r--spec/models/request_mailer_spec.rb4
-rw-r--r--spec/models/track_mailer_spec.rb1
-rw-r--r--spec/models/track_thing_spec.rb8
-rw-r--r--spec/models/user_spec.rb5
-rw-r--r--spec/models/xapian_spec.rb104
-rw-r--r--spec/script/handle-mail-replies_spec.rb10
-rw-r--r--spec/spec_helper.rb58
-rw-r--r--spec/views/request/list.rhtml_spec.rb2
-rw-r--r--spec/views/request/show.rhtml_spec.rb14
55 files changed, 3114 insertions, 460 deletions
diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb
index 22af3df80..1e82a0ba4 100644
--- a/spec/controllers/admin_public_body_controller_spec.rb
+++ b/spec/controllers/admin_public_body_controller_spec.rb
@@ -2,14 +2,19 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AdminPublicBodyController, "when administering public bodies" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
username = MySociety::Config.get('ADMIN_USERNAME', '')
password = MySociety::Config.get('ADMIN_PASSWORD', '')
basic_auth_login @request
+
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
+ end
it "shows the index page" do
get :index
@@ -25,9 +30,9 @@ describe AdminPublicBodyController, "when administering public bodies" do
end
it "creates a new public body" do
- PublicBody.count.should == 2
+ n = PublicBody.count
post :create, { :public_body => { :name => "New Quango", :short_name => "", :tag_string => "blah", :request_email => 'newquango@localhost', :last_edit_comment => 'From test code' } }
- PublicBody.count.should == 3
+ PublicBody.count.should == n + 1
end
it "edits a public body" do
@@ -42,29 +47,45 @@ describe AdminPublicBodyController, "when administering public bodies" do
pb.name.should == "Renamed"
end
+ it "does not destroy a public body that has associated requests" do
+ id = public_bodies(:humpadink_public_body).id
+ n = PublicBody.count
+ post :destroy, { :id => id }
+ response.should redirect_to(:controller=>'admin_public_body', :action=>'show', :id => id)
+ PublicBody.count.should == n
+ end
+
it "destroys a public body" do
- PublicBody.count.should == 2
- post :destroy, { :id => 3 }
- PublicBody.count.should == 1
+ n = PublicBody.count
+ post :destroy, { :id => public_bodies(:forlorn_public_body).id }
+ response.should redirect_to(:controller=>'admin_public_body', :action=>'list')
+ PublicBody.count.should == n - 1
end
it "sets a using_admin flag" do
get :show, :id => 2
session[:using_admin].should == 1
end
+
+ it "mass assigns tags" do
+ n = PublicBody.count
+ post :mass_tag_add, { :new_tag => "department", :table_name => "substring" }
+ response.flash[:notice].should == "Added tag to table of bodies."
+ response.should redirect_to(:action=>'list')
+ PublicBody.find_by_tag("department").count.should == n
+ end
end
describe AdminPublicBodyController, "when administering public bodies and paying attention to authentication" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "disallows non-authenticated users to do anything" do
@request.env["HTTP_AUTHORIZATION"] = ""
- PublicBody.count.should == 2
+ n = PublicBody.count
post :destroy, { :id => 3 }
response.code.should == "401"
- PublicBody.count.should == 2
+ PublicBody.count.should == n
session[:using_admin].should == nil
end
@@ -73,19 +94,22 @@ describe AdminPublicBodyController, "when administering public bodies and paying
config['ADMIN_USERNAME'] = ''
config['ADMIN_PASSWORD'] = ''
@request.env["HTTP_AUTHORIZATION"] = ""
- PublicBody.count.should == 2
- post :destroy, { :id => 3 }
- PublicBody.count.should == 1
+
+ n = PublicBody.count
+ post :destroy, { :id => public_bodies(:forlorn_public_body).id }
+ PublicBody.count.should == n - 1
session[:using_admin].should == 1
end
+
it "skips admin authorisation when no username set" do
config = MySociety::Config.load_default()
config['ADMIN_USERNAME'] = ''
config['ADMIN_PASSWORD'] = 'fuz'
@request.env["HTTP_AUTHORIZATION"] = ""
- PublicBody.count.should == 2
- post :destroy, { :id => 3 }
- PublicBody.count.should == 1
+
+ n = PublicBody.count
+ post :destroy, { :id => public_bodies(:forlorn_public_body).id }
+ PublicBody.count.should == n - 1
session[:using_admin].should == 1
end
it "forces authorisation when password and username set" do
@@ -93,11 +117,11 @@ describe AdminPublicBodyController, "when administering public bodies and paying
config['ADMIN_USERNAME'] = 'biz'
config['ADMIN_PASSWORD'] = 'fuz'
@request.env["HTTP_AUTHORIZATION"] = ""
- PublicBody.count.should == 2
+ n = PublicBody.count
basic_auth_login(@request, "baduser", "badpassword")
- post :destroy, { :id => 3 }
+ post :destroy, { :id => public_bodies(:forlorn_public_body).id }
response.code.should == "401"
- PublicBody.count.should == 2
+ PublicBody.count.should == n
session[:using_admin].should == nil
end
@@ -107,7 +131,6 @@ end
describe AdminPublicBodyController, "when administering public bodies with i18n" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
username = MySociety::Config.get('ADMIN_USERNAME', '')
@@ -167,43 +190,47 @@ describe AdminPublicBodyController, "when administering public bodies with i18n"
end
it "destroy a public body" do
- PublicBody.count.should == 2
- post :destroy, { :id => 3 }
- PublicBody.count.should == 1
+ n = PublicBody.count
+ post :destroy, { :id => public_bodies(:forlorn_public_body).id }
+ PublicBody.count.should == n - 1
end
end
describe AdminPublicBodyController, "when creating public bodies with i18n" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
username = MySociety::Config.get('ADMIN_USERNAME', '')
password = MySociety::Config.get('ADMIN_PASSWORD', '')
basic_auth_login @request
- ActionController::Routing::Routes.filters.clear # don't auto-insert locale, complicates assertions
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+ end
+
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
end
it "creates a new public body in one locale" do
- PublicBody.count.should == 2
+ n = PublicBody.count
post :create, { :public_body => { :name => "New Quango", :short_name => "", :tag_string => "blah", :request_email => 'newquango@localhost', :last_edit_comment => 'From test code' } }
- PublicBody.count.should == 3
+ PublicBody.count.should == n + 1
body = PublicBody.find_by_name("New Quango")
response.should redirect_to(:controller=>'admin_public_body', :action=>'show', :id=>body.id)
end
it "creates a new public body with multiple locales" do
- PublicBody.count.should == 2
+ n = PublicBody.count
post :create, {
:public_body => {
:name => "New Quango", :short_name => "", :tag_string => "blah", :request_email => 'newquango@localhost', :last_edit_comment => 'From test code',
:translated_versions => [{ :locale => "es", :name => "Mi Nuevo Quango", :short_name => "", :request_email => 'newquango@localhost' }]
}
}
- PublicBody.count.should == 3
+ PublicBody.count.should == n + 1
body = PublicBody.find_by_name("New Quango")
body.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"]
diff --git a/spec/controllers/admin_request_controller_spec.rb b/spec/controllers/admin_request_controller_spec.rb
index 635d73b9e..ece1fe389 100644
--- a/spec/controllers/admin_request_controller_spec.rb
+++ b/spec/controllers/admin_request_controller_spec.rb
@@ -2,9 +2,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AdminRequestController, "when administering requests" do
integrate_views
- fixtures :users, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before { basic_auth_login @request }
+ before(:each) do
+ load_raw_emails_data
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+ end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
+ end
+
it "shows the index/list page" do
get :index
end
@@ -41,10 +49,14 @@ end
describe AdminRequestController, "when administering the holding pen" do
integrate_views
- fixtures :users, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
basic_auth_login @request
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+ end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
end
it "shows a rejection reason for an incoming message from an invalid address" do
diff --git a/spec/controllers/admin_track_controller_spec.rb b/spec/controllers/admin_track_controller_spec.rb
index b87ee9f0e..728c79f1f 100644
--- a/spec/controllers/admin_track_controller_spec.rb
+++ b/spec/controllers/admin_track_controller_spec.rb
@@ -2,7 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AdminTrackController, "when administering tracks" do
integrate_views
- fixtures :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "shows the list page" do
get :list
diff --git a/spec/controllers/admin_user_controller_spec.rb b/spec/controllers/admin_user_controller_spec.rb
index b2b2d0626..65ecbc37d 100644
--- a/spec/controllers/admin_user_controller_spec.rb
+++ b/spec/controllers/admin_user_controller_spec.rb
@@ -2,7 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AdminUserController, "when administering users" do
integrate_views
- fixtures :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before { basic_auth_login @request }
it "shows the index/list page" do
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 875d7d224..f16cee312 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -1,10 +1,47 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'fakeweb'
+
+describe ApplicationController, "when accessing third party services" do
+ before (:each) do
+ FakeWeb.clean_registry
+ end
+ after (:each) do
+ FakeWeb.clean_registry
+ end
+ it "should succeed if the service responds OK" do
+ config = MySociety::Config.load_default()
+ config['GAZE_URL'] = 'http://denmark.com'
+ FakeWeb.register_uri(:get, %r|denmark.com|, :body => "DK")
+ country = self.controller.send :country_from_ip
+ country.should == "DK"
+ end
+ it "should fail silently if the country_from_ip domain doesn't exist" do
+ config = MySociety::Config.load_default()
+ config['GAZE_URL'] = 'http://12123sdf14qsd.com'
+ country = self.controller.send :country_from_ip
+ country.should == config['ISO_COUNTRY_CODE']
+ end
+ it "should fail silently if the country_from_ip service doesn't exist" do
+ config = MySociety::Config.load_default()
+ config['GAZE_URL'] = 'http://www.google.com'
+ country = self.controller.send :country_from_ip
+ country.should == config['ISO_COUNTRY_CODE']
+ end
+ it "should fail silently if the country_from_ip service returns an error" do
+ FakeWeb.register_uri(:get, %r|500.com|, :body => "Error", :status => ["500", "Error"])
+ config = MySociety::Config.load_default()
+ config['GAZE_URL'] = 'http://500.com'
+ country = self.controller.send :country_from_ip
+ country.should == config['ISO_COUNTRY_CODE']
+ end
+end
+
+describe ApplicationController, "when caching fragments" do
+ it "should not fail with long filenames" do
+ long_name = "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah.txt"
+ path = self.controller.send(:foi_fragment_cache_path, long_name)
+ self.controller.send(:foi_fragment_cache_write, path, "whassap")
+ end
-describe ApplicationController, "when authenticating user" do
- integrate_views
- fixtures :users
-
-# it "blah" do
-# end
end
diff --git a/spec/controllers/comment_controller_spec.rb b/spec/controllers/comment_controller_spec.rb
index 4c14b8d24..93752537c 100644
--- a/spec/controllers/comment_controller_spec.rb
+++ b/spec/controllers/comment_controller_spec.rb
@@ -2,7 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe CommentController, "when commenting on a request" do
integrate_views
- fixtures :users, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "should give an error and render 'new' template when body text is just some whitespace" do
post :new, :url_title => info_requests(:naughty_chicken_request).url_title,
diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb
index 40a676d61..7fc019c64 100644
--- a/spec/controllers/general_controller_spec.rb
+++ b/spec/controllers/general_controller_spec.rb
@@ -1,23 +1,28 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'fakeweb'
+
+describe GeneralController, "when trying to show the blog" do
+ before (:each) do
+ FakeWeb.clean_registry
+ end
+ after (:each) do
+ FakeWeb.clean_registry
+ end
+
+ it "should fail silently if the blog is returning an error" do
+ FakeWeb.register_uri(:get, %r|.*|, :body => "Error", :status => ["500", "Error"])
+ get :blog
+ response.status.should == "200 OK"
+ assigns[:blog_items].count.should == 0
+ end
+end
describe GeneralController, "when searching" do
integrate_views
- fixtures [
- :public_bodies,
- :public_body_translations,
- :public_body_versions,
- :users,
- :info_requests,
- :raw_emails,
- :incoming_messages,
- :outgoing_messages,
- :comments,
- :info_request_events,
- :track_things,
- ]
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should render the front page successfully" do
@@ -68,36 +73,58 @@ describe GeneralController, "when searching" do
it "should redirect from search query URL to pretty URL" do
post :search_redirect, :query => "mouse" # query hidden in POST parameters
- response.should redirect_to(:action => 'search', :combined => "mouse", :view => "requests") # URL /search/:query/all
+ response.should redirect_to(:action => 'search', :combined => "mouse", :view => "all") # URL /search/:query/all
end
describe "when using different locale settings" do
home_link_regex = /href=".*\/en"/
it "should generate URLs with a locale prepended when there's more than one locale set" do
- ActionController::Routing::Routes.add_filters('conditionallyprependlocale')
get :frontpage
response.should have_text(home_link_regex)
end
it "should generate URLs without a locale prepended when there's only one locale set" do
- ActionController::Routing::Routes.add_filters('conditionallyprependlocale')
- old_available_locales = FastGettext.default_available_locales
- available_locales = ['en']
- FastGettext.default_available_locales = available_locales
- I18n.available_locales = available_locales
+ old_fgt_available_locales = FastGettext.default_available_locales
+ old_i18n_available_locales = I18n.available_locales
+ FastGettext.default_available_locales = I18n.available_locales = ['en']
get :frontpage
response.should_not have_text(home_link_regex)
- FastGettext.default_available_locales = old_available_locales
- I18n.available_locales = old_available_locales
+ FastGettext.default_available_locales = old_fgt_available_locales
+ I18n.available_locales = old_i18n_available_locales
+ end
+ end
+
+ describe 'when constructing the list of recent requests' do
+ before(:each) do
+ load_raw_emails_data
+ rebuild_xapian_index
+ end
+
+ it 'should list the newest successful request first' do
+ # Make sure the newest is listed first even if an older one
+ # has a newer comment or was reclassified more recently:
+ # https://github.com/sebbacon/alaveteli/issues/370
+ #
+ # This is a deliberate behaviour change, in that the
+ # previous behaviour (showing more-recently-reclassified
+ # requests first) was intentional.
+ get :frontpage
+ assigns[:request_events].first.info_request.should == info_requests(:another_boring_request)
+ end
+
+ it 'should coalesce duplicate requests' do
+ get :frontpage
+ assigns[:request_events].map(&:info_request).select{|x|x.url_title =~ /^spam/}.length.should == 1
end
end
describe 'when using xapian search' do
# rebuild xapian index after fixtures loaded
- before(:all) do
+ before(:each) do
+ load_raw_emails_data
rebuild_xapian_index
end
@@ -128,21 +155,31 @@ describe GeneralController, "when searching" do
it "should filter results based on end of URL being 'all'" do
get :search, :combined => ['"bob"', "all"]
- assigns[:xapian_requests].results.size.should == 2
- assigns[:xapian_users].results.size.should == 1
- assigns[:xapian_bodies].results.size.should == 0
+ assigns[:xapian_requests].results.map{|x| x[:model]}.should =~ [
+ info_request_events(:useless_outgoing_message_event),
+ info_request_events(:silly_outgoing_message_event),
+ info_request_events(:useful_incoming_message_event),
+ info_request_events(:another_useful_incoming_message_event),
+ ]
+ assigns[:xapian_users].results.map{|x| x[:model]}.should == [users(:bob_smith_user)]
+ assigns[:xapian_bodies].results.should == []
end
it "should filter results based on end of URL being 'users'" do
get :search, :combined => ['"bob"', "users"]
assigns[:xapian_requests].should == nil
- assigns[:xapian_users].results.size.should == 1
+ assigns[:xapian_users].results.map{|x| x[:model]}.should == [users(:bob_smith_user)]
assigns[:xapian_bodies].should == nil
end
it "should filter results based on end of URL being 'requests'" do
get :search, :combined => ['"bob"', "requests"]
- assigns[:xapian_requests].results.size.should == 2
+ assigns[:xapian_requests].results.map{|x|x[:model]}.should =~ [
+ info_request_events(:useless_outgoing_message_event),
+ info_request_events(:silly_outgoing_message_event),
+ info_request_events(:useful_incoming_message_event),
+ info_request_events(:another_useful_incoming_message_event),
+ ]
assigns[:xapian_users].should == nil
assigns[:xapian_bodies].should == nil
end
@@ -151,7 +188,7 @@ describe GeneralController, "when searching" do
get :search, :combined => ['"quango"', "bodies"]
assigns[:xapian_requests].should == nil
assigns[:xapian_users].should == nil
- assigns[:xapian_bodies].results.size.should == 1
+ assigns[:xapian_bodies].results.map{|x|x[:model]}.should == [public_bodies(:geraldine_public_body)]
end
it "should show help when searching for nothing" do
diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb
index 8182e1331..e6eca0781 100644
--- a/spec/controllers/public_body_controller_spec.rb
+++ b/spec/controllers/public_body_controller_spec.rb
@@ -4,7 +4,11 @@ require 'json'
describe PublicBodyController, "when showing a body" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
+
+ before(:each) do
+ load_raw_emails_data
+ rebuild_xapian_index
+ end
it "should be successful" do
get :show, :url_name => "dfh", :view => 'all'
@@ -21,11 +25,23 @@ describe PublicBodyController, "when showing a body" do
assigns[:public_body].should == public_bodies(:humpadink_public_body)
end
- it "should assign the requests" do
+ it "should assign the requests (1)" do
get :show, :url_name => "tgq", :view => 'all'
- assigns[:xapian_requests].results.count.should == 2
+ assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(
+ :conditions => ["public_body_id = ?", public_bodies(:geraldine_public_body).id])
+ end
+
+ it "should assign the requests (2)" do
get :show, :url_name => "tgq", :view => 'successful'
- assigns[:xapian_requests].results.count.should == 0
+ assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(
+ :conditions => ["described_state = ? and public_body_id = ?",
+ "successful", public_bodies(:geraldine_public_body).id])
+ end
+
+ it "should assign the requests (3)" do
+ get :show, :url_name => "dfh", :view => 'all'
+ assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(
+ :conditions => ["public_body_id = ?", public_bodies(:humpadink_public_body).id])
end
it "should assign the body using different locale from that used for url_name" do
@@ -43,9 +59,13 @@ describe PublicBodyController, "when showing a body" do
end
it "should redirect use to the relevant locale even when url_name is for a different locale" do
- ActionController::Routing::Routes.filters.clear
+ old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+
get :show, {:url_name => "edfh", :view => 'all'}
response.should redirect_to "http://test.host/body/dfh"
+
+ ActionController::Routing::Routes.filters = old_filters
end
it "should redirect to newest name if you use historic name of public body in URL" do
@@ -61,7 +81,6 @@ end
describe PublicBodyController, "when listing bodies" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "should be successful" do
get :list
@@ -70,25 +89,28 @@ describe PublicBodyController, "when listing bodies" do
it "should list all bodies from default locale, even when there are no translations for selected locale" do
PublicBody.with_locale(:en) do
- english_only = PublicBody.new(:name => 'English only',
+ @english_only = PublicBody.new(:name => 'English only',
:short_name => 'EO',
:request_email => 'english@flourish.org',
:last_edit_editor => 'test',
:last_edit_comment => '')
- english_only.save
+ @english_only.save
end
PublicBody.with_locale(:es) do
get :list
- assigns[:public_bodies].length.should == 3
+ assigns[:public_bodies].include?(@english_only).should == true
end
end
it "should list bodies in alphabetical order" do
+ # Note that they are alphabetised by localised name
get :list
response.should render_template('list')
- assigns[:public_bodies].should == [ public_bodies(:humpadink_public_body), public_bodies(:geraldine_public_body) ]
+ assigns[:public_bodies].should == PublicBody.all(
+ :conditions => "id <> #{PublicBody.internal_admin_body.id}",
+ :order => "(select name from public_body_translations where public_body_id=public_bodies.id and locale='en')")
assigns[:tag].should == "all"
assigns[:description].should == ""
end
@@ -114,22 +136,23 @@ describe PublicBodyController, "when listing bodies" do
end
it "should list a tagged thing on the appropriate list page, and others on the other page, and all still on the all page" do
+ load_test_categories
+
public_bodies(:humpadink_public_body).tag_string = "foo local_council"
get :list, :tag => "local_council"
response.should render_template('list')
assigns[:public_bodies].should == [ public_bodies(:humpadink_public_body) ]
assigns[:tag].should == "local_council"
- assigns[:description].should == "Local councils"
+ assigns[:description].should == "in the category ‘Local councils’"
get :list, :tag => "other"
response.should render_template('list')
- assigns[:public_bodies].should == [ public_bodies(:geraldine_public_body) ]
+ assigns[:public_bodies].should =~ PublicBody.all(:conditions => "id not in (#{public_bodies(:humpadink_public_body).id}, #{PublicBody.internal_admin_body.id})")
get :list
response.should render_template('list')
- assigns[:public_bodies].count.should == 2
-
+ assigns[:public_bodies].should =~ PublicBody.all(:conditions => "id <> #{PublicBody.internal_admin_body.id}")
end
it "should list a machine tagged thing, should get it in both ways" do
@@ -157,8 +180,6 @@ end
describe PublicBodyController, "when showing JSON version for API" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
-
it "should be successful" do
get :show, :url_name => "dfh", :format => "json", :view => 'all'
@@ -172,38 +193,45 @@ describe PublicBodyController, "when showing JSON version for API" do
end
describe PublicBodyController, "when doing type ahead searches" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
+
+ integrate_views
+
+ before(:each) do
+ load_raw_emails_data
+ rebuild_xapian_index
+ end
it "should return nothing for the empty query string" do
- get :search_typeahead, :q => ""
+ get :search_typeahead, :query => ""
response.should render_template('public_body/_search_ahead')
assigns[:xapian_requests].should be_nil
end
it "should return a body matching the given keyword, but not users with a matching description" do
- get :search_typeahead, :q => "Geraldine"
+ get :search_typeahead, :query => "Geraldine"
response.should render_template('public_body/_search_ahead')
+ response.body.should include('search_ahead')
assigns[:xapian_requests].results.size.should == 1
assigns[:xapian_requests].results[0][:model].name.should == public_bodies(:geraldine_public_body).name
end
it "should return all requests matching any of the given keywords" do
- get :search_typeahead, :q => "Geraldine Humpadinking"
+ get :search_typeahead, :query => "Geraldine Humpadinking"
response.should render_template('public_body/_search_ahead')
- assigns[:xapian_requests].results.size.should == 2
- assigns[:xapian_requests].results[0][:model].name.should == public_bodies(:humpadink_public_body).name
- assigns[:xapian_requests].results[1][:model].name.should == public_bodies(:geraldine_public_body).name
+ assigns[:xapian_requests].results.map{|x|x[:model]}.should =~ [
+ public_bodies(:humpadink_public_body),
+ public_bodies(:geraldine_public_body),
+ ]
end
it "should return requests matching the given keywords in any of their locales" do
- get :search_typeahead, :q => "baguette" # part of the spanish notes
+ get :search_typeahead, :query => "baguette" # part of the spanish notes
response.should render_template('public_body/_search_ahead')
- assigns[:xapian_requests].results.size.should == 1
- assigns[:xapian_requests].results[0][:model].name.should == public_bodies(:humpadink_public_body).name
+ assigns[:xapian_requests].results.map{|x|x[:model]}.should =~ [public_bodies(:humpadink_public_body)]
end
it "should not return matches for short words" do
- get :search_typeahead, :q => "b"
+ get :search_typeahead, :query => "b"
response.should render_template('public_body/_search_ahead')
assigns[:xapian_requests].should be_nil
end
diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index 4994c2a8f..25dce3f22 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -4,58 +4,125 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require 'json'
describe RequestController, "when listing recent requests" do
- fixtures :users, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
rebuild_xapian_index
end
it "should be successful" do
- get :list, :view => 'recent'
+ get :list, :view => 'all'
response.should be_success
end
it "should render with 'list' template" do
- get :list, :view => 'recent'
+ get :list, :view => 'all'
response.should render_template('list')
end
it "should filter requests" do
get :list, :view => 'all'
- assigns[:list_results].size.should == 2
+ assigns[:list_results].map(&:info_request).should =~ InfoRequest.all
+
+ # default sort order is the request with the most recently created event first
+ assigns[:list_results].map(&:info_request).should == InfoRequest.all(
+ :order => "(select max(info_request_events.created_at) from info_request_events where info_request_events.info_request_id = info_requests.id) DESC")
+
get :list, :view => 'successful'
- assigns[:list_results].size.should == 0
+ assigns[:list_results].map(&:info_request).should =~ InfoRequest.all(
+ :conditions => "id in (
+ select info_request_id
+ from info_request_events
+ where not exists (
+ select *
+ from info_request_events later_events
+ where later_events.created_at > info_request_events.created_at
+ and later_events.info_request_id = info_request_events.info_request_id
+ and later_events.described_state is not null
+ )
+ and info_request_events.described_state in ('successful', 'partially_successful')
+ )")
end
it "should filter requests by date" do
+ # The semantics of the search are that it finds any InfoRequest
+ # that has any InfoRequestEvent created in the specified range
+
get :list, :view => 'all', :request_date_before => '13/10/2007'
- assigns[:list_results].size.should == 1
+ assigns[:list_results].map(&:info_request).should =~ InfoRequest.all(
+ :conditions => "id in (select info_request_id from info_request_events where created_at < '2007-10-13'::date)")
+
get :list, :view => 'all', :request_date_after => '13/10/2007'
- assigns[:list_results].size.should == 1
- get :list, :view => 'all', :request_date_after => '10/10/2007', :request_date_before => '01/01/2010'
- assigns[:list_results].size.should == 2
+ assigns[:list_results].map(&:info_request).should =~ InfoRequest.all(
+ :conditions => "id in (select info_request_id from info_request_events where created_at > '2007-10-13'::date)")
+
+ get :list, :view => 'all', :request_date_after => '13/10/2007', :request_date_before => '01/11/2007'
+ assigns[:list_results].map(&:info_request).should =~ InfoRequest.all(
+ :conditions => "id in (select info_request_id from info_request_events where created_at between '2007-10-13'::date and '2007-11-01'::date)")
+ end
+
+ it "should make a sane-sized cache tag" do
+ get :list, :view => 'all', :request_date_after => '13/10/2007', :request_date_before => '01/11/2007'
+ assigns[:cache_tag].size.should <= 32
+ end
+
+ it "should list internal_review requests as unresolved ones" do
+ get :list, :view => 'awaiting'
+
+ # This doesn’t precisely duplicate the logic of the actual
+ # query, but it is close enough to give the same result with
+ # the current set of test data.
+ assigns[:list_results].should =~ InfoRequestEvent.all(
+ :conditions => "described_state in (
+ 'waiting_response', 'waiting_clarification',
+ 'internal_review', 'gone_postal', 'error_message', 'requires_admin'
+ ) and not exists (
+ select *
+ from info_request_events later_events
+ where later_events.created_at > info_request_events.created_at
+ and later_events.info_request_id = info_request_events.info_request_id
+ )")
+
+
+ get :list, :view => 'awaiting'
+ assigns[:list_results].map(&:info_request).include?(info_requests(:fancy_dog_request)).should == false
+
+ event = info_request_events(:useless_incoming_message_event)
+ event.described_state = event.calculated_state = "internal_review"
+ event.save!
+ rebuild_xapian_index
+
+ get :list, :view => 'awaiting'
+ assigns[:list_results].map(&:info_request).include?(info_requests(:fancy_dog_request)).should == true
end
it "should assign the first page of results" do
xap_results = mock_model(ActsAsXapian::Search,
:results => (1..25).to_a.map { |m| { :model => m } },
- :matches_estimated => 103)
+ :matches_estimated => 1000000)
InfoRequest.should_receive(:full_search).
- with([InfoRequestEvent]," variety:sent", "created_at", anything, anything, anything, anything).
+ with([InfoRequestEvent]," (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)", "created_at", anything, anything, anything, anything).
and_return(xap_results)
- get :list, :view => 'recent'
+ get :list, :view => 'all'
assigns[:list_results].size.should == 25
+ assigns[:show_no_more_than].should == RequestController::MAX_RESULTS
end
+ it "should return 404 for pages we don't want to serve up" do
+ xap_results = mock_model(ActsAsXapian::Search,
+ :results => (1..25).to_a.map { |m| { :model => m } },
+ :matches_estimated => 1000000)
+ lambda {
+ get :list, :view => 'all', :page => 100
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+
end
describe RequestController, "when showing one request" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
-
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should be successful" do
@@ -80,24 +147,40 @@ describe RequestController, "when showing one request" do
describe 'when handling an update_status parameter' do
-
- before do
- mock_request = mock_model(InfoRequest, :url_title => 'test_title',
- :title => 'test title',
- :null_object => true)
- InfoRequest.stub!(:find_by_url_title).and_return(mock_request)
- end
-
it 'should assign the "update status" flag to the view as true if the parameter is present' do
- get :show, :url_title => 'test_title', :update_status => 1
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog', :update_status => 1
assigns[:update_status].should be_true
end
- it 'should assign the "update status" flag to the view as true if the parameter is present' do
- get :show, :url_title => 'test_title'
+ it 'should assign the "update status" flag to the view as false if the parameter is not present' do
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
assigns[:update_status].should be_false
end
+ it 'should require login' do
+ session[:user_id] = nil
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog', :update_status => 1
+ post_redirect = PostRedirect.get_last_post_redirect
+ response.should redirect_to(:controller => 'user', :action => 'signin', :token => post_redirect.token)
+ end
+
+ it 'should work if logged in as the requester' do
+ session[:user_id] = users(:bob_smith_user).id
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog', :update_status => 1
+ response.should render_template "request/show"
+ end
+
+ it 'should not work if logged in as not the requester' do
+ session[:user_id] = users(:silly_name_user).id
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog', :update_status => 1
+ response.should render_template "user/wrong_user"
+ end
+
+ it 'should work if logged in as an admin user' do
+ session[:user_id] = users(:admin_user).id
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog', :update_status => 1
+ response.should render_template "request/show"
+ end
end
describe 'when handling incoming mail' do
@@ -123,7 +206,8 @@ describe RequestController, "when showing one request" do
it "should download attachments" do
ir = info_requests(:fancy_dog_request)
- ir.incoming_messages.each { |x| x.parse_raw_email! }
+ ir.incoming_messages.each { |x| x.parse_raw_email!(true) }
+
get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
response.content_type.should == "text/html"
size_before = assigns[:info_request_events].size
@@ -134,10 +218,12 @@ describe RequestController, "when showing one request" do
get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
(assigns[:info_request_events].size - size_before).should == 1
ir.reload
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt']
+
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1
response.content_type.should == "text/plain"
response.should have_text(/Second hello/)
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3, :file_name => ['hello.txt']
+
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3, :file_name => ['hello.txt'], :skip_cache => 1
response.content_type.should == "text/plain"
response.should have_text(/First hello/)
end
@@ -149,7 +235,7 @@ describe RequestController, "when showing one request" do
response.should have_text(/tënde/u)
end
- it "should generate valid HTML verson of plain text attachments " do
+ it "should generate valid HTML verson of plain text attachments" do
ir = info_requests(:fancy_dog_request)
receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
ir.reload
@@ -158,6 +244,71 @@ describe RequestController, "when showing one request" do
response.should have_text(/Second hello/)
end
+ # This is a regression test for a bug where URLs of this form were causing 500 errors
+ # instead of 404s.
+ #
+ # (Note that in fact only the integer-prefix of the URL part is used, so there are
+ # *some* “ugly URLs containing a request id that isn't an integer” that actually return
+ # a 200 response. The point is that IDs of this sort were triggering an error in the
+ # error-handling path, causing the wrong sort of error response to be returned in the
+ # case where the integer prefix referred to the wrong request.)
+ #
+ # https://github.com/sebbacon/alaveteli/issues/351
+ it "should return 404 for ugly URLs containing a request id that isn't an integer" do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
+ ir.reload
+ ugly_id = "55195"
+ lambda {
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1
+ }.should raise_error(ActiveRecord::RecordNotFound)
+
+ lambda {
+ get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ it "should return 404 when incoming message and request ids don't match" do
+ ir = info_requests(:fancy_dog_request)
+ wrong_id = info_requests(:naughty_chicken_request).id
+ receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
+ ir.reload
+ lambda {
+ get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => wrong_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ it "should return 404 for ugly URLs contain a request id that isn't an integer, even if the integer prefix refers to an actual request" do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
+ ir.reload
+ ugly_id = "%d95" % [info_requests(:naughty_chicken_request).id]
+
+ lambda {
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1
+ }.should raise_error(ActiveRecord::RecordNotFound)
+
+ lambda {
+ get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ugly_id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ it "should return 404 when incoming message and request ids don't match" do
+ ir = info_requests(:fancy_dog_request)
+ wrong_id = info_requests(:naughty_chicken_request).id
+ receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
+ ir.reload
+ lambda {
+ get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => wrong_id, :part => 2, :file_name => ['hello.txt.html'], :skip_cache => 1
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it "should generate valid HTML verson of PDF attachments " do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('incoming-request-pdf-attachment.email', ir.incoming_email)
+ ir.reload
+ get :get_attachment_as_html, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['fs_50379341.pdf.html'], :skip_cache => 1
+ response.content_type.should == "text/html"
+ response.should have_text(/Walberswick Parish Council/)
+ end
+
it "should not cause a reparsing of the raw email, even when the result would be a 404 " do
ir = info_requests(:fancy_dog_request)
receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
@@ -205,7 +356,7 @@ describe RequestController, "when showing one request" do
receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
lambda {
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2,
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2,
:file_name => ['http://trying.to.hack']
}.should raise_error(ActiveRecord::RecordNotFound)
end
@@ -219,12 +370,16 @@ describe RequestController, "when showing one request" do
censor_rule.last_edit_editor = "unknown"
censor_rule.last_edit_comment = "none"
ir.censor_rules << censor_rule
-
- receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
-
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt']
- response.content_type.should == "text/plain"
- response.should have_text(/xxxxxx hello/)
+
+ begin
+ receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
+
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1
+ response.content_type.should == "text/plain"
+ response.should have_text(/xxxxxx hello/)
+ ensure
+ ir.censor_rules.clear
+ end
end
it "should censor with rules on the user (rather than the request)" do
@@ -237,12 +392,16 @@ describe RequestController, "when showing one request" do
censor_rule.last_edit_comment = "none"
ir.user.censor_rules << censor_rule
- receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
- ir.reload
+ begin
+ receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
+ ir.reload
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1
- response.content_type.should == "text/plain"
- response.should have_text(/xxxxxx hello/)
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :file_name => ['hello.txt'], :skip_cache => 1
+ response.content_type.should == "text/plain"
+ response.should have_text(/xxxxxx hello/)
+ ensure
+ ir.user.censor_rules.clear
+ end
end
it "should censor attachment names" do
@@ -273,9 +432,12 @@ describe RequestController, "when showing one request" do
censor_rule.last_edit_editor = "unknown"
censor_rule.last_edit_comment = "none"
ir.censor_rules << censor_rule
-
- get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
- response.body.should have_tag("p.attachment strong", /goodbye.txt/m)
+ begin
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
+ response.body.should have_tag("p.attachment strong", /goodbye.txt/m)
+ ensure
+ ir.censor_rules.clear
+ end
end
it "should make a zipfile available, which has a different URL when it changes" do
@@ -287,7 +449,7 @@ describe RequestController, "when showing one request" do
old_path = assigns[:url_path]
response.location.should have_text(/#{assigns[:url_path]}$/)
zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", old_path)) { |zipfile|
- zipfile.count.should == 2
+ zipfile.count.should == 1 # just the message
}
receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
get :download_entire_request, :url_title => title
@@ -295,25 +457,29 @@ describe RequestController, "when showing one request" do
old_path = assigns[:url_path]
response.location.should have_text(/#{assigns[:url_path]}$/)
zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", old_path)) { |zipfile|
- zipfile.count.should == 2
+ zipfile.count.should == 3 # the message plus two "hello.txt" files
}
+
+ # The path of the zip file is based on the hash of the timestamp of the last request
+ # in the thread, so we wait for a second to make sure this one will have a different
+ # timestamp than the previous.
+ sleep 1
receive_incoming_mail('incoming-request-attachment-unknown-extension.email', ir.incoming_email)
get :download_entire_request, :url_title => title
assigns[:url_path].should have_text(/#{title}.zip$/)
+ assigns[:url_path].should_not == old_path
response.location.should have_text(/#{assigns[:url_path]}/)
zipfile = Zip::ZipFile.open(File.join(File.dirname(__FILE__), "../../cache/zips", assigns[:url_path])) { |zipfile|
- zipfile.count.should == 4
+ zipfile.count.should == 5 # the message, two hello.txt, the unknown attachment, and its empty message
}
- assigns[:url_path].should_not == old_path
end
end
end
describe RequestController, "when changing prominence of a request" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should not show hidden requests" do
@@ -379,11 +545,11 @@ describe RequestController, "when changing prominence of a request" do
ir.save!
receive_incoming_mail('incoming-request-two-same-name.email', ir.incoming_email)
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 2, :skip_cache => 1
response.content_type.should == "text/html"
response.should_not have_text(/Second hello/)
response.should render_template('request/hidden')
- get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3
+ get :get_attachment, :incoming_message_id => ir.incoming_messages[1].id, :id => ir.id, :part => 3, :skip_cache => 1
response.content_type.should == "text/html"
response.should_not have_text(/First hello/)
response.should render_template('request/hidden')
@@ -398,7 +564,6 @@ end
# end
describe RequestController, "when searching for an authority" do
- fixtures :public_bodies, :users
# Whether or not sign-in is required for this step is configurable,
# so we make sure we're logged in, just in case
@@ -411,7 +576,7 @@ describe RequestController, "when searching for an authority" do
get :select_authority, :query => ""
response.should render_template('select_authority')
- assigns[:xapian_requests].results.size == 0
+ assigns[:xapian_requests].should == nil
end
it "should return matching bodies" do
@@ -422,11 +587,24 @@ describe RequestController, "when searching for an authority" do
assigns[:xapian_requests].results.size == 1
assigns[:xapian_requests].results[0][:model].name.should == public_bodies(:geraldine_public_body).name
end
+
+ it "should not give an error when user users unintended search operators" do
+ for phrase in ["Marketing/PR activities - Aldborough E-Act Free Schoo",
+ "Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ",
+ "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the",
+ "NHS Ayrshire & Arran",
+ " cardiff",
+ "Foo * bax",
+ "qux ~ quux"]
+ lambda {
+ get :select_authority, :query => phrase
+ }.should_not raise_error(StandardError)
+ end
+ end
end
describe RequestController, "when creating a new request" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@user = users(:bob_smith_user)
@@ -555,6 +733,58 @@ describe RequestController, "when creating a new request" do
response.should redirect_to(:action => 'show', :url_title => ir2.url_title)
end
+
+ it 'should respect the rate limit' do
+ # Try to create three requests in succession.
+ # (The limit set in config/test.yml is two.)
+ session[:user_id] = users(:robin_user)
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What is the answer to the ultimate question?", :tag_string => "" },
+ :outgoing_message => { :body => "Please supply the answer from your files." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'what_is_the_answer_to_the_ultima')
+
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "Why did the chicken cross the road?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send me all the relevant documents you hold." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'why_did_the_chicken_cross_the_ro')
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What's black and white and red all over?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send all minutes of meetings and email records that address this question." },
+ :submitted_new_request => 1, :preview => 0
+ response.should render_template('user/rate_limited')
+ end
+
+ it 'should ignore the rate limit for specified users' do
+ # Try to create three requests in succession.
+ # (The limit set in config/test.yml is two.)
+ session[:user_id] = users(:robin_user)
+ users(:robin_user).no_limit = true
+ users(:robin_user).save!
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What is the answer to the ultimate question?", :tag_string => "" },
+ :outgoing_message => { :body => "Please supply the answer from your files." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'what_is_the_answer_to_the_ultima')
+
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "Why did the chicken cross the road?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send me all the relevant documents you hold." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'why_did_the_chicken_cross_the_ro')
+
+ post :new, :info_request => { :public_body_id => @body.id,
+ :title => "What's black and white and red all over?", :tag_string => "" },
+ :outgoing_message => { :body => "Please send all minutes of meetings and email records that address this question." },
+ :submitted_new_request => 1, :preview => 0
+ response.should redirect_to(:action => 'show', :url_title => 'whats_black_and_white_and_red_al')
+ end
end
@@ -600,6 +830,7 @@ describe RequestController, "when making a new request" do
it "should fail if user is banned" do
@user.stub!(:can_file_requests?).and_return(false)
+ @user.stub!(:exceeded_limit?).and_return(false)
@user.should_receive(:can_fail_html).and_return('FAIL!')
session[:user_id] = @user.id
get :new, :public_body_id => @body.id
@@ -610,10 +841,9 @@ end
describe RequestController, "when viewing an individual response for reply/followup" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should ask for login if you are logged in as wrong person" do
@@ -657,13 +887,11 @@ end
describe RequestController, "when classifying an information request" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
-
before(:each) do
@dog_request = info_requests(:fancy_dog_request)
@dog_request.stub!(:is_old_unclassified?).and_return(false)
InfoRequest.stub!(:find).and_return(@dog_request)
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
def post_status(status)
@@ -901,7 +1129,11 @@ describe RequestController, "when classifying an information request" do
session[:user_id] = @request_owner.id
@dog_request = info_requests(:fancy_dog_request)
InfoRequest.stub!(:find).and_return(@dog_request)
- ActionController::Routing::Routes.filters.clear
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+ end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
end
def request_url
@@ -993,10 +1225,9 @@ end
describe RequestController, "when sending a followup message" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should require login" do
@@ -1076,10 +1307,9 @@ end
describe RequestController, "sending overdue request alerts" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should send an overdue alert mail to creators of overdue requests" do
@@ -1090,8 +1320,8 @@ describe RequestController, "sending overdue request alerts" do
RequestMailer.alert_overdue_requests
deliveries = ActionMailer::Base.deliveries
- deliveries.size.should == 1
- mail = deliveries[0]
+ deliveries.size.should == 2
+ mail = deliveries[1]
mail.body.should =~ /promptly, as normally/
mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email
@@ -1118,8 +1348,8 @@ describe RequestController, "sending overdue request alerts" do
RequestMailer.alert_overdue_requests
deliveries = ActionMailer::Base.deliveries
- deliveries.size.should == 1
- mail = deliveries[0]
+ deliveries.size.should == 2
+ mail = deliveries[1]
mail.body.should =~ /promptly, as normally/
mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email
end
@@ -1143,8 +1373,8 @@ describe RequestController, "sending overdue request alerts" do
RequestMailer.alert_overdue_requests
deliveries = ActionMailer::Base.deliveries
- deliveries.size.should == 1
- mail = deliveries[0]
+ deliveries.size.should == 2
+ mail = deliveries[1]
mail.body.should =~ /required by law/
mail.to_addrs.first.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email
@@ -1164,10 +1394,9 @@ end
describe RequestController, "sending unclassified new response reminder alerts" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should send an alert" do
@@ -1195,9 +1424,8 @@ end
describe RequestController, "clarification required alerts" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should send an alert" do
@@ -1249,9 +1477,8 @@ end
describe RequestController, "comment alerts" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should send an alert (once and once only)" do
@@ -1324,9 +1551,8 @@ end
describe RequestController, "when viewing comments" do
integrate_views
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should link to the user who submitted it" do
@@ -1348,7 +1574,6 @@ end
describe RequestController, "authority uploads a response from the web interface" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
# domain after the @ is used for authentication of FOI officers, so to test it
@@ -1434,11 +1659,9 @@ describe RequestController, "authority uploads a response from the web interface
end
describe RequestController, "when showing JSON version for API" do
-
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should return data in JSON form" do
@@ -1455,7 +1678,8 @@ describe RequestController, "when showing JSON version for API" do
end
describe RequestController, "when doing type ahead searches" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
+
+ integrate_views
it "should return nothing for the empty query string" do
get :search_typeahead, :q => ""
@@ -1473,16 +1697,44 @@ describe RequestController, "when doing type ahead searches" do
it "should return all requests matching any of the given keywords" do
get :search_typeahead, :q => "money dog"
response.should render_template('request/_search_ahead.rhtml')
- assigns[:xapian_requests].results.size.should == 2
- assigns[:xapian_requests].results[0][:model].title.should == info_requests(:fancy_dog_request).title
- assigns[:xapian_requests].results[1][:model].title.should == info_requests(:naughty_chicken_request).title
+ assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ [
+ info_requests(:fancy_dog_request),
+ info_requests(:naughty_chicken_request),
+ info_requests(:another_boring_request),
+ ]
end
- it "should not return matches for short words" do
+ it "should not return matches for short words" do
get :search_typeahead, :q => "a"
response.should render_template('request/_search_ahead.rhtml')
assigns[:xapian_requests].should be_nil
end
+
+ it "should do partial matches for longer words" do
+ get :search_typeahead, :q => "chick"
+ response.should render_template('request/_search_ahead.rhtml')
+ assigns[:xapian_requests].results.size.should ==1
+ end
+
+ it "should not give an error when user users unintended search operators" do
+ for phrase in ["Marketing/PR activities - Aldborough E-Act Free Schoo",
+ "Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ",
+ "Bellevue Road Ryde Isle of Wight PO33 2AR - what is the",
+ "NHS Ayrshire & Arran",
+ "uda ( units of dent",
+ "frob * baz",
+ "bar ~ qux"]
+ lambda {
+ get :search_typeahead, :q => phrase
+ }.should_not raise_error(StandardError)
+ end
+ end
+
+ it "should return all requests matching any of the given keywords" do
+ get :search_typeahead, :q => "dog -chicken"
+ assigns[:xapian_requests].results.size.should == 1
+ end
+
end
diff --git a/spec/controllers/request_game_controller_spec.rb b/spec/controllers/request_game_controller_spec.rb
index cc0808ef3..7247cd388 100644
--- a/spec/controllers/request_game_controller_spec.rb
+++ b/spec/controllers/request_game_controller_spec.rb
@@ -1,10 +1,8 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe RequestGameController, "when playing the game" do
-
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things # all needed as integrating views
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should show the game homepage" do
diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb
index 90d13495f..38a447640 100644
--- a/spec/controllers/track_controller_spec.rb
+++ b/spec/controllers/track_controller_spec.rb
@@ -36,17 +36,18 @@ end
describe TrackController, "when sending alerts for a track" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things, :track_things_sent_emails
include LinkToHelper # for main_url
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
rebuild_xapian_index
end
it "should send alerts" do
# Don't do clever locale-insertion-unto-URL stuff
- ActionController::Routing::Routes.filters.clear
+ old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+
# set the time the comment event happened at to within the last week
ire = info_request_events(:silly_comment_event)
ire.created_at = Time.now - 3.days
@@ -91,6 +92,9 @@ describe TrackController, "when sending alerts for a track" do
TrackMailer.alert_tracks
deliveries = ActionMailer::Base.deliveries
deliveries.size.should == 0
+
+ # Restore the routing filters
+ ActionController::Routing::Routes.filters = old_filters
end
it "should send localised alerts" do
@@ -110,10 +114,9 @@ end
describe TrackController, "when viewing RSS feed for a track" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
rebuild_xapian_index
end
@@ -136,10 +139,9 @@ end
describe TrackController, "when viewing JSON version of a track feed" do
integrate_views
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
rebuild_xapian_index
end
diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb
index 399b275a7..1a701ad43 100644
--- a/spec/controllers/user_controller_spec.rb
+++ b/spec/controllers/user_controller_spec.rb
@@ -8,9 +8,9 @@ require 'json'
describe UserController, "when showing a user" do
integrate_views
- fixtures :users, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should be successful" do
@@ -28,6 +28,16 @@ describe UserController, "when showing a user" do
response.should render_template('show')
end
+ it "should distinguish between 'my profile' and 'my requests' for logged in users" do
+ session[:user_id] = users(:bob_smith_user).id
+ get :show, :url_name => "bob_smith", :view => 'requests'
+ response.body.should_not include("Change your password")
+ response.body.should match(/Your [0-9]+ Freedom of Information requests/)
+ get :show, :url_name => "bob_smith", :view => 'profile'
+ response.body.should include("Change your password")
+ response.body.should_not match(/Your [0-9]+ Freedom of Information requests/)
+ end
+
it "should assign the user" do
get :show, :url_name => "bob_smith"
assigns[:display_user].should == users(:bob_smith_user)
@@ -35,22 +45,28 @@ describe UserController, "when showing a user" do
it "should search the user's contributions" do
get :show, :url_name => "bob_smith"
- assigns[:xapian_requests].results.count.should == 2
+ assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(
+ :conditions => "user_id = #{users(:bob_smith_user).id}")
+
get :show, :url_name => "bob_smith", :user_query => "money"
- assigns[:xapian_requests].results.count.should == 1
+ assigns[:xapian_requests].results.map{|x|x[:model].info_request}.should =~ [
+ info_requests(:naughty_chicken_request),
+ info_requests(:another_boring_request),
+ ]
end
-# Error handling not quite good enough for this yet
-# it "should not show unconfirmed users" do
-# get :show, :url_name => "silly_emnameem"
-# assigns[:display_users].should == [ users(:silly_name_user) ]
-# end
+ it "should not show unconfirmed users" do
+ begin
+ get :show, :url_name => "unconfirmed_user"
+ rescue => e
+ end
+ e.should be_an_instance_of(ActiveRecord::RecordNotFound)
+ end
end
describe UserController, "when signing in" do
integrate_views
- fixtures :users
def get_last_postredirect
post_redirects = PostRedirect.find_by_sql("select * from post_redirects order by id desc limit 1")
@@ -86,7 +102,9 @@ describe UserController, "when signing in" do
end
it "should log in when you give right email/password, and redirect to where you were" do
- ActionController::Routing::Routes.filters.clear
+ old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+
get :signin, :r => "/list"
response.should render_template('sign')
post_redirect = get_last_postredirect
@@ -97,6 +115,26 @@ describe UserController, "when signing in" do
# response doesn't contain /en/ but redirect_to does...
response.should redirect_to(:controller => 'request', :action => 'list', :post_redirect => 1)
response.should_not send_email
+
+ ActionController::Routing::Routes.filters = old_filters
+ end
+
+ it "should not log you in if you use an invalid PostRedirect token, and shouldn't give 500 error either" do
+ old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+
+ post_redirect = "something invalid"
+ lambda {
+ post :signin, { :user_signin => { :email => 'bob@localhost', :password => 'jonespassword' },
+ :token => post_redirect
+ }
+ }.should_not raise_error(NoMethodError)
+ post :signin, { :user_signin => { :email => 'bob@localhost', :password => 'jonespassword' },
+ :token => post_redirect }
+ response.should render_template('sign')
+ assigns[:post_redirect].should == nil
+
+ ActionController::Routing::Routes.filters = old_filters
end
# No idea how to test this in the test framework :(
@@ -120,7 +158,9 @@ describe UserController, "when signing in" do
end
it "should confirm your email, log you in and redirect you to where you were after you click an email link" do
- ActionController::Routing::Routes.filters.clear
+ old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+
get :signin, :r => "/list"
post_redirect = get_last_postredirect
@@ -146,13 +186,14 @@ describe UserController, "when signing in" do
get :confirm, :email_token => post_redirect.email_token
session[:user_id].should == users(:unconfirmed_user).id
response.should redirect_to(:controller => 'request', :action => 'list', :post_redirect => 1)
+
+ ActionController::Routing::Routes.filters = old_filters
end
end
describe UserController, "when signing up" do
integrate_views
- fixtures :users
it "should be an error if you type the password differently each time" do
post :signup, { :user_signup => { :email => 'new@localhost', :name => 'New Person',
@@ -210,7 +251,6 @@ end
describe UserController, "when signing out" do
integrate_views
- fixtures :users
it "should log you out and redirect to the home page" do
session[:user_id] = users(:bob_smith_user).id
@@ -220,18 +260,21 @@ describe UserController, "when signing out" do
end
it "should log you out and redirect you to where you were" do
- ActionController::Routing::Routes.filters.clear
+ old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
+
session[:user_id] = users(:bob_smith_user).id
get :signout, :r => '/list'
session[:user_id].should be_nil
response.should redirect_to(:controller => 'request', :action => 'list')
+
+ ActionController::Routing::Routes.filters = old_filters
end
end
describe UserController, "when sending another user a message" do
integrate_views
- fixtures :users
it "should redirect to signin page if you go to the contact form and aren't signed in" do
get :contact, :id => users(:silly_name_user)
@@ -269,7 +312,6 @@ end
describe UserController, "when changing password" do
integrate_views
- fixtures :users
it "should show the email form when not logged in" do
get :signchangepassword
@@ -340,7 +382,6 @@ end
describe UserController, "when changing email address" do
integrate_views
- fixtures :users
it "should require login" do
get :signchangeemail
@@ -486,7 +527,6 @@ end
describe UserController, "when using profile photos" do
integrate_views
- fixtures :users
before do
@user = users(:bob_smith_user)
@@ -502,6 +542,13 @@ describe UserController, "when using profile photos" do
post :set_profile_photo, { :id => @user.id, :file => @uploadedfile, :submitted_draft_profile_photo => 1, :automatically_crop => 1 }
end
+ it "should return a 404 not a 500 when a profile photo has not been set" do
+ @user.profile_photo.should be_nil
+ lambda {
+ get :get_profile_photo, {:url_name => @user.url_name }
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+
it "should let you change profile photo if you're logged in as the user" do
@user.profile_photo.should be_nil
session[:user_id] = @user.id
@@ -535,8 +582,6 @@ describe UserController, "when using profile photos" do
end
describe UserController, "when showing JSON version for API" do
-
- fixtures :users
it "should be successful" do
get :show, :url_name => "bob_smith", :format => "json"
diff --git a/spec/fixtures/comments.yml b/spec/fixtures/comments.yml
index ed1925bfa..b73385a55 100644
--- a/spec/fixtures/comments.yml
+++ b/spec/fixtures/comments.yml
@@ -8,4 +8,13 @@ silly_comment:
user_id: "2"
created_at: 2008-08-13 01:25:17.486939
+sensible_comment:
+ id: 2
+ body: This a wise and helpful annotation.
+ info_request_id: 106
+ visible: t
+ comment_type: request
+ user_id: 1
+ created_at: 2008-08-13 01:25:17.486939
+ updated_at: 2008-08-13 01:25:17.486939
diff --git a/spec/fixtures/files/incoming-request-pdf-attachment.email b/spec/fixtures/files/incoming-request-pdf-attachment.email
new file mode 100644
index 000000000..1163725ec
--- /dev/null
+++ b/spec/fixtures/files/incoming-request-pdf-attachment.email
@@ -0,0 +1,543 @@
+MIME-Version: 1.0
+Received: by 10.100.197.1 with HTTP; Sun, 8 Jan 2012 01:16:15 -0800 (PST)
+Reply-To: bar@frob.com
+Date: Sun, 8 Jan 2012 09:16:15 +0000
+Delivered-To: seb.bacon@gmail.com
+Message-ID: <CACwNqZkZDZiLtxD=CmE55kBGCBgnDVS1YGtrdC=tOhz+8dpokA@mail.gmail.com>
+Subject: Hello
+From: EMAIL_FROM
+To: FOI Person <EMAIL_TO>
+Content-Type: multipart/mixed; boundary=0016e644b8d0e3913b04b600bbe4
+
+--0016e644b8d0e3913b04b600bbe4
+Content-Type: text/plain; charset=ISO-8859-1
+
+PDF attachment enclosed.
+
+--0016e644b8d0e3913b04b600bbe4
+Content-Type: application/pdf; name="fs_50379341.pdf"
+Content-Disposition: attachment; filename="fs_50379341.pdf"
+Content-Transfer-Encoding: base64
+X-Attachment-Id: f_gx5ul6jw0
+
+JVBERi0xLjUNJeLjz9MNCjIwNCAwIG9iag08PC9MaW5lYXJpemVkIDEvTCAyOTYwNy9PIDIwNi9F
+IDExNTE2L04gNS9UIDI5MjMzL0ggWyA0NjUgMjQwXT4+DWVuZG9iag0gICAgICAgICAgICAgICAg
+DQoyMTEgMCBvYmoNPDwvRGVjb2RlUGFybXM8PC9Db2x1bW5zIDQvUHJlZGljdG9yIDEyPj4vRmls
+dGVyL0ZsYXRlRGVjb2RlL0lEWzxBRjMzQjg1MTFGOUJDMjI5RDlFMDM1QzI3RTBFODIyRT48MzM0
+QjkwQThFRDQ0OTg0MUJDMUM3QTE5NkM3NzNDRDg+XS9JbmRleFsyMDQgMjFdL0luZm8gMjAzIDAg
+Ui9MZW5ndGggNTcvUHJldiAyOTIzNC9Sb290IDIwNSAwIFIvU2l6ZSAyMjUvVHlwZS9YUmVmL1db
+MSAyIDFdPj5zdHJlYW0NCmjeYmJkEGBgYmDaCCJ8gQRjCJBgeQ4k2BOAhNA5IHHvLwMTI0M0kMXA
+wEgG8Z+R6StAgAEA0IkH/g0KZW5kc3RyZWFtDWVuZG9iag1zdGFydHhyZWYNCjANCiUlRU9GDQog
+ICAgICAgIA0KMjI0IDAgb2JqDTw8L0MgMTQxL0ZpbHRlci9GbGF0ZURlY29kZS9JIDE2NC9MIDEy
+NS9MZW5ndGggMTQwL08gMTA5L1MgNzQ+PnN0cmVhbQ0KaN5iYGBgYmBglgORrM4MfAwIwMfADIQs
+DBwHHPrW+F8MPsDA9aTIgkHq4Tpx3gL2BvYG9YYKhgq4FFAHFwND1W8gzQrEbCAjGEMYeBkYlpyR
+ZF8yo/UCSISbgaH2MEgGiI6DLWHoug3hM3QBMQ8DQz2IBjqHOxAszrwASAkyMMy5CdXmDhBgAPuw
+HeMNCmVuZHN0cmVhbQ1lbmRvYmoNMjA1IDAgb2JqDTw8L0xhc3RNb2RpZmllZChEOjIwMTExMTIy
+MTUwMTQzKS9NYXJrSW5mbzw8L0xldHRlcnNwYWNlRmxhZ3MgMC9NYXJrZWQgdHJ1ZT4+L01ldGFk
+YXRhIDE1IDAgUi9PQ1Byb3BlcnRpZXM8PC9EPDwvT3JkZXJbXS9SQkdyb3Vwc1tdPj4vT0NHc1sy
+MTIgMCBSXT4+L091dGxpbmVzIDI4IDAgUi9QYWdlTGFiZWxzIDIwMCAwIFIvUGFnZUxheW91dC9P
+bmVDb2x1bW4vUGFnZXMgMjAyIDAgUi9QaWVjZUluZm88PC9NYXJrZWRQREY8PC9MYXN0TW9kaWZp
+ZWQoRDoyMDExMTEyMjE1MDE0Myk+Pj4+L1N0cnVjdFRyZWVSb290IDM3IDAgUi9UeXBlL0NhdGFs
+b2c+Pg1lbmRvYmoNMjA2IDAgb2JqDTw8L0NvbnRlbnRzIDIwOCAwIFIvQ3JvcEJveFswIDAgNTk1
+IDg0Ml0vTWVkaWFCb3hbMCAwIDU5NSA4NDJdL1BhcmVudCAyMDIgMCBSL1Jlc291cmNlczw8L0Nv
+bG9yU3BhY2U8PC9DUzAgMjEzIDAgUj4+L0V4dEdTdGF0ZTw8L0dTMCAyMTQgMCBSPj4vRm9udDw8
+L1RUMCAyMTYgMCBSL1RUMSAyMTggMCBSL1RUMiAyMjAgMCBSL1RUMyAyMjIgMCBSPj4vUHJvY1Nl
+dFsvUERGL1RleHQvSW1hZ2VDXS9Qcm9wZXJ0aWVzPDwvTUMwIDIyMyAwIFI+Pi9YT2JqZWN0PDwv
+SW0wIDIwOSAwIFI+Pj4+L1JvdGF0ZSAwL1N0cnVjdFBhcmVudHMgMC9UYWJzL1MvVHlwZS9QYWdl
+Pj4NZW5kb2JqDTIwNyAwIG9iag08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvRmlyc3QgMTAwL0xlbmd0
+aCA5MDEvTiAxMi9UeXBlL09ialN0bT4+c3RyZWFtDQpo3qRW227bOBDVp/AxeXAp3kmgMOA4cRJg
+3QbrtCkQ5IG1GUeoLAWyim1/fncPKduRi6ZtHAv0kHPhcEZnhuKMk5xwJggzDFQS5uJaEa4i1UQq
+B2qIkxbUEsYUhMwRxi04PCdM5QITBlNjMOFRjM04uAo7vn1L3/lVOLoIfhGaSV23oTmm198fA30/
+Pqcf1n4ZoDNugm/r5rK6r59WR//+l42yedZkdfY581mbkewqO80m2RSrL1mAhGQue5Mx0HtoxfVN
+ootjOvv6uY1+Rk37T918GQ7pFZydlWEVqhZetvKLyTD9bunleHzi12GBGHJk5u87aL2/Ive+XOO4
+V1PC6Gy0Wc6mJH+T8y6Us2/t+az1baD1YycfDmE7Ws/hirA8V3TsHy9CsXxIy5yehk424Lmjk9Iv
+10RwOqmr9uSk/nY7wAuAyBAmpUkWd0k48aui/H70MTQLX/njxIv5pRtOYszaJrTzB/qubla+TKyb
+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
+nt6KLkxW8wKXBDiU1bOOPROv9YgGm+pPWzMW/SuZyvylk3QL3YNhFjMyyuLAJnAwSGBG/yUCtz3y
+hNMTXSZpUblPUtR7QIBtfTqer0WN5w7Qi11AIQ8t38bJj6tj0gWFPOk7RN/tLXrpbL9TMGPJ5upv
+ErISAzH6KfWuZuzklTxRqPYpniXq7BWQi7vaGxn7jA28ahgYQTeOM/1OZKCa5thEX8uB0Ywo9fvH
+n4xmNrC9nxPqfD7TJEIH7XwOh/kV/nP8Wrh3KC0Od6lqti3mths5ubCKOdRmmnXNFuzCtVsLHCpk
+4tnYMIk9WguPnBzVbddk7MkudN+u0ypfmn/ATlTiqRK7NVBvWNHRX1N0NJxx/s9tRO1C1GSjbegY
+BAbFzFvRdmlUctZMsZkHrOuLbYE8uFXIeaGTY+Seq/cU1lg420tqVHtlzr/VLVayle5owdBo2OVA
+6VIvJbzIH7pIuHQ1ItpJjXBkX2DxaF0Y1bat2vDh2iR/ozbWi8vsbW2Oy+qRfQIXhOLdFTLGvbqr
+UFUIXdyXHJsoVpZ2pe0r906dGjuWBEYJg9jf6c34Isl6YZ65vzVqb8nzwWqY2OH8y0rlK5EqneJL
+pUS6RncL/6pUqtzCo391Vf6ARfs6gWgpDyAgkcc51gsfU/168eg/7JfqdSfB/1hiH6jAn5u7e/GE
+uTUq7up2dw1YSwLmTrfQY7FG+2TU1XHbVhgnCJvp11xqkkYNV+bOdycgSCSDlHP8P1rA1IS6X3+F
+4tTd0Ul7KCJNNL0XtNjkSf/57PxfgAEA+xIfxA0KZW5kc3RyZWFtDWVuZG9iag0yMDkgMCBvYmoN
+PDwvQml0c1BlckNvbXBvbmVudCA4L0NvbG9yU3BhY2UgMjEzIDAgUi9GaWx0ZXIvRENURGVjb2Rl
+L0hlaWdodCAyMjUvTGVuZ3RoIDQ0MDIvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGgg
+MzAxPj5zdHJlYW0NCv/Y/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8MDA8V
+GBMTFRMTGBcSFBQUFBIXFxscHhwbFyQkJyckJDUzMzM1Ozs7Ozs7Ozs7OwENCwsNDg0QDg4QFA4P
+DhQUEBEREBQdFBQVFBQdJRoXFxcXGiUgIx4eHiMgKCglJSgoMjIwMjI7Ozs7Ozs7Ozs7/8AAEQgA
+4QEtAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEA
+AAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGh
+sUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0
+lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhED
+ITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2
+dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQAC
+EQMRAD8A9VSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkk
+lKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUp
+JJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkk
+klKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSU
+pJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkk
+kklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSS
+UpJJJJSkkkklKSSSSUpJQstqqbute1jfFxAH4qQIcAWmQeCElLpJJJKUkkkkpSSSSSlJJJJKUkkk
+kpSSSSSlJJJJKUkkkkpSSSSSlJJJJKUkkkkpSSSSSlJJJJKUkkkkpSSSSSlJJJJKUkkkkpSSSodW
+630vo1TLupXiiu12xjiHOl0THtBRAJNDVRIGp0fIPrz1LNzvrHm15L3eni2upoqJ9rWt0BA/lcyu
+k/xT9TzX5OX0173WYjKhawEyGO3BsN8N0o31gu/xbddyPtd+e6jKIAfbS143Acbg6sg/Fb/1KZ9U
+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
+CxG2tqL5vr9Gxx2/RBceGtDZ957KLfq9hsxqMeqy6o42/wBO5j4sAtM2N42wfCNOy1EkOI908I7O
+Ufq10vYK2te2sSAwOMAFtVcfdU1R/wCbHTyaSXWuGMSKGuLXBjCWu9Mbmn2y0efmtdJHjl3Vwx7K
+SSSTUqSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSS
+SSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJ
+SkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKS
+SSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJ
+JSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklK
+SSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJJJSkkkklKSSSSUpJJ
+JJSkkkklKSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl
+8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXy
+qkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp/9kNCmVuZHN0cmVhbQ1lbmRvYmoNMjEwIDAgb2JqDTw8
+L0FsdGVybmF0ZS9EZXZpY2VSR0IvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCAyNTk3L04gMz4+
+c3RyZWFtDQpo3pyWd1RU1xaHz713eqHNMNIZepMuMID0LiAdBFEYZgYYygDDDE1siKhARBERAUWQ
+oIABo6FIrIhiISioYA9IEFBiMIqoqGRG1kp8eXnv5eX3x73f2mfvc/fZe5+1LgAkTx8uLwWWAiCZ
+J+AHejjTV4VH0LH9AAZ4gAGmADBZ6am+Qe7BQCQvNxd6usgJ/IveDAFI/L5l6OlPp4P/T9KsVL4A
+AMhfxOZsTjpLxPkiTsoUpIrtMyKmxiSKGUaJmS9KUMRyYo5b5KWffRbZUczsZB5bxOKcU9nJbDH3
+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
+/qb8sa0eW5sLJAr4BcPbbLfVbEdt527v32G+Y/+OT4XswmtFJkXlRR+KWcXXvjL9quKrhZ2xO/tL
+LEsO7sLs4u0a2u2w+2ipdGlO6dge3z3tZfSywrLXe6P2Xi1fVl6zj7BPuG+kwqeic7/m/l37P1TG
+V96pcq5qrVaq3lE9d4B9YPCg48GWGuWaopr3h7iH7tZ61LbXadeVH8Yczjj8tD60vvdrxteNDQoN
+RQ0fj/COjBwNPNrTaNXY2KTUVNIMNwubp45FHrv5jes3nS2GLbWttNai4+C48Pizb6O/HTrhfaL7
+JONky3da31W3UdoK26H27PaZjviOkc7wzoFTK051d9l2tX1v9P2R02qnq87Inik5Szibf3bhXM65
+2fOp56cvxF0Y647qfnBx1cXbPQE9/Ze8L1257H75Yq9T77krdldOX7W5euoa41rHdcvr7X0WfW0/
+WPzQ1m/Z337D6kbnTeubXQPLB84OOgxeuOV66/Jtr9vX76y8MzAUMnR3OHJ45C777uS9pHsv72fc
+n3+w6SH6YeEjqUflj5Ue1/2o92PriOXImVHX0b4nQU8ejLHGnv+U/tOH8fyn5KflE6oTjZNmk6en
+3KduPlv9bPx56vP56YKfpX+ufqH74rtfHH/pm1k1M/6S/3Lh1+JX8q+OvF72unvWf/bxm+Q383OF
+b+XfHn3HeNf7Puz9xHzmB+yHio96H7s+eX96uJC8sPCbAAMA94Tz+w0KZW5kc3RyZWFtDWVuZG9i
+ag0xIDAgb2JqDTw8L0NvbnRlbnRzIDIgMCBSL0Nyb3BCb3hbMCAwIDU5NSA4NDJdL01lZGlhQm94
+WzAgMCA1OTUgODQyXS9QYXJlbnQgMjAyIDAgUi9SZXNvdXJjZXM8PC9Db2xvclNwYWNlPDwvQ1Mw
+IDIxMyAwIFI+Pi9FeHRHU3RhdGU8PC9HUzAgMjE0IDAgUj4+L0ZvbnQ8PC9UVDAgMjE2IDAgUi9U
+VDEgMjE4IDAgUi9UVDIgMjAgMCBSL1RUMyAyMjAgMCBSPj4vUHJvY1NldFsvUERGL1RleHQvSW1h
+Z2VDXS9Qcm9wZXJ0aWVzPDwvTUMwIDIyMyAwIFI+Pi9YT2JqZWN0PDwvSW0wIDIwOSAwIFI+Pj4+
+L1JvdGF0ZSAwL1N0cnVjdFBhcmVudHMgMS9UYWJzL1MvVHlwZS9QYWdlPj4NZW5kb2JqDTIgMCBv
+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
+b8f62e11vON51u8m7JtegW7OOnTeWQvI2mrcrCSXdcUYMpHBTk6ScY63jOsiSHPuYhkwbQy5LLaY
+DVGASIyIXdtVSEbbBZQiSbEz9t3yxM5lYUBwglaOvbMlo7mSnez29K3G6/G4dw/x69K5XrsAWZhv
+3oz+ekMgXtDFYLCtptbUWYhtltT11L/2ekJzgFgn12Qxr5cIBVVBFzfFU1MnzywhvasVTUTqL/L+
+pjuiHxTMYLi54p9vrisTpt9dy445jQTWooWp+fBfSl/ihv6CS+oQDa0KI+a0mbr2drphIrcDZM+5
+NqUaXArChsH1DrHnhTbXQgYvLBckrJtKYc8j/0TKh/qy3pEXjhc2GCBf6/4h2ooizStssYxrjKq9
+dPa3tdltqcWGpZqwvtWabqcZrGZ3Umu5h+fZ3Z18hZXdvUJa7OMAd7DIiePQo5XM87EFnmdP1Vqf
+Dhxm76TUCMhsaZ4+sS3y3fClKeDHe8CiumCeaB3s5PDq0hc1zbuvy4xJk9QToylt36S0HH0dBa7n
+hCbSGBcJjA6F2Qlp9/wCxbm7zkl9KHJtNq0XtGhxoj+fR/8TYAA9ZWkRDQplbmRzdHJlYW0NZW5k
+b2JqDTMgMCBvYmoNPDwvQ29udGVudHMgNCAwIFIvQ3JvcEJveFswIDAgNTk1IDg0Ml0vTWVkaWFC
+b3hbMCAwIDU5NSA4NDJdL1BhcmVudCAyMDIgMCBSL1Jlc291cmNlczw8L0NvbG9yU3BhY2U8PC9D
+UzAgMjEzIDAgUj4+L0V4dEdTdGF0ZTw8L0dTMCAyMTQgMCBSPj4vRm9udDw8L1RUMCAyMTYgMCBS
+L1RUMSAyMTggMCBSL1RUMiAyMjAgMCBSL1RUMyAyMCAwIFI+Pi9Qcm9jU2V0Wy9QREYvVGV4dC9J
+bWFnZUNdL1Byb3BlcnRpZXM8PC9NQzAgMjIzIDAgUj4+L1hPYmplY3Q8PC9JbTAgMjA5IDAgUj4+
+Pj4vUm90YXRlIDAvU3RydWN0UGFyZW50cyAyL1RhYnMvUy9UeXBlL1BhZ2U+Pg1lbmRvYmoNNCAw
+IG9iag08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDIzMDE+PnN0cmVhbQ0KSIm0V11v27gS
+ffevmEd5sZZJ6sPyYrFAPtrbXqA37Y2BfUj7oEh0rFtbciUqbv79nSEpiXKUbLfAokBrq9Zw5syZ
+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
+2sacOR7HhmG8bj8SkhZUGgKsTzA4VfVX2rp5+tS8PGULHWY0EhQLEzhIvOLkUMwjIwDngGEbajPN
+ernhZjM6If0X9pv4wf2WTO+34Gf3m+i5Lc7X27vqJB9l/evzPuI1T74CG02XGK4KExI30hAk8dRC
+WtgwowViqYBbCGNqfaevg/5POdhu4nmXkuaC4+dz8vMI4bXMjPz3UVaDdwm6nPgoJb0pzL1DUZ0H
+HOQsVZ0ROkBbqjM7oPMRzOfd4CCnOVy0D21D113OfXgnjZk4A3pgub2vmiguQZ1psZh33FN9muY2
+IvOp3S2My1n70brnDaJMM/2iUPSMfLOZLS9qVVBbiZsXSqUZOby75WWlFOr7l+XlZfUd7mJBviVc
++RGPAwhY5MdxyAEfc4Flflnetvfq6Shh+baqSMmWG/3tY/qAJWnOdIS/uQIcAgb62+VmdOHtFxFB
+zegfc3DUwXmwY4EFizXNAdclB7qkzezbLGDcD3WmMYo+oc1DP0TqzP6EcnzccIh9KWKmmv4UjGhw
+or8+zf4vwAAUVrhNDQplbmRzdHJlYW0NZW5kb2JqDTUgMCBvYmoNPDwvQ29udGVudHMgNiAwIFIv
+Q3JvcEJveFswIDAgNTk1IDg0Ml0vTWVkaWFCb3hbMCAwIDU5NSA4NDJdL1BhcmVudCAyMDIgMCBS
+L1Jlc291cmNlczw8L0NvbG9yU3BhY2U8PC9DUzAgMjEzIDAgUj4+L0V4dEdTdGF0ZTw8L0dTMCAy
+MTQgMCBSPj4vRm9udDw8L1RUMCAyMTYgMCBSL1RUMSAyMTggMCBSPj4vUHJvY1NldFsvUERGL1Rl
+eHQvSW1hZ2VDXS9Qcm9wZXJ0aWVzPDwvTUMwIDIyMyAwIFI+Pi9YT2JqZWN0PDwvSW0wIDIwOSAw
+IFI+Pj4+L1JvdGF0ZSAwL1N0cnVjdFBhcmVudHMgMy9UYWJzL1MvVHlwZS9QYWdlPj4NZW5kb2Jq
+DTYgMCBvYmoNPDwvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCA5NjY+PnN0cmVhbQ0KSIl8Vdtu
+2zgQfddXzKO0gCiSom5FUSB2mt0sELTZCNiHNA+KRNvctUVXouPm7zukJMsx0iJAYjPknMsccr57
+FHLBISkSQjmEuWAkT6GT3r9/QOt99yihMdjVIn+zCb/aTW5P9OcDhXXvMSGIYAWlaQwUfxjNQQhK
+4rgoClzLYgH1zotudxSutXfvRVedUauqNvDxY3RlTFVvZAOPUan38BQtFvoHPKac4LGsQMgYa3CW
+kjQXGeQ0JYIjuafo4fBsXvcSor9k1cgOotJ9+1qtVVsZpVv49GlxvQREvPcWpRd9WUJ0t6TgFif2
+UVkiZShXXoiiKcWPNbiPLIHyCIwPojhMlMRAoNx5/j9yJTvZ1vIDwM1DQuOsiAWDoPzP+3yHIJ/L
+4a9FPxM98kJoNkBTC0rfhUtz7MwINxeOvlrv7pa317h5LvdbJTGEnPAYPzfeo7/Uu53qe7RJdgRu
+W6iCUPhN00lcbNdgNsFT+bfnKvG5Uu5IpoSKxBJuPF9CrXf7bYWmt+Yb57yH2vKclRS5UyI4nhqU
+cEGyXAwFHn0dcB897NoeUSU43EGCQwvH3SEjnF2wDxLfCoBN1cOxU8bIFox2ZWp9aOu51si8IGkx
+Eldb2Hf6RTVW7vqgmgpJAMZGtQbJVFtndzgcmcH9Tr4oeeyhahuQP5zywbDK4Jo77Q46BcJ11uLH
+Ft93dYcK0G/0YdvMe/OTzYNwnpJisvnRh2cJFdKT0BvsVeKvgzD2R7vo3KF08Gw4e+4Ziq2xuQNR
+hx1gw4OQ+7CWaGK13b5aEGxnEGb+3v5nKw1ezaMyuHVjF1QLnMJRd/9bzU312hMYKFzmkk25HBRl
+p4iHQxBHN9He91LN4f1LwkgaT8lz/ZlTP8M4RO4MZyROTxaWmzdhxdQEqd9DV6keVVbQHnYXbnLn
+JstInJ2qPGPe9ApNsY/O3lplA4xtx0g864O5DHE898ZRCsdyZ5FyWVXb8fZYhsqFEY3fuHI3X26v
+rNrLPmMpkZ+YEbAKz2+2uxiqXeluJ939du2eb7aYlU7UbL3z2JjJNLxrVcD8wTrjvDNByHxLsJew
+q/D2dT00ai5/9gRl4/Wjs5ENtNrACnMHxyBMfRSL8bJ4fa3xKUeTN6o/C/gQn7HImX2qfZG9UWv3
+6pM3z++vZs1CG6N3F+NGZCRhOG1impA0xYccl9nFsLnR2vxu2LydMvbhPwX08m1PpnhMTzsq44V9
+LZiTJZyQEkdtTBkRjl+a4v+xAsMpNI3iX4CMhxI6aJgHyDiU3K9776cAAwDczA1EDQplbmRzdHJl
+YW0NZW5kb2JqDTcgMCBvYmoNPDwvQW5ub3RzIDE5IDAgUi9Db250ZW50cyA4IDAgUi9Dcm9wQm94
+WzAgMCA1OTUgODQyXS9NZWRpYUJveFswIDAgNTk1IDg0Ml0vUGFyZW50IDIwMiAwIFIvUmVzb3Vy
+Y2VzPDwvQ29sb3JTcGFjZTw8L0NTMCAyMTMgMCBSPj4vRXh0R1N0YXRlPDwvR1MwIDIxNCAwIFI+
+Pi9Gb250PDwvVFQwIDIxNiAwIFIvVFQxIDIxOCAwIFIvVFQyIDIyMCAwIFI+Pi9Qcm9jU2V0Wy9Q
+REYvVGV4dC9JbWFnZUNdL1hPYmplY3Q8PC9JbTAgMjA5IDAgUj4+Pj4vUm90YXRlIDAvU3RydWN0
+UGFyZW50cyA0L1RhYnMvUy9UeXBlL1BhZ2U+Pg1lbmRvYmoNOCAwIG9iag08PC9GaWx0ZXIvRmxh
+dGVEZWNvZGUvTGVuZ3RoIDE1NDI+PnN0cmVhbQ0KSIm0V1uPm0YUfvevOE8VjsJ4btxWUdS9eNNN
+kybdRcpDtw8sxjapDQ7gdfbf98wAZoyxU0WqvNZimPOdy3duXIWjyWVRpfMoruDNm7dvr26uYTR5
+90BhUY4mYUiBQTgf2ZRQSvEyBn3JHAh3wDhQ/OA/lxMhwQskkZwKCNcj6z6ZJ0WSxckFwO2DQ4UX
+CMlgHH5VuKzGpQqRKiwKNicMRW9GVnuItodsJyABdbqHLCA8ALQED8xGlqPuTT+i6dNBh76NBGVE
+SpAecV2UQ5MZ2gpFMvoC2egqNNR1XjVCjjrfeKW1oxKt7E8EpuBLDk7gEMrB9iUjvqthXyEuPiYo
+qO4G/sEh/Nno/jZiEk1hAaWuqDVTH6SkRIggCPCeh6GN16PJ3ZrCTY5a1UeZ/Bk9nHy8vrtBoZa6
+MORN1BRj3p4xxBxiTDhoSstYulhWkM8h2mySaAVgRtWlxMfzzCMORlEQx8cwSu3FvGcMM4w5yB9v
+z3bfDtf3iGjt4JTsNRuw3IA104cRVzgKdnacOb2s9bRuItz2/DStlkkBm6ioXmAZlYA/odBxqPI2
+DgpTI8kOSQP5hNU4f1nRIhq7VpqVKLhMS7hJ4rRM8wz+yKs0ThSagh7/Hb6vsXiHpZmxNZrNCFe1
+pSBv06Ks7CpF+8IifdpmaMqjNZbW3ZhZ2Twv1lGlNCja8E5VogGPYwJ3xrPoKd9WWnPtS1lb0C9n
+6jQl2KjHMtsUeZyUJayjF3hKIH+qojRLZjAv8vWFkRoGQaIlaNBBhomDJf5T7jW+QW19X69s9Yav
+EPfd/TX8Au/ux7a0Pu+hy9cnhJ1WeB+IGLqQIKL1+RNc5d8hEJS+HnbcPcQQneeiBfkwvbuePoTT
++xMQ3gEE61OjPfswZeDfvB/brnXCGX/PgNlXkVTetc6+THBovEGbPEqKMFldAMVAYOUK6WBBDEIy
+ajBi3UbfUYgxF7gMQHJHnJBiB/kj9i4okOk6SlF3J/ewibJOtOsN1zi64rLuLgBlnI06XiXx3LZg
+0y7FqiZHxo71K+bech1XJVlgJpZjbqVkkT+T7T915cKi6Tk4fw6bzpE3Q9XABQkCx6hy60vyVKZV
+cqGH2r4pMmyw0gUHZ1Qg666IlAgMoSF6MhjyR8Fw6yRXeE00drsd+Yr+b8c2t8oqxcsYnU8a5yeL
+rbo1i3CcYyVO4nxbVKUdZTO762g6xLaOsWFlG9xyMuwiRTvc2kVE8eRBC+yElfqOMVu3aIR0LP1A
+WT1LvpNlhb/Wg6XBnK42Fk2VuQ2V0nVbKoe5dA/qyuY+8U8wYQgdlnQ9/FQqczY43pj/k/PNaDdB
+f77dzeEl38IuLZfGQMNhpSdV1B9Tr/XpGJOp7vfd6Ot3c+WIUUKAf8t8Z+pY5dlCy5vrh2+UzQ5n
+bz1vDzNDUg+zHqTvEK9ZCXBuuEEAtiCubFIjwUpdJc9RVoGyotSDqTdj+5Nf1R+j5pS1zGG5H0O7
+uijJiWwIBojVjcoWxoSzOB9eY+j/wPNl9tJuGri/XdYUlMt8u5rh9O5YONrgHeL6bROAMimek9nY
+9izFp4plFxIkC/OB+4MrDA3qFUajGdF9tOJolWSzqMDhPYteSmWdwp1FVaJ07JZpvM+xzjheG4d5
+wFoPl8N7Fd4qk6w6QRVnA3txRxcumkqBwdkwCjfH2fAR8eMj8mAg7BcN7vXH9EO6UJvWI6eO+T2s
+Re2Bb6RA//h//R69bKlUVC8qZ8cb7/YmLCoR/LAdcveYiqONwz3aOG6jlwQeNuo9shjG9Q63vyLf
+bvSG9DHKokVS6HTtudfEzqXnXfRPWex2FnOdSDWWOblUX1EbaNtbrlVV5diz1uu0VAmcFI+c8xI+
+zeeYx9rik6biiAr8s6YGZ01VV6J5y9BQ5gLyEq/S+TyB3/JtmQwlQxMtT5yzQAy8gQ7Ta2so0wLs
+BQV8iLLT2l3ieWe5EgOFbqqvAUyl6WpdrnBiDah0iM/OKuMDXaXTpcUNVdfLpFymxaB3DjlfZkKc
+8ivoN18NZah9+D0A5/L2VEglcb0jzdNw9K8AAwBBYUiqDQplbmRzdHJlYW0NZW5kb2JqDTkgMCBv
+YmoNPDwvRmlsdGVyL0ZsYXRlRGVjb2RlL0ZpcnN0IDUvTGVuZ3RoIDI5L04gMS9UeXBlL09ialN0
+bT4+c3RyZWFtDQpo3jK0VDBQiDYyB5JBCkZmEMoURMUCBBgASDEFUQ0KZW5kc3RyZWFtDWVuZG9i
+ag0xMCAwIG9iag08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvRmlyc3QgNTYvTGVuZ3RoIDYxNy9OIDgv
+VHlwZS9PYmpTdG0+PnN0cmVhbQ0KaN7EU0tP3DAQ/is+0sPGbydGCHWXdgUSQhVL2UorDibrJi6J
+s3KcAv++thMWikA9cKisscf2PD7PfCYIIEAwYLwAhABRYEAoyGVYGJAoLBxIEUwEwEjmgOQAE8rA
+0RFcqF4vO+vhtXZbZdXszKvGlPCrLbutsRVcGzu3vdnvl8b1/qRWDlACo+cX3ZfO7HznIgQELuG5
+miwwK+BquPWPOw2v3KCvkhKnlHJttr7uN5QTgP4ajLMkUaeC7WdBxV7QNL89REHjLIu04zkf4yaA
+L6wQnawZEHiMJuWb8UIRRagpJ9MqBYi4RSw3paGiDFAWMUZN5jSdCpQn6ygsFD16U8nSHQ/dKXAR
+VpL0t98RLdC7g3EZ5eb4OHRy3pfa+tBgxOGJ2p1qU9Vpi2BsUbybESThslFVH+iQerBYdA+bGaY4
+3gVWMIGTy026XarWNI8HEzU+pbML1erXZInnK++0L2t40blWNeloPUJgAcFoOLdVo8EMc7jyur0O
+1Mwow8+MeKYS/PECf3reCn6/PItyUHu/O4Tw/v4++zX03pQ6q7rf2XAHq8EEWKWGZTc438+U3c68
+M7eDVU0PnzVjf0aU3nR25mKaeLTVD1nt20//NVurTOO7wxcuT3E+123p+6zqzZR/dJ3HDx8/3WKV
+Aq3Gai46t9UOrkEo3rTZJM6ExgIGT+EZvNSl32AsQgsAK2hGAqUZKjJEOWAyz/LiJrTJDaX/plxk
+T77/y+fG3o155tZ2/gkI/QiQnGZMpMRFLuJvyWjgIsckrK+AiH8BYR8HEhMzPlaEIxa+rsgkewWE
+vw/kjwADAFqkkmYNCmVuZHN0cmVhbQ1lbmRvYmoNMTEgMCBvYmoNPDwvRmlsdGVyL0ZsYXRlRGVj
+b2RlL0ZpcnN0IDYwL0xlbmd0aCAzNjAvTiA5L1R5cGUvT2JqU3RtPj5zdHJlYW0NCmjedJJrT8Iw
+FIbPTzkf4dO6djcMISEQjImBRUnwgh8Qa1wcm9kF5c+rbzsgoJBm69m5Pn1XGbFg2WHfZSXYDSNW
+sKR5WPkdVoq9ULDy2BeI+ex34Aw4UBF3u84gr7OKPWeUFGVl+gi+ca4XsNHN2NPNh3YmdZUmmS57
+PZT0TbkJjfVXZRobO14UGo1k1BQlVapb3z80ooI01gvltCLG+xXvK8qw54itaEEVJbAz+Pu0xBeT
+JGEX07yFFhMU9Gnebu/GuydGxoVemzMfjY+ppmdKMWBp29do/2YHJ7A2dAGvWTNgpMjUiJT0afPf
+4Y/hN7klqpgGqKwBuoQnJW5who9SNHLc3T9wIDnwAs7qNH1ybp3LfJrvoNWBZuLsAbzjAwytPnoP
+yuRaXcZAWcO/2kI3mrnknoMKT0P5B1DyHNT2VhxAaatBuf9xGfbKqqZPAUhPcogr+Y/gOM0FTuh7
+f9J+BRgAu1mrqw0KZW5kc3RyZWFtDWVuZG9iag0xMiAwIG9iag08PC9GaWx0ZXIvRmxhdGVEZWNv
+ZGUvRmlyc3QgODI5L0xlbmd0aCAxODA0L04gMTAwL1R5cGUvT2JqU3RtPj5zdHJlYW0NCmjexFhd
+b9s2FP0rBPa8iZffBIoCbbqiWdImaDrsIciD06iZ19QOFGdY//3OFS8d25Eda+02IM6VyKNzP3lJ
+yUallU2KtFE2K2OMclr5YJUjFZxXzqhMpJxVRM4p/JFJuPeKbAYqKHIEWFQUPOZBFQkyQ+asvFaU
+QlSeFOUMZqMMaae8hS6Lewfpg/IeMiVoVsYSZISMVvmkjON72OZgVdDKeJ1UIEiQBPD5jHvwBRgZ
+wBdSVgF8MXoVwJdgP0wwCeQBfBm+BvBl61UEX45GRVJWa9wjDBo+Q7XV4I1OWfYbVJZgfwzKGhtU
+jJAJuKQsLlTMkAAnRNMZrRAi66AcEOvJqAQ+D2cS+AL8T+ALCFICX4TyBL6UgQdfNpDgyzAOKp0G
+PiPkGsHNnB8o5dAb+JERasM4pMDyfYBEPnOEhLNwwTnoRyqcA440CL01uOAkxpJ5FwzyqjmdPQak
+UfMIJxZRIg3aiJiRBm/Co4QcuGR5BMwJYSMCc+anuFwyyoeg1+XIlYNE6n4KmddcEygZr2EsEXJv
+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
+DeYE5oAdPDmZzPLBUPR98g0Vsnl2OZmfrZfPp6eNXYkpnyGA7okL5kN1t3h6rDNqKoXP6+eTL+vN
+r8UjHLOfi6/9GntLnjH2NWZ+2wJ0BpgekimhGrI6IwMwDl9PoDOymZCPK7oM0P0sXkA2HWcJGRD7
+i/YSeBwQuFzBsk9FeHefplRCnl3LncWslb/J+ajW46Khuy41aMluthEAdEhpGnCz0k2Zm0aJ0HHX
+SbL8Yrf9GagiZ7Zy7jADX1ChjLGMdkBGvhTJ+6MSe3Bd4GYQ3KUCL4mYdDwR3MX9m4IWcXCepBG2
+tYsdtdVyhIrcPsf+KdLN8Q79Wtt9DF1a+fR786aWyRS+Xyu8aPkurXxfve/Xmuae1vSfT9Vi+bC6
+f6eVKU1oe7O23juoVwxNUxrro//Bxwz2iW1zLUmXPtblvF+W4th0tVFaTY8b6RLGu8RBecjb9boC
+aZRnechGOfBYBz3WwYzbRR626+Vd2S0WuwGech3luiXbe2Vzu0rhTa7ckpLr5UoZ499sJfnHRNJ9
+XDr/mEg8sDpw0MNqElPboorrsWcrlgeoiSF3+2QOnq2mum1lWtK+5+oc3pm/9QxH+ffCKe9j8sfD
+yT882+xc16NdDt/2WOzaP66WF6tltapJvVeTr5P54nn9VE8ufy9+VtO7utrk9fx5Vt2tN1XzXS82
+dfFjFbFyVf2pp48P96vGlr8LwHjYf2weajSQz+tlNZlvrm7/k7jakz7HUrXZ1Vad0n8FGABNHxW9
+DQplbmRzdHJlYW0NZW5kb2JqDTE0IDAgb2JqDTw8L0ZpbHRlci9GbGF0ZURlY29kZS9GaXJzdCAx
+My9MZW5ndGggNDQvTiAyL1R5cGUvT2JqU3RtPj5zdHJlYW0NCmjeMjIwUDBQMDIwBGIFGxt9v9Lc
+4miIgIFCUKydHVAsWN/Fzg4gwAC4WAlEDQplbmRzdHJlYW0NZW5kb2JqDTE1IDAgb2JqDTw8L0xl
+bmd0aCA0MjMzL1N1YnR5cGUvWE1ML1R5cGUvTWV0YWRhdGE+PnN0cmVhbQ0KPD94cGFja2V0IGJl
+Z2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxu
+czp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNC4yLjEtYzA0MyA1
+Mi4zNzI3MjgsIDIwMDkvMDEvMTgtMTU6MDg6MDQgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5z
+OnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAg
+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0
+cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWNy
+b2JhdCBQREZNYWtlciA5LjEgZm9yIFdvcmQ8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHht
+cDpNb2RpZnlEYXRlPjIwMTEtMTEtMjJUMTU6MDE6NDNaPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAg
+ICAgPHhtcDpDcmVhdGVEYXRlPjIwMTEtMTEtMjJUMTU6MDE6MzVaPC94bXA6Q3JlYXRlRGF0ZT4K
+ICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxMS0xMS0yMlQxNTowMTo0M1o8L3htcDpNZXRh
+ZGF0YURhdGU+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgICA8cmRmOkRlc2NyaXB0aW9u
+IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpwZGY9Imh0dHA6Ly9ucy5hZG9iZS5jb20v
+cGRmLzEuMy8iPgogICAgICAgICA8cGRmOlByb2R1Y2VyPkFjcm9iYXQgRGlzdGlsbGVyIDkuMC4w
+IChXaW5kb3dzKTwvcGRmOlByb2R1Y2VyPgogICAgICAgICA8cGRmOktleXdvcmRzLz4KICAgICAg
+PC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAg
+ICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAg
+ICAgICAgIDxkYzpmb3JtYXQ+YXBwbGljYXRpb24vcGRmPC9kYzpmb3JtYXQ+CiAgICAgICAgIDxk
+YzpjcmVhdG9yPgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaT5t
+aWxib3VybmVqPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC9kYzpj
+cmVhdG9yPgogICAgICAgICA8ZGM6dGl0bGU+CiAgICAgICAgICAgIDxyZGY6QWx0PgogICAgICAg
+ICAgICAgICA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPkZyZWVkb20gb2YgSW5mb3JtYXRp
+b24gQWN0IDIwMDAgKFNlY3Rpb24gNTApPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOkFsdD4K
+ICAgICAgICAgPC9kYzp0aXRsZT4KICAgICAgICAgPGRjOmRlc2NyaXB0aW9uPgogICAgICAgICAg
+ICA8cmRmOkFsdD4KICAgICAgICAgICAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ii8+
+CiAgICAgICAgICAgIDwvcmRmOkFsdD4KICAgICAgICAgPC9kYzpkZXNjcmlwdGlvbj4KICAgICAg
+PC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAg
+ICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIj4K
+ICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+dXVpZDpkMTA5Zjg5Mi1iMTUyLTRlMjMtOWRjMy1l
+ZjNkZDAxMjdkOGQ8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlE
+PnV1aWQ6ODY4YWY5ZjUtOWQwMi00ZDg0LTg5NjUtYTg4MDhlY2NjZTljPC94bXBNTTpJbnN0YW5j
+ZUlEPgogICAgICAgICA8eG1wTU06c3ViamVjdD4KICAgICAgICAgICAgPHJkZjpTZXE+CiAgICAg
+ICAgICAgICAgIDxyZGY6bGk+MzwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpTZXE+CiAgICAg
+ICAgIDwveG1wTU06c3ViamVjdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6
+RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnBkZng9Imh0dHA6Ly9u
+cy5hZG9iZS5jb20vcGRmeC8xLjMvIj4KICAgICAgICAgPHBkZng6Q29tcGFueT5JbmZvcm1hdGlv
+biBDb21taXNzaW9uZXJzIE9mZmljZTwvcGRmeDpDb21wYW55PgogICAgICAgICA8cGRmeDpTb3Vy
+Y2VNb2RpZmllZD5EOjIwMTExMTIyMTQ1MTE5PC9wZGZ4OlNvdXJjZU1vZGlmaWVkPgogICAgICA8
+L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSJ3
+Ij8+DQplbmRzdHJlYW0NZW5kb2JqDTE2IDAgb2JqDTw8L0ZpbHRlci9GbGF0ZURlY29kZS9GaXJz
+dCA2L0xlbmd0aCA2NC9OIDEvVHlwZS9PYmpTdG0+PnN0cmVhbQ0KaN4yMjBSMFCwsdF3zi/NK1Ew
+1ffOTCmONjIwA4oGKRiCSWMwaQomzUFkrH5IZUGqfkBiemqxnR1AgAEAHocQmg0KZW5kc3RyZWFt
+DWVuZG9iag0xNyAwIG9iag08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvRmlyc3QgNi9MZW5ndGggMjMz
+L04gMS9UeXBlL09ialN0bT4+c3RyZWFtDQpo3mzPTWvDMAwG4L+io32pP9IcOkohLBTGKCt0UBi9
+JLbC3CXWsB1K//3UMlgP00lIL4+Q1RVoWK9VM5dPSmIKY09ziniW6pmm7y5exUscKE1dCRSBZ1PI
+mVtMGd6GITjkZML7uu0KivbJasNlram1qeqP3z3rjUvUdwX27XbXfWGC1cIA43Ck5KV6xeuFmyyk
+2pH/B1tWjO0T+dnhn9aGXMI43jm90HASxxA9XfJJSnXgbxwyF4aA/tFb1sasODD3Z3SFb76HMqLY
+JkRPE9AAj483roDV+qYfOH4b1ZoPbDY/AgwAP1hmow0KZW5kc3RyZWFtDWVuZG9iag0xOCAwIG9i
+ag08PC9EZWNvZGVQYXJtczw8L0NvbHVtbnMgNC9QcmVkaWN0b3IgMTI+Pi9GaWx0ZXIvRmxhdGVE
+ZWNvZGUvSURbPEFGMzNCODUxMUY5QkMyMjlEOUUwMzVDMjdFMEU4MjJFPjwzMzRCOTBBOEVENDQ5
+ODQxQkMxQzdBMTk2Qzc3M0NEOD5dL0luZm8gMjAzIDAgUi9MZW5ndGggMTE0L1Jvb3QgMjA1IDAg
+Ui9TaXplIDIwNC9UeXBlL1hSZWYvV1sxIDIgMV0+PnN0cmVhbQ0KaN5iYgACJkadPwxMDEz+QILz
+I5BgBLOcQWIWQIKFGyRmDiTYfECsSpDECRBxHEhw5AMJ5kcgiS4gIXgdSDDMBcm6A03uA3MZQQQD
+I0GC8Sdx6iCKf5CgeJQYFgTj3NEwIDfoDsFYTP/BWRIgwABfDBGsDQplbmRzdHJlYW0NZW5kb2Jq
+DXN0YXJ0eHJlZg0KMTE2DQolJUVPRg0K
+--0016e644b8d0e3913b04b600bbe4-- \ No newline at end of file
diff --git a/spec/fixtures/files/quoted-subject-iso8859-1.email b/spec/fixtures/files/quoted-subject-iso8859-1.email
new file mode 100644
index 000000000..6ada69905
--- /dev/null
+++ b/spec/fixtures/files/quoted-subject-iso8859-1.email
@@ -0,0 +1,462 @@
+From: =?iso-8859-1?Q?Coordena=E7=E3o_de_Relacionamento=2C_Pesquisa_e_Informa=E7?=
+ =?iso-8859-1?Q?=E3o/CEDI?= <geraldinequango@localhost>
+To: FOI Person <EMAIL_TO>
+MIME-Version: 1.0
+Content-Type: multipart/related;
+ type="multipart/alternative";
+ boundary="----_=_NextPart_001_01CCB66F.F38B15FC"
+Subject: =?iso-8859-1?Q?C=E2mara_Responde=3A__Banco_de_ideias?=
+Date: Fri, 9 Dec 2011 10:42:02 -0200
+
+This is a multi-part message in MIME format.
+
+------_=_NextPart_001_01CCB66F.F38B15FC
+Content-Type: multipart/alternative;
+ boundary="----_=_NextPart_002_01CCB66F.F38B15FC"
+
+
+------_=_NextPart_002_01CCB66F.F38B15FC
+Content-Type: text/plain;
+ charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+=20
+
+Senhor Benedito,
+
+=20
+
+O Centro de Documenta=E7=E3o e Informa=E7=E3o (Cedi) da C=E2mara dos =
+Deputados agradece o seu contato.
+
+=20
+
+Em aten=E7=E3o ao solicitado, informamos que a C=E2mara dos Deputados, =
+por iniciativa da Comiss=E3o de Legisla=E7=E3o Participativa - CLP, =
+criou um "Banco de Id=E9ias" com o objetivo de registrar e reunir =
+id=E9ias de interesse da popula=E7=E3o. As sugest=F5es s=E3o organizadas =
+por temas e ficam =E0s disposi=E7=E3o para consulta de entidades da =
+sociedade civil e parlamentares, que poder=E3o adot=E1-las, =
+aprimorando-as ou n=E3o, para serem transformadas em sugest=E3o de =
+iniciativa legislativa, no caso das entidades da sociedade civil, ou em =
+proposi=E7=E3o legislativa, no caso dos parlamentares. Cabe ressaltar =
+que a Comiss=E3o reserva-se o direito de editar ou resumir os textos =
+recebidos.
+
+A seguir, o endere=E7o eletr=F4nico do Banco de Id=E9ias:=20
+
+=20
+
+http://www2.camara.gov.br/atividade-legislativa/comissoes/comissoes-perma=
+nentes/clp/banideias.htm/banco-de-ideias
+
+=20
+
+Atenciosamente,
+*****************************************************
+Coordena=E7=E3o de Relacionamento, Pesquisa e Informa=E7=E3o - Corpi
+Centro de Documenta=E7=E3o e Informa=E7=E3o - Cedi
+C=E2mara dos Deputados - Anexo II
+Pra=E7a dos Tr=EAs Poderes - Bras=EDlia - DF=20
+70160-900=20
+Tel.: 0-XX-61- 3216-5777; fax: 0-XX-61- 3216-5757=20
+informa.cedi@camara.gov.br <mailto:informa.cedi@camara.gov.br>=20
+*****************************************************
+
+mbb
+
+=20
+
+Solicita=E7=E3o:=20
+
+=20
+
+ Prezado(a) C=E2mara dos Deputados,
+
+ =20
+
+ Gostaria de sugerir que o sal=E1rio de quem trabalha com pol=EDtica
+
+ seja vinculado ao sal=E1rio m=EDnimo.
+
+ =20
+
+ Atenciosamente,
+
+ Benedito P.B.Neto
+
+ =20
+
+ -------------------------------------------------------------------
+
+ =20
+
+ Por favor use esse endere=E7o de email em todas as repostas para =
+este
+
+ pedido:
+
+ leideacesso+request-120-9702221c@queremossaber.org.br
+
+ =20
+
+ Caso este email - informa.cedi@camara.gov.br - seja o endere=E7o
+
+ errado para fazer acesso a informa=E7=E3o por favor nos contate e
+
+ aponte o endere=E7o correto atrav=E9s desse formul=E1rio:
+
+ http://queremossaber.org.br/pt/help/contact
+
+ =20
+
+ Aviso: Esta mensagem e todas as respostas ser=E3o publicadas na
+
+ internet. Leia sobre nossa pol=EDtica de privacidade:
+
+ http://queremossaber.org.br/pt/help/officers
+
+ =20
+
+ Caso voc=EA ache esse servi=E7o =FAtil, por favor entre em contato.
+
+ =20
+
+ =20
+
+ -------------------------------------------------------------------
+
+
+------_=_NextPart_002_01CCB66F.F38B15FC
+Content-Type: text/html;
+ charset="iso-8859-1"
+Content-Transfer-Encoding: quoted-printable
+
+<html xmlns:v=3D"urn:schemas-microsoft-com:vml" =
+xmlns:o=3D"urn:schemas-microsoft-com:office:office" =
+xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
+xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" =
+xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta =
+http-equiv=3DContent-Type content=3D"text/html; =
+charset=3Diso-8859-1"><meta name=3DGenerator content=3D"Microsoft Word =
+14 (filtered medium)"><!--[if !mso]><style>v\:* =
+{behavior:url(#default#VML);}
+o\:* {behavior:url(#default#VML);}
+w\:* {behavior:url(#default#VML);}
+.shape {behavior:url(#default#VML);}
+</style><![endif]--><style><!--
+/* Font Definitions */
+@font-face
+ {font-family:Calibri;
+ panose-1:2 15 5 2 2 2 4 3 2 4;}
+@font-face
+ {font-family:Tahoma;
+ panose-1:2 11 6 4 3 5 4 4 2 4;}
+/* Style Definitions */
+p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:11.0pt;
+ font-family:"Calibri","sans-serif";
+ mso-fareast-language:EN-US;}
+a:link, span.MsoHyperlink
+ {mso-style-priority:99;
+ color:blue;
+ text-decoration:underline;}
+a:visited, span.MsoHyperlinkFollowed
+ {mso-style-priority:99;
+ color:purple;
+ text-decoration:underline;}
+p.MsoPlainText, li.MsoPlainText, div.MsoPlainText
+ {mso-style-priority:99;
+ mso-style-link:"Texto sem Formata=E7=E3o Char";
+ margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:11.0pt;
+ font-family:"Calibri","sans-serif";
+ mso-fareast-language:EN-US;}
+p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
+ {mso-style-priority:99;
+ mso-style-link:"Texto de bal=E3o Char";
+ margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:8.0pt;
+ font-family:"Tahoma","sans-serif";
+ mso-fareast-language:EN-US;}
+span.TextosemFormataoChar
+ {mso-style-name:"Texto sem Formata=E7=E3o Char";
+ mso-style-priority:99;
+ mso-style-link:"Texto sem Formata=E7=E3o";
+ font-family:"Calibri","sans-serif";}
+span.TextodebaloChar
+ {mso-style-name:"Texto de bal=E3o Char";
+ mso-style-priority:99;
+ mso-style-link:"Texto de bal=E3o";
+ font-family:"Tahoma","sans-serif";}
+.MsoChpDefault
+ {mso-style-type:export-only;
+ font-family:"Calibri","sans-serif";
+ mso-fareast-language:EN-US;}
+@page WordSection1
+ {size:612.0pt 792.0pt;
+ margin:70.85pt 3.0cm 70.85pt 3.0cm;}
+div.WordSection1
+ {page:WordSection1;}
+--></style><!--[if gte mso 9]><xml>
+<o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" />
+</xml><![endif]--><!--[if gte mso 9]><xml>
+<o:shapelayout v:ext=3D"edit">
+<o:idmap v:ext=3D"edit" data=3D"1" />
+</o:shapelayout></xml><![endif]--></head><body lang=3DPT-BR link=3Dblue =
+vlink=3Dpurple><div class=3DWordSection1><p class=3DMsoNormal><span =
+style=3D'mso-fareast-language:PT-BR'><img width=3D566 height=3D58 =
+id=3D"Imagem_x0020_1" src=3D"cid:image001.png@01CCB65F.2FD5C970" =
+alt=3D"Descri=E7=E3o: Logo Corpi_html_1cd70d8a"><o:p></o:p></span></p><p =
+class=3DMsoPlainText> <o:p></o:p></p><p class=3DMsoPlainText>Senhor =
+Benedito,<o:p></o:p></p><p class=3DMsoPlainText><o:p>&nbsp;</o:p></p><p =
+class=3DMsoPlainText>O Centro de Documenta=E7=E3o e Informa=E7=E3o =
+(Cedi) da C=E2mara dos Deputados agradece o seu =
+contato.<o:p></o:p></p><p class=3DMsoPlainText><o:p>&nbsp;</o:p></p><p =
+class=3DMsoPlainText>Em aten=E7=E3o ao solicitado, informamos que a =
+C=E2mara dos Deputados, por iniciativa da Comiss=E3o de Legisla=E7=E3o =
+Participativa &#8211; CLP, criou um &#8220;Banco de Id=E9ias&#8221; com =
+o objetivo de registrar e reunir id=E9ias de interesse da popula=E7=E3o. =
+As sugest=F5es s=E3o organizadas por temas e ficam =E0s disposi=E7=E3o =
+para consulta de entidades da sociedade civil e parlamentares, que =
+poder=E3o adot=E1-las, aprimorando-as ou n=E3o, para serem transformadas =
+em sugest=E3o de iniciativa legislativa, no caso das entidades da =
+sociedade civil, ou em proposi=E7=E3o legislativa, no caso dos =
+parlamentares. Cabe ressaltar que a Comiss=E3o reserva-se o direito de =
+editar ou resumir os textos recebidos.<o:p></o:p></p><p =
+class=3DMsoPlainText>A seguir, o endere=E7o eletr=F4nico do Banco de =
+Id=E9ias: <o:p></o:p></p><p class=3DMsoPlainText><o:p>&nbsp;</o:p></p><p =
+class=3DMsoPlainText>http://www2.camara.gov.br/atividade-legislativa/comi=
+ssoes/comissoes-permanentes/clp/banideias.htm/banco-de-ideias<o:p></o:p><=
+/p><p class=3DMsoPlainText><o:p>&nbsp;</o:p></p><p =
+class=3DMsoNormal><span =
+style=3D'font-size:10.0pt;font-family:"Arial","sans-serif";mso-fareast-la=
+nguage:PT-BR'>Atenciosamente,<br>****************************************=
+*************<br>Coordena=E7=E3o de Relacionamento, Pesquisa e =
+Informa=E7=E3o &#8211; Corpi<br>Centro de Documenta=E7=E3o e =
+Informa=E7=E3o &#8211; Cedi<br>C=E2mara dos Deputados &#8211; Anexo =
+II<br>Pra=E7a dos Tr=EAs Poderes &#8211; Bras=EDlia &#8211; DF =
+<br>70160-900 <br>Tel.: 0-XX-61- 3216-5777; fax: 0-XX-61- 3216-5757 =
+<br><a href=3D"mailto:informa.cedi@camara.gov.br"><span =
+style=3D'color:windowtext'>informa.cedi@camara.gov.br</span></a><br>*****=
+************************************************<o:p></o:p></span></p><p =
+class=3DMsoNormal><span =
+style=3D'font-size:8.0pt;font-family:"Arial","sans-serif";mso-fareast-lan=
+guage:PT-BR'>mbb<o:p></o:p></span></p><p =
+class=3DMsoPlainText><o:p>&nbsp;</o:p></p><p =
+class=3DMsoPlainText>Solicita=E7=E3o: <o:p></o:p></p><p =
+class=3DMsoPlainText><o:p>&nbsp;</o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 Prezado(a) C=E2mara dos =
+Deputados,<o:p></o:p></p><p class=3DMsoPlainText>=A0=A0=A0=A0 =
+<o:p></o:p></p><p class=3DMsoPlainText>=A0=A0=A0=A0=A0Gostaria de =
+sugerir que o sal=E1rio de quem trabalha com pol=EDtica<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 seja vinculado ao sal=E1rio =
+m=EDnimo.<o:p></o:p></p><p class=3DMsoPlainText>=A0=A0=A0=A0 =
+<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0Atenciosamente,<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 Benedito P.B.Neto<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 <o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0-------------------------------------=
+------------------------------<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 <o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0Por favor use esse endere=E7o de =
+email em todas as repostas para este<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 pedido:<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 =
+leideacesso+request-120-9702221c@queremossaber.org.br<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 <o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0Caso este email - =
+informa.cedi@camara.gov.br - seja o endere=E7o<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 errado para fazer acesso a =
+informa=E7=E3o por favor nos contate e<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 aponte o endere=E7o correto atrav=E9s =
+desse formul=E1rio:<o:p></o:p></p><p class=3DMsoPlainText>=A0=A0=A0=A0 =
+http://queremossaber.org.br/pt/help/contact<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 <o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0Aviso: Esta mensagem e todas as =
+respostas ser=E3o publicadas na<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 internet. Leia sobre nossa pol=EDtica =
+de privacidade:<o:p></o:p></p><p class=3DMsoPlainText>=A0=A0=A0=A0 =
+http://queremossaber.org.br/pt/help/officers<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 <o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0Caso voc=EA ache esse servi=E7o =
+=FAtil, por favor entre em contato.<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0 <o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0<o:p></o:p></p><p =
+class=3DMsoPlainText>=A0=A0=A0=A0=A0-------------------------------------=
+------------------------------<o:p></o:p></p></div></body></html>
+------_=_NextPart_002_01CCB66F.F38B15FC--
+
+------_=_NextPart_001_01CCB66F.F38B15FC
+Content-Type: image/png;
+ name="image001.png"
+Content-Transfer-Encoding: base64
+Content-ID: <image001.png@01CCB65F.2FD5C970>
+Content-Description: image001.png
+Content-Location: image001.png
+
+iVBORw0KGgoAAAANSUhEUgAAAjYAAAA6CAIAAAAsiYQwAAAjEUlEQVR4nO2dB3gc1bn336nbm7pV
+rWZZkiU3ucmWcQMMGBsbguFiMARM5wMSQhIuaf4INyEkfOAvBG4IJU8uJU5CQlxkXHDFvajYlixZ
+stUsraTVStt3p9wzK1vI2tVom4rx/J71ejRzznvec2b2/OedOXOG5Hkerjd48LjdLp7v6eg4eKil
+utr21NMzdDpVxMt58slDb789O+JmJSQkJK4TyNF2YETgwNhqbbf0dHa7a+vOXjjTve1Ia6PLxtT2
+YOCeV5wql5dEvEye544f/xOAJFESEhISIUKyLEsQxGi7EXm6Ozvr66znu7u6WhpPNeDlZ6qbWxos
+1tgeM9B0N01NpDEdF63p5OpWr1spkw1HC2A0rRgGsxISEhLXC6TFYtFqtTiOj7Yn4dLGgOXc+bNV
+5hMnjp902C4Z7W2tqYzNbOjp6WJcGKVUEuPieZVbaSYZttN2AjxUjjJ+6dLxJZPVo+27hISEhIQf
+BImSyWQKxTV4vs+7zpg7vjrN7tlf4d5daoSoSme6zeHOtVpO82Q6rm/BPZMxeRUpswIFzl3gxFPj
+49MTYm4riC0snlyQNylaFaXRYAqVWN3dYG2zNtW26fft33fvzEnZubkjVj8JCQmJ6xxSLpezLDva
+bgRHp7E1fd1HCS5bS22djSKAYPPxJVWYy8Db1Tx2GtcU8vvLSRIIrhUfn8elFk5z3nrbf86YgSWM
+SyEppbhxj4exOaytra2fNTTtKd/ZRDXWwDmADoqO/WnKwZGpoISEhIQEglQqlWVlZcXFxaPtSRD8
+9jfvWE63OFXj4nQ3UsDlcthBRwtOGLioTlqrydfZp1E5zxWXTJmSmplDavXJIqbcLt7E28w95nZo
+O2w5e7Su63jTkfNdh4B0A0GBigYghEElLH17zApQC5dDOY7DvIxUdSUkJCSuU0iapnmedzgc18q1
+PjvAH76oK9Le2I67bOBKZvFOueu5NSkTycycfENGujo1c5zISEXGbW+zQQN/qb6pvsl5sbazu5xr
+rK6rMrOnAZcDgQvKpNYAXH1zjnGsnbIEvPrUO8BEkigJCQmJ4YakKCo2NtZoNKalpY22MwHxt7+d
+MssID8ZcBK4QCYnjQuGD+W88e69YHgcc7Gw/6yi/dPHSWeeZGkdXC9/e1NIAhAlwEjACaPQdN3h+
+Bhzxy9Nm9v6B9OlbMLpEQkJCYuwjRBtRUVEXzp9PTkwkKGq0/RkS+46NNTnAVAMkA3QDxXa1vLLq
+Md90RmisaTRt9Bw1VXeUmU42e6wWtsftcALuAcwjXL5TorrrAyrTbfn13B/0BmaSOElISEiMGEK/
+G20wnNRoqru782JiRtufQeB58F5Y++wvxz6r3eYm587CPBgQZbaq79wbn5OYIKTh3MAzQCj/q3br
+J9terCjHoAgD5srcGUJ2HGjs8r2lIIp2azxZD0xYFfE6SUhISEiII3TWGEFMUCguVVUxs2eTZG8n
+PsZgu4HUG43wyy3lbld+gZwGYM5xHiC45x54SLh7hMDRSvpM85lf7vq/NhTqzCSBQSu9d4ywy/+C
+hwc393zRwoQ4kcuAEhISEhLDwuV4Ii09/UhtbUxDc1ZG/FiUKFIP4Ppwx66KKnsRHVMHzRQkm2x1
+K1dkp+Xl9E/46xObbW470DSwWIiq1B/OlSYvWDPhobANSUhISEgEzTeXvObOnb/3zOaMlJU8Phan
+RGqub930wYEcJpakeQIYl8eeksz8dNWUKPk3QrSxav+nbZuA5EONmQbAggu/f8pt2fHxkbAWLhj2
+C57/2Wh7ISEhITFyfCNRiUrZzKTJn1V/eu8k0dFxo8TqX/3rQENDpsbAARfFpTaD46lbCqfMLkKb
+XC6XTCazdJne3vemm2kHYoiHcwOC54DBc9NueGLugghYCwwkQt+Uf7Ua9erTWFCpXifDd6N/ZSNi
+cLBSArccqapJSEhEiqsGDmSMyzxTdnZfx76SBSVjanrZ+95648BXddGaNAPYCd5Q7Xbrki8++sLT
+vVuRPqHv9Sff3O2sBFlE9IkH3iOjYt6Z+qNEMiECBgOgf/+Ilgf0rb3L377ec7D6RoQBKighIXHN
+MXBs27Kly35/9Peq88ppmdN7XyU16s+objhy8ONfnsKSFxMYR8I5K9sJxJmvX/mdQejg+F733jZ+
++PqJP4E2PkKX+FAIRXy46jfzE0dBn8BfCNW33LepL0vf1r7l/tl98wayZkgPxX0L0Gb/BANUKpAq
++673TQNXB1LiZoejahISEuHgZ/j1g9kPfv7lVgr0BRkZMFr6xLm9I/TgzW3nvv/8/0QlLUrBPD2A
+WZhxp7kz7z+zJq/IICRjWSDJ4+cOPPX5i2BIjVTZ4DA9n/niPYlFETIYFgN62AHRRt8FwP7LfWlE
+8vZfL2K/bz1c3e8PWD8gr3hEGEiVRbL7VtMvfpXMt6YjXDUJCYmg8CNRKr3qhhuX7NyzW+F2Z43W
+xN44Dx54/69HXt/w70nUJAVut0GjjSPqSetzD9320LrFvakwkvzk4rmndzwO+qQIFcyBTf7g5KW/
+W/RUhAyGi2+g47vVdzmQvIGn6Z848Ktnvd13xHvwkA0O2ZKjXjUJCYkB+H+INcWgWTVv9ptbdy5S
+9sxNmzXCPnmRPf3OV++9/1EGl0tTJAasBTijqf37jyx//albgbcBJrzH/V9njz+/d70JIwCL0KQP
+tu510xb/6ob/jIy1CDHYmX6k8oZj3y/9AzsIVVSG405S+DWNSNUkJCQCZLB5FnBtTMKLa+776L0P
+Ghacvzf7P4bdkStzQ/T+VfjdtypONEZDTBPFZQMcY6mUjoRn7pr7+svLOJbFvckOna1Yt+sn7Xgj
+EHQEbkHxLDg61xYseO2GH+kDnBhpRAi/lxfPO0xdbf+QJbSrYcM0eiJ8s+FXTUJCIkD8SxTvfbJI
+xtseXffQF5tLf3j4Lz9fdadCqeibiCjyeOeGQP//+eOKn7z4ywZdbLRsei7OHgVwOZ286sRr/7Vm
+9ZqFQkJCeO7pwZb3/rzpZWF8BBYJfUIC6SF/nvfqz5asCb8qIeB7DwnG5Bl6gMFHn/8Bxisi9fU7
+AER8TEdoDFPVJCQkwsG/RHEcB8KU3sLFtOW3LU07V7Oh9PObsibEjM/RsIxcqewd5x1BWLfn5Imz
+7/7lq/d3nU6JvSkO74nGuGqOZ60mfYb5r7/+3Xcm65BbgOP17S33nfjtwcqNoE0KY2YjL0JWDlwO
+nSr6g+wnVi6+L1LVCYE+ler70+/6cGyGn2ZAvxygzyJa6zeNeHbfcRBDutc3ZN+3psNXNQkJifDx
+L1EDnoiaPCE7Pln11cGvzBdborTRs2JjWjpa8/PzddERmHa2k4Hj24/8ed+R0s3nHR4iUT7VgbNa
+3sg5OlyE8pGbdY+/9Pzkcd5Z+FjXf1/8x893fHbJVQOa2HCDJ5S72wM2Ys6sWb+d9Mic5Hnh1yVM
+Buvv/K4fbKCEb4c+pLVA+tnBBsQH5XPgCYLdGqB74i0ZqapJSEhEisDm/OaZBGXCykV31ZVVbXac
+LD25a65m8c5N+/F2a1F+8c23JAFcHVSxNvBGYKJ4jtSe++Dfx45Ud9Udwwhrp1KZnk4ZyoCVuVxG
+d/fC4qRXVhWvXDqPoAQnN5858Zfa/7/xUjnLuYBWhn1xjwfGDjLdT6Y99b0Ft+vxMXTzSUJCQkKi
+lwBfS4GjLl2OyfKmTE52pX2kb9l5fmMSHZc/667N/7P7Fz99JTk19abFN5aUJCWPV6k0MYPok8fj
+sNpt3YePwFtf7SQrT5/yWKzGJAOrT6HVemVUPd9sdFd6zA554dT3X/zxPbPiFTIheLL0tK78/Hf7
+3AfcbhOQCiDCucbI984cAQ7L/fqFT9z/f+aQU8OwJjGiSOGLhMT1RmAS1W9It1amfyZX/0juCx8e
+eW/D18/e80hh0Zo3z+0/8oMvvjS/3ZjqcdPMDHYuFsfwE3CMw4Q3NO0GXEZgRDNVc7HGTRgBIzEs
+fyqG6bA5eozHif0nPdOB2B2FkwvTsz/53qLiG2YLJTGe3TV1rx78cHvPP4S3tBMkUENGZiLwwrR7
+LAsYn8rk/X3V94pGZzC9hISEhESgBPNyv34oQPXEzGefyOc2dO56ccOyWXPnvnjDfKWyZM8B07Gd
+5bgZ6hm+3ORwuO1gxYDrAtABkQV4XAI/TsWzaqLerZzcLnM5qZZxcRnfU9hm3Prs0rum6QFvc3Sd
+NFVv2Ltje837TbJ2QZYohXcYYchX9pAyMUjwoihDXtSk+8c/9OjsOaGakpAYSP9nra7nOE9qB4nh
+IESJuowKf0a15JnfLPnnmU2fHP2qprnVMDlh/t3x2nSV0pzgvOjs5rXq8yqcq7hEYZiTUmpoGcZa
+CXURvciSwidGcRnKhUVTFEatsvlizRcnPtnXVrGlvrLFXQm0DHRKgHBeJMgD5wHWA4wmNjZ5Ser8
+J5WF86YuBmyszI3rS6Qmf4tgHxHs8Hff8XIRcWO4CbPFhmkAeoCNP3aGF0oD8SUiTngSdYU78pbd
+kXdrVVNLhfH81srNm3bv7Sb1bKwzPio3LVWlwOkiKtvjpJVqWomzdkJJcJVOtulrjtjuNq3ffrHW
+w3a0XmAIs/AQLkGBMjr0mAkXBneA2wUMlqDOnZmZfot6Vn5mQUncxIjUdPiI1ORvY6GPuLamsAuz
+xfpGtEfIneAYO4/QjW47SHxbCVKimB4gtT4ru4HUIXGYmJyMPndOLW5sa67ounCk48BfT5/4ynIA
+SHILEQ0kDjgOHIEJ86dzPFgFHcJwb1iDgRJ9DzmsjvV+E0KE1Evv/yQPDO+dn8IN1XZKn1k8f+66
+6GlzUufHajQaKhKv5xhmfB/08d06YNOAuXwGTEA34Cng/nkDidUG6/iCivMGPJYknn0wP0WW+0cP
+fp/wHcygeIuJ+CmyIwJZ6Uvg7Rmm80O2hq9xEfeCqnKkrg1IXJ8EKVGExt/Kq0QLx6i0hPHoswwW
+rC8Bh9VR2rzr0wtHzTXnd1TXc4ntvBYHHikTdTlU6r3PhDRLUCDv29wHRlBIfsC7NQ3ADXDJu46/
+/I30aQ8Hc4g56iXzJ86fd9fCJXFR8uBqNaYRj66wq6f99ttZg08/Ih7l+HZegecNrSIhWO7/sO2A
+RhiyLPEWG5BY3KbfxAFWJ5xaizgvYtPvvh6sGcNvh9DqKCHRH38SxbOD3rDxO/uR6JRICrViZc5t
+6AM3I5FxdPRc+rD1rN1hP1txphEaGrAOYB12BuMxmwMIHHM67QxwWD+VQvqkkmswnAcZ30nRNF4W
+R0+i59Lz3Jw7KTVxXuzCuY8qErlkiNBEstcWw/qDH5VbCwHWSLznDce+b6wpYiSQxBEk4rtbpBnH
+cjtIXD/4kyjOGcCDt6FAgCJem/FDbYbwx2QAJ+fAcZujra4bc2DnGoCiiJa6OrPT2f81iizDTCgo
+JOUMpPBclCJWsUIRx8bh+qufjvq269PY+fGPHU+GJGRXB4sjw088WPaxyUi2g4SEX/xJ1PDokx/k
+uAKFWXR8jA6+GbyXOEKFX1uMncsjY8eTIQlnvEmAeYNK7Jcx254j3A4SEn4Z8l5U74CEMGcb6oX1
+jnQINpMTeJd3OMZVcF5IMjIjEkcdkVsp/RnhjkDkdDgQT0LzVnzgQwgMR6NF3OY12sVfo25LXEN8
+08WfONa69fM9u5w2wHGWxwmCxc4AY+JxGYbNAmAEhcm1ee76/rrFmYJimUzG997bb75k3k9SFNos
+QGDCwAakajgLWAqw6UB8DdgUljHGqTY8WrxtW90fD1UzNIUDzgA/HrBk4AjgDwDkAN4BWCaSHp7H
+eCJ7gnNSwe0zi8cBgaxpPE77S6++ddiaQhHQYzv04WPfzZ88Fcfxnp6esrKyadOmWq226urq8ePH
+YxiWlJRkNps7OjqMRmN0dBRBkCjZxIkT1Wr1qVOn9Ho9SoZ8Rem7urqmTZvW2dlZU1NjMBgKCgpG
+ZR/00qdSfX+Krx/Sjt+UgVgbcM88qLy9+E0jkt3vpsHcCISgGm1Aiw3IG6CTIZQe7J4NhAjaDL8d
+IuuPxPWJIFE95q4XX/h/724pB908wDQ4WNOwS/UwEQjPRJyosjrgC++booDYA+XvfHHPc9+55Y03
+HnS73Qf37flnVTZQJwGKvcp0GmCcMJEEtCIJGwf5rVDOQ9sOZnZCUoXpzhsry5nt/3KCEulZBUDK
+HrAAjPe6ge0Hkww6ScjqBoqFfbCJA9v2yVOK/rHh8Yx0hZMj39hvY5v+DeQ0MNn2P8LkA7S3t5eW
+lmZkZGzduqO+vmbGjBmxsXFr1tz3wgvfP3mybOHCBbt3750/f/6hQ18vW7bs5Zd/snr13RZLz549
+e5YvX56env7aa6899NBD27dv37lz18qVdzAMM6o7QkCkLxNfOdj4Pb95A+kmBtwGDzzvkGIQ1Ca/
+bgSy7Ndg4InFRUXclLiFoJKFUOvA/QnNeN/6ANtBZL2ERCAIEvXpriN/31Y7L3HBMdCSvMfqsOtY
+Qxw0tbP6KnBMhVN2KMRJppWOcuFF8RTzQdmRHzXdRispmYwcr+AS6JIuzqZw2Xk2vgZkTmjJhppW
+mB4HHVbQWSGbZ20xtD06pgePpaZocTlFV0NRjMfhYZouQA2APh1YK1Dt4AI4mwAxVjong0zUaxrL
+aw8/9rxh28ZHSQKTy2ilojCVGnfcWV3sdd1s7omNjUfK5HA4/vjH2paWlubmlscee+zQoUNmsy03
+N7ekpC0vb+KZM6f37duXnp7V2WmeN69YLpejGAtlz8zMnDdv3v79XyNxamlBKQdeS5SQ8EUaDtCL
+1A4SI4PwBtv9NV1WVTIPejd/MccRPftuxURtHMcxOCShWIWFFAfOnKl1nTxqNLNkN045HVBR0TV3
+rrYV4tuBNHAOULcvv60wJo5gXCqSNLqZDBLXsEBgnJEis1wuT3x8ulqt5Si2Dqez+XqKyOSnKOZk
+FS1wqyiy0+6Ji6JMbteEC+Bxy03E7todXY4sUpevnvTVoTM2t4uicRVoDKDuBg8Ik+4Jz0mlpCS1
+traUln5JUQSKilQqNU2TCoXigQfWvv766ygBTcs8Hndubt4NN5S8+eYb06dOPH78ZHv7pVtumYK2
+qtXqzZu3pKamzJkzOzU1qaOja3T3hMTYR7r10ovUDhIjBolxQBtxnECdPsY5L6TdWvzOz28A8L5C
+ULh2d3mgREer/bbHf1V1+GA6JecJS0NjU45iCkckZYPVwzmVGvvj3711XPoQj8wyTbzWdZZXRBmx
+inWLV76ytoRzA064WZYmCNbKEG6UiPa0fadt5tI/WeO0POhY2T6LoyeaNniAd4Dw9JMV2At8+mQA
+FA+VoECpzRgbG2O1Wu12O1Kd6OholUq1fv16ZAkFWDiOozVoee0DD+oNBqU6iqZnIRlDa9asWeNw
+OJOSEidOnOjN7oArrxtGuYTK83zfoAxM9NkviesEqVPuRWoHiRFDuNBH4leWHfiSe3VX9An6DeRj
+YhKwTR+96Oi2AM8ROBkbH2PpbjaxjPAiKUx+2j7+51v+lZ5OMAyKcmYDHPLmzcDAxEEHwVK3JqdO
+mTEH59lmSEsEFfAKGhfu/eA0+qK97/gl1JeH+1FReclTM+FkV3UqOfE8htttjhhDlBbA4b3H1Qp4
+PN4GgOI8buvWrfX1DU8//YRWq/3007/PnTs7Pz/38OHDlZWV999/f2dnZ1xcnMVirag4uGDBgp4e
+i8lkqqmpOX369KpVq5DCxcfHVVRUVFdXo/Xz589vbcWjopCG0R9//LHBYLjlllu2bNmi0+nQpt27
+d1+8eHHt2rUjt2euffo/KCN1ahIS4XDd/ppIJCnlgjqRLFQCdMVhk/wmQ59YJF46dd+qZkqWRmJb
+AKajOKjb8t9vHwKW9D5D+6VwKU7QORQU5QsPPDm/rF98zx9nAJZL8Lsrj3iKCkDp5jkRt+QLZjCf
+baVJHkU0bW1t6akpnV4nEgDqAGes7ShNQ0MDim/uumvlW2+9qVDoVt99x8lTZb/4xd+XLFm0YsWK
+Tz75BIVTc+fOPXXq1BtvvJGennHgwL59+75+9NF1zz13Y2dnx8MPP/Lss8/GxsYWFBSUlZWhWOqF
+F15AsoSkCGU/fvy42Wyura3NyMjYsuVLvV5z5513vvrqqy+99FKE90A/BgyfG74iRuwQD/OORbDe
++h1RFtkiws84woTTo4XQnhFhZNo28FLGyIjEYbr/N0zdTqR2IomUJN07FK/x8ox5/MAkPILhMQrH
+XP1fAB/rZlvYU6mQRmPkbF7rgFgMyCqIdQIrh+o8yGsApgOYSXxLpSxXXSjcQ4KzDFiKchRYFZhX
+sGJuZXOwHUxOMAKPabUa5AGSPjOSUGEjx6svP99LEER8fLzL5dZoOZ1ej+EIPjMzIyYmZtq0ourq
+s0J9eP6ee+4tLf1Sq1WjGOvYsWPl5WU33njjypXfQTo0c+bMcePGoZipsbEJWWtrM6JviqJmz57d
+3Nzs8XhQrFZbe3b16nvQglqtFnM6PL59s5n1DUcelXJhmJvxmtg7EenRRqY9/ZY4Fhgj5yLD9Gsa
+vm4nUnZQ8AQmYYHLgphmnPS0IyEYODU4z3lwkjpdYTzdZuIpHGf4otR4IkGmw6gLgLs4JkZpXH5T
+XlyCClgWE25hpbHA4t6QiuF5gsdmTssRDAlzmvNtgEVDD+BicxZVIzfw3EsoauJrZRTNeyeNRfLo
+vdnF2zjBQyQYPT09W7ZsQaGSTqdDIkTT1KpVq1BIdOzocYNeidTrwIEDWVlZKpXGYulWq3UorlKr
+NdHRBrvdlpc30eVKM5lMeXl5wgD6g4eeeuqpqqoaggCUq6WlBWW86aabjEbjtGnTKyrKkUoWFxdH
+pNF9GfAzGLB3RU5z/G7yXSn+LLDf7H4HFgdYXAiJfb3yuzXMM74hswdelwFORrAl+58s++YNvKC+
+lNjVc7yKt0DghHAw+PVQfDnYgob0UCSlSGtjVz9WP6QzIe/KYOsbzg4NodsZsqa+x2RQLvlCEt75
+w0uB64YYoAurdh+Em+4cUA+cFCThnxu3/XRLBy/Xk46uV1elrv3RigYMGBSHce5unePpJx9ITKX8
+F/INqLSabJhwAeNkctlgiTjOdmjfkWR6Mo/M87xaq+V7NeoKrHeWChQqzZ8/3263p6amoj+R/CQk
+JHjvMMWbu7qzsjPdHk9TY2NGhjAlIBIhmqY5DlpamiwWS2xsXGZmFoZhvYZRFJWRka5UqlJSUtxu
+149//NIPf/hDZAdtYhiGJMnOzg6TyZydnRVKG4eHyGmO+BmQSMcXSHbM3/ThvifUgxkJKrFfr3wj
+gDDP+IbM7tfnADOG35K+6X3zBlWQeK8R5imzX1MiBwOEep1qsIKGjO1CqKzvnhLX1MF+cb4GfY0H
+dbCFfGSGTMg1jaAPvZCoi/Z4UJnYKWCyZKk7d+6w/iHqjsxsT79HWSmCOGG8tPl4Zb4rq4Kt9Niy
+LLYeHcuqWL4eThZg02h797Yth9MzMnH8jNuT6Z01ibvyeifSyWPNCuaxhfEUhaQlHsfwNI969+fb
+zzV02TyeWQDHhEd/uQZgGgmgz9AO814D2Gw40ECQbkYnl/VKlAbpkLc1DFgXQBJSndOnTzc1XZo5
+05Wdna1UKuvr6xMTE3Ec1xt0n37695iYqFmzirZv3ymX0yUlJX/b+HFMtLzkhpV1dftyc3Pb29vN
+ZrNCoUDSFRcXd/bs2fLy8ptvvtlmsy1YsADpk9HYvmPHzsWLF6Ll6OgY9Ilgu48KQfURvseZ71mk
+SJYhEwfiQGjZQz6vDMTnEH5+wbakeF8QWd+Ggz6B9N0Uzj7tbzP8o8svEW9AkV0Z1ME2TPWNIMN3
+7JEYAYUoXPk3k6EgG/Hjarf7zbf/8jlAg6Az6NM7qI+LxZLdxLTx9BHg8yn10cL8h1sIsJEzUADG
+4PKD3UV7/rADuPeuTDnOeaeFzfZmPwqMKzFBuTR1nXdKPe1hjJ+MJ++saoEzGzN54h8Ak4D7J+j1
+kC/DmCYeK8Rz2mREEc+VOc9OL0yW0QoPzyFLvGAN2ccUYEdltLW1NTc3FxYWIAlhWfbkyZN79+5F
+EVVmZqZFwLRixa1bt27Nyso2Gts2bdrUabIkp2SUl5965plnysrK3n//z/n5OT09PSaT6fHHH//i
+iy8efviRxsbm7m4T2rp8+fJ3333nySefLC0tnTdvXlpa2jDtgFEnqOM+qNPhcM6dhzQrgvjvWTz7
+MPkc2YJGuKsSkfwBnvSPGHwTh8ZgNgNswLHcrY+FX9PYRxh0vuyW4rdLd1nLq1Px8RyOA8Zd4rFc
+1BqgBnB69YZngOMZo5UdDww7ZVrykqXj8S6LzN4KrvyjXIcgZrzG+4INbAJw5wQhQbnM8cKbdHOs
+HO7gPW4cGMYOzp5MvNwCOdnCAPLpLArdAG3ldBiYeVMqYJkYdLNcqhu3EF3T9d2/f+1ZUkY6bC5X
+l9vtMhlZClwec7cFvE8vNTU1O51Og8Gg0Wg8Hs/MmbN6err37v160aKSo0ePlZVVymQKuVy+aNGi
+9evXu1yu1tbW1atX33vvvRs2bFAqaRQwIdWsrj53/PiJnJychAQkdUxFRdm5c+fq6uqQzejoaBRj
+oYyjvZuGkcD7kaD6nQh2UgMI0OZglx1Esg+fz5EtaISjJZHixAPESF3z8bUZeAOOkcjSlxH7NfVJ
+2phtCnEEicpMSNn2yvqNG3fsudQY1W0Gq47ArDywnZDkgjpUNRno9JxDrVbRCdH/QU747sNrddGa
+7s62oiJDXEyNjAAGk7MYxWM8zVp6yJibGCQ/mIUgSY5xEPFxrktUvN4lN0yYcGlJSbeHnmgn9TJO
+xoGdwWQKtstGxiaxXTypUoCNF6RxXJzONkVXsGLVggkTxgle8thNaZrGqXYt69b2JEcZhKdxFQpF
+fv4klUqJQigMwxISErq7LUuXLn3ttV/r9Ya1ax9AqlNRUXHhQv3Ro0eefvrpysrKCRMmIJVCUdHR
+o0fvvPPO/fv3z549a+rU6Z2dHUiu3n33XaVSOXPmzAceeOCjjz4qKirasmVLbGxs77Szw4rvvQoY
+hkNK5PwrIiVG1u0Aw51wjIeQfcRkbCQ9iVRj9i0MdrIfQmg7pM2gPAwt+2gREbfFzzAi1e1E/BZU
+H5dnOh+fHf+Dl+77ntveYTLZLXoMs+DAd4DTKcybRyGJikYSpVGpxkUrruTUGmJef2GN3G0ieNaD
+I4mieYyQsRYradB5jCjI6SEJOcc6iRiVx9hDy5Plqgl3x9+6bCbKayNjUEqU3oPJlazJSsYomG6O
+UquRNArPSxlkV7+ySqGmPvrj3RZcr2NcBGNVaAxoZVRU1IIFJVarrXcs+NSpU0EYho6//PLLfaMr
+CgoKMjIyULyF9KykpIQgiLi4OLQVqRTaevfdd6M1SN6yszMnTy4sLS1duXJlb8Y1a9agTWazWavV
+4qKDDwcFibzLGUTy4Gc6F9nk1/KAH3mA2QdLH5TbgZc4mLfhONz/1rdIdr8+h5AxtJYMhOFugTA9
+GfJgGOwIFJGfQAoKPGOYDF8DihcR8pEZrBuBdDsidkLzQZyr3rdE0Mr4BKXwfKxwiQ9SRXNi4IlX
+8qCMunq1QSt8C+8n7Kcycd6VQBMKmhY0TgNXvgRivEu9s7gONpcrFq2Jib7s8DeGVSo1+lx2nrg8
+OwWGQf/5ilQqVf8E/V8x1X8Zadjtt9/e92dvYr1eP4g/Q8NjkHTr8uCyDK4xQWUZ7PKL76YhsweY
+3u/RGaBvImlEKiKecbA1ISQIJ2MILRnUcggFie9BEbMBbg32GPa7ryN+IA25NfwGDMG4+Dll4In9
+rg+coCwH3hdFSqvCeCUgJus3h9+3gci+IBHHsI9/tiyCBscyImfBEmOf4btKIxEa0g+qj3Ak6luk
+TsMDdT21kNTHXbuM5L6TjpMAuVYaarj9/Ja8WF1CQkJC4tuHJFESEhISEmMUSaIkJCQkJMYokkRJ
+SEhISIxR/heHXcIrMvkS1gAAAABJRU5ErkJggg==
+
+------_=_NextPart_001_01CCB66F.F38B15FC-- \ No newline at end of file
diff --git a/spec/fixtures/files/useless_raw_email.email b/spec/fixtures/files/raw_emails/1.email
index 2e4585af7..2e4585af7 100644
--- a/spec/fixtures/files/useless_raw_email.email
+++ b/spec/fixtures/files/raw_emails/1.email
diff --git a/spec/fixtures/files/raw_emails/2.email b/spec/fixtures/files/raw_emails/2.email
new file mode 100644
index 000000000..eab0b0f8d
--- /dev/null
+++ b/spec/fixtures/files/raw_emails/2.email
@@ -0,0 +1,20 @@
+From: "FOI Person" <foiperson@localhost>
+To: "Bob Smith" <bob@localhost>
+Date: Tue, 13 Nov 2007 11:39:55 +0000
+Bcc:
+Subject: Re: Your email
+Reply-To:
+In-Reply-To: <471f1eae5d1cb_7347..fdbe67386164@cat.tmail>
+Content-Type: text/plain; charset=utf-8
+
+Dear “Bob”,
+
+In the financial year 2010–2011, this Department spent a
+total of nine hundred of your earth pounds on the purchase
+and repair of boring equipment.
+
+Yours most sincerely,
+
+Quentin Nobble-Boston,
+Permanent Under-Secretary,
+Department for Humpadinking
diff --git a/spec/fixtures/files/raw_emails/3.email b/spec/fixtures/files/raw_emails/3.email
new file mode 100644
index 000000000..a6e780fe5
--- /dev/null
+++ b/spec/fixtures/files/raw_emails/3.email
@@ -0,0 +1,19 @@
+From: "The Minister" <msw@localhost>
+To: "Bob Smith" <bob@localhost>
+Date: Tue, 13 Nov 2009 11:39:55 +0000
+Bcc:
+Subject: Re: Your message
+Reply-To:
+In-Reply-To: <471f1eae5d1cb_7347..fdbe67386165@cat.tmail>
+Content-Type: text/plain; charset=utf-8
+
+Dear “Bob”,
+
+In the financial year 2010–2011, this Ministry spent precisely
+no money at all on the purchase or repair of boring equipment.
+
+Yours most sincerely,
+
+Martin Kibble-von Scratsching,
+Chief Assistant to the Assistant Chief,
+Ministry of Silly Walks
diff --git a/spec/fixtures/files/raw_emails/4.email b/spec/fixtures/files/raw_emails/4.email
new file mode 100644
index 000000000..c778e5ba9
--- /dev/null
+++ b/spec/fixtures/files/raw_emails/4.email
@@ -0,0 +1,17 @@
+From: "The Minister" <msw@localhost>
+To: robin@localhost
+Date: Tue, 13 Nov 2008 11:39:55 +0000
+Bcc:
+Subject: Re: v1agra
+Reply-To:
+In-Reply-To: <fdshjksdahhjkfsdahjkfsd@gfh.example.com>
+Content-Type: text/plain; charset=utf-8
+
+Thank you for your spam, which we have processed with pleasure. Please
+accept herewith our order for six packs of the finest cheap v1agra.
+
+Yours most sincerely,
+
+Martin Kibble-von Scratsching,
+Chief Assistant to the Assistant Chief,
+Ministry of Silly Walks
diff --git a/spec/fixtures/files/raw_emails/5.email b/spec/fixtures/files/raw_emails/5.email
new file mode 100644
index 000000000..16b65610a
--- /dev/null
+++ b/spec/fixtures/files/raw_emails/5.email
@@ -0,0 +1,17 @@
+From: "The Minister" <sensewalk@localhost>
+To: robin@localhost
+Date: Tue, 13 Nov 2008 12:39:55 +0000
+Bcc:
+Subject: Re: v1agra
+Reply-To:
+In-Reply-To: <fdshjks+hihhjkfsdahjkfsd@gfh.example.com>
+Content-Type: text/plain; charset=utf-8
+
+Thank you for your spam, which we have processed with pleasure. Please
+accept herewith our order for six packs of the finest cheap v1agra.
+
+Yours most sincerely,
+
+Martin Scratsching-von Kibble,
+Assistant (Second class) to the Chief Assistant to the Assistant Chief,
+Ministry of Sensible Walks
diff --git a/spec/fixtures/files/track-response-abcmail-oof.email b/spec/fixtures/files/track-response-abcmail-oof.email
new file mode 100644
index 000000000..5d1733143
--- /dev/null
+++ b/spec/fixtures/files/track-response-abcmail-oof.email
@@ -0,0 +1,80 @@
+Delivered-To: mysociety.robin@gmail.com
+Received: by 10.216.154.212 with SMTP id h62cs265517wek;
+ Fri, 30 Dec 2011 02:03:17 -0800 (PST)
+Received: by 10.227.208.129 with SMTP id gc1mr47630338wbb.4.1325239396543;
+ Fri, 30 Dec 2011 02:03:16 -0800 (PST)
+Return-Path: <Name.Removed@example.gov.uk>
+Received: from wildfire.ukcod.org.uk (wildfire.ukcod.org.uk. [89.238.145.74])
+ by mx.google.com with ESMTPS id ei10si9596065wbb.20.2011.12.30.02.03.16
+ (version=TLSv1/SSLv3 cipher=OTHER);
+ Fri, 30 Dec 2011 02:03:16 -0800 (PST)
+Received-SPF: neutral (google.com: 89.238.145.74 is neither permitted nor denied by best guess record for domain of Name.Removed@example.gov.uk) client-ip=89.238.145.74;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 89.238.145.74 is neither permitted nor denied by best guess record for domain of Name.Removed@example.gov.uk) smtp.mail=Name.Removed@example.gov.uk
+Received: from foi by wildfire.ukcod.org.uk with local (Exim 4.72)
+ (envelope-from <Name.Removed@example.gov.uk>)
+ id 1RgZIs-0000ME-1T
+ for team_delivery@whatdotheyknow.com; Fri, 30 Dec 2011 10:03:10 +0000
+Received: from truro.icritical.com ([93.95.13.13]:51540)
+ by wildfire.ukcod.org.uk with smtp (Exim 4.72)
+ (envelope-from <Name.Removed@example.gov.uk>)
+ id 1RgZIq-0000M6-St
+ for track@whatdotheyknow.com; Fri, 30 Dec 2011 10:03:09 +0000
+Received: (qmail 19136 invoked from network); 30 Dec 2011 10:03:08 -0000
+Received: from localhost (127.0.0.1)
+ by truro.icritical.com with SMTP; 30 Dec 2011 10:03:08 -0000
+Received: from truro.icritical.com ([127.0.0.1])
+ by localhost (truro.icritical.com [127.0.0.1]) (amavisd-new, port 10024)
+ with SMTP id 19122-01 for <track@whatdotheyknow.com>;
+ Fri, 30 Dec 2011 10:03:07 +0000 (GMT)
+Received: (qmail 19112 invoked by uid 599); 30 Dec 2011 10:03:06 -0000
+Received: from unknown (HELO abcmail.example.gov.uk) (213.185.212.82)
+ by truro.icritical.com (qpsmtpd/0.28) with ESMTP; Fri, 30 Dec 2011 10:03:06 +0000
+Subject: AUTO: Name Removed is out of the office (returning 03/01/2012)
+Auto-Submitted: auto-generated
+From: Name.Removed@example.gov.uk
+To: track@whatdotheyknow.com
+Message-ID: <OFF4E36F18.ED02EFA3-ON80257976.00373794-80257976.00373794@example.gov.uk>
+Date: Fri, 30 Dec 2011 10:03:07 +0000
+X-MIMETrack: Serialize by Router on ABCMail/SVR/ABC(Release 8.5.2FP1|November 29, 2010) at
+ 30/12/2011 10:03:07
+MIME-Version: 1.0
+Content-type: text/plain; charset=US-ASCII
+X-Virus-Scanned: by iCritical at truro.icritical.com
+
+
+I am out of the office until 03/01/2012.
+
+I will be out of the office until 3rd January December 2012. I will deal
+with all emails upon my return. If your query is urgent please contact
+Colleague Name on colleague.name@example.gov.uk or 01234 567890.
+
+If you are requesting information under the Freedom of Information Act, the
+Environmental Information Regulations or the Data Protection Act, please
+forward your enquiry to colleague.name@example.gov.uk The Council
+will begin processing your request once it is received by that address.
+
+
+Thanks
+
+Name
+
+
+
+
+
+Note: This is an automated response to your message "Your WhatDoTheyKnow
+email alert" sent on 30/12/2011 06:54:19.
+
+This is the only notification you will receive while this person is away.
+
+
+This e-mail and any files transmitted with it are confidential and
+intended solely for the use of the individual or entity to whom
+they are addressed.
+If you have received this e-mail in error please notify the
+originator of the message. This footer also confirms that this
+e-mail message has been scanned for the presence of computer viruses.
+
+Any views expressed in this message are those of the individual
+sender, except where the sender specifies and with authority,
+states them to be the views of Organisation Name.
diff --git a/spec/fixtures/files/track-response-outlook-oof.email b/spec/fixtures/files/track-response-outlook-oof.email
new file mode 100644
index 000000000..ee5a28b15
--- /dev/null
+++ b/spec/fixtures/files/track-response-outlook-oof.email
@@ -0,0 +1,587 @@
+Delivered-To: mysociety.robin@gmail.com
+Received: by 10.152.24.138 with SMTP id u10cs341636laf;
+ Thu, 8 Dec 2011 02:39:53 -0800 (PST)
+Received: by 10.180.103.131 with SMTP id fw3mr4246912wib.57.1323340792168;
+ Thu, 08 Dec 2011 02:39:52 -0800 (PST)
+Return-Path: <peter@kentadvice.co.uk>
+Received: from wildfire.ukcod.org.uk (wildfire.ukcod.org.uk. [89.238.145.74])
+ by mx.google.com with ESMTPS id ft12si3357577wbb.14.2011.12.08.02.39.51
+ (version=TLSv1/SSLv3 cipher=OTHER);
+ Thu, 08 Dec 2011 02:39:52 -0800 (PST)
+Received-SPF: neutral (google.com: 89.238.145.74 is neither permitted nor denied by best guess record for domain of peter@kentadvice.co.uk) client-ip=89.238.145.74;
+Authentication-Results: mx.google.com; spf=neutral (google.com: 89.238.145.74 is neither permitted nor denied by best guess record for domain of peter@kentadvice.co.uk) smtp.mail=peter@kentadvice.co.uk
+Received: from foi by wildfire.ukcod.org.uk with local (Exim 4.72)
+ (envelope-from <peter@kentadvice.co.uk>)
+ id 1RYbOC-00034X-Vm
+ for team_delivery@whatdotheyknow.com; Thu, 08 Dec 2011 10:39:45 +0000
+Received: from mail-ey0-f173.google.com ([209.85.215.173]:38997)
+ by wildfire.ukcod.org.uk with esmtp (Exim 4.72)
+ (envelope-from <peter@kentadvice.co.uk>)
+ id 1RYbOC-00034L-GF
+ for track@whatdotheyknow.com; Thu, 08 Dec 2011 10:39:44 +0000
+Received: by eaai10 with SMTP id i10so1168752eaa.32
+ for <track@whatdotheyknow.com>; Thu, 08 Dec 2011 02:39:33 -0800 (PST)
+Received: by 10.213.21.148 with SMTP id j20mr131258ebb.87.1323340773446;
+ Thu, 08 Dec 2011 02:39:33 -0800 (PST)
+Received: from PRWin7 (cpc2-tilb7-2-0-cust982.basl.cable.virginmedia.com. [94.168.103.215])
+ by mx.google.com with ESMTPS id 49sm16411187eec.1.2011.12.08.02.39.31
+ (version=TLSv1/SSLv3 cipher=OTHER);
+ Thu, 08 Dec 2011 02:39:32 -0800 (PST)
+From: "Name Removed" <name-removed@example.co.uk>
+To: <track@whatdotheyknow.com>
+Subject: Out of Office reply
+Date: Thu, 8 Dec 2011 10:39:24 -0000
+Message-ID: <00ab01ccb595$aada0070$008e0150$@co.uk>
+MIME-Version: 1.0
+Content-Type: multipart/alternative;
+ boundary="----=_NextPart_000_00AC_01CCB595.AADA0070"
+X-Mailer: Microsoft Office Outlook 12.0
+Thread-Index: Acy1laTpNPAp9QuHRu2X59T70yzpQw==
+Content-Language: en-gb
+
+This is a multi-part message in MIME format.
+
+------=_NextPart_000_00AC_01CCB595.AADA0070
+Content-Type: text/plain;
+ charset="US-ASCII"
+Content-Transfer-Encoding: 7bit
+
+Thank you for your message. I am currently out of the office, with [limited]
+[no] access to e-mail.
+
+I will be returning on [day, date].
+
+If you need assistance before then, you may reach me at [phone number].
+For urgent issues, please contact [name] at [e-mail address] or [telephone
+number].
+
+[Signature]
+
+[Optional: Type your favorite quotation or saying here along with the author
+or source]
+
+------=_NextPart_000_00AC_01CCB595.AADA0070
+Content-Type: text/html;
+ charset="US-ASCII"
+Content-Transfer-Encoding: quoted-printable
+
+<html xmlns:v=3D"urn:schemas-microsoft-com:vml" =
+xmlns:o=3D"urn:schemas-microsoft-com:office:office" =
+xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
+xmlns:x=3D"urn:schemas-microsoft-com:office:excel" =
+xmlns:p=3D"urn:schemas-microsoft-com:office:powerpoint" =
+xmlns:a=3D"urn:schemas-microsoft-com:office:access" =
+xmlns:dt=3D"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" =
+xmlns:s=3D"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" =
+xmlns:rs=3D"urn:schemas-microsoft-com:rowset" xmlns:z=3D"#RowsetSchema" =
+xmlns:b=3D"urn:schemas-microsoft-com:office:publisher" =
+xmlns:ss=3D"urn:schemas-microsoft-com:office:spreadsheet" =
+xmlns:c=3D"urn:schemas-microsoft-com:office:component:spreadsheet" =
+xmlns:oa=3D"urn:schemas-microsoft-com:office:activation" =
+xmlns:html=3D"http://www.w3.org/TR/REC-html40" =
+xmlns:q=3D"http://schemas.xmlsoap.org/soap/envelope/" xmlns:D=3D"DAV:" =
+xmlns:x2=3D"http://schemas.microsoft.com/office/excel/2003/xml" =
+xmlns:ois=3D"http://schemas.microsoft.com/sharepoint/soap/ois/" =
+xmlns:dir=3D"http://schemas.microsoft.com/sharepoint/soap/directory/" =
+xmlns:ds=3D"http://www.w3.org/2000/09/xmldsig#" =
+xmlns:dsp=3D"http://schemas.microsoft.com/sharepoint/dsp" =
+xmlns:udc=3D"http://schemas.microsoft.com/data/udc" =
+xmlns:xsd=3D"http://www.w3.org/2001/XMLSchema" =
+xmlns:sub=3D"http://schemas.microsoft.com/sharepoint/soap/2002/1/alerts/"=
+ xmlns:ec=3D"http://www.w3.org/2001/04/xmlenc#" =
+xmlns:sp=3D"http://schemas.microsoft.com/sharepoint/" =
+xmlns:sps=3D"http://schemas.microsoft.com/sharepoint/soap/" =
+xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance" =
+xmlns:udcxf=3D"http://schemas.microsoft.com/data/udc/xmlfile" =
+xmlns:wf=3D"http://schemas.microsoft.com/sharepoint/soap/workflow/" =
+xmlns:mver=3D"http://schemas.openxmlformats.org/markup-compatibility/2006=
+" xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" =
+xmlns:mrels=3D"http://schemas.openxmlformats.org/package/2006/relationshi=
+ps" =
+xmlns:ex12t=3D"http://schemas.microsoft.com/exchange/services/2006/types"=
+ =
+xmlns:ex12m=3D"http://schemas.microsoft.com/exchange/services/2006/messag=
+es" xmlns=3D"http://www.w3.org/TR/REC-html40">
+
+<head>
+<META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
+charset=3Dus-ascii">
+
+
+<meta name=3DProgId content=3DWord.Document>
+<meta name=3DGenerator content=3D"Microsoft Word 12">
+<meta name=3DOriginator content=3D"Microsoft Word 12">
+<link rel=3DFile-List href=3D"cid:filelist.xml@01C895B2.35BC4F70">
+<!--[if gte mso 9]><xml>
+ <o:OfficeDocumentSettings>
+ <o:AllowPNG/>
+ <o:TargetScreenSize>1024x768</o:TargetScreenSize>
+ </o:OfficeDocumentSettings>
+</xml><![endif]-->
+<link rel=3DthemeData href=3D"~~themedata~~">
+<link rel=3DcolorSchemeMapping href=3D"~~colorschememapping~~">
+<!--[if gte mso 9]><xml>
+ <w:WordDocument>
+ <w:SpellingState>Clean</w:SpellingState>
+ <w:TrackMoves/>
+ <w:TrackFormatting/>
+ <w:EnvelopeVis/>
+ <w:ValidateAgainstSchemas/>
+ <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
+ <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
+ <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
+ <w:DoNotPromoteQF/>
+ <w:LidThemeOther>EN-US</w:LidThemeOther>
+ <w:LidThemeAsian>X-NONE</w:LidThemeAsian>
+ <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
+ <w:Compatibility>
+ <w:DoNotExpandShiftReturn/>
+ <w:BreakWrappedTables/>
+ <w:SnapToGridInCell/>
+ <w:WrapTextWithPunct/>
+ <w:UseAsianBreakRules/>
+ <w:DontGrowAutofit/>
+ <w:SplitPgBreakAndParaMark/>
+ <w:DontVertAlignCellWithSp/>
+ <w:DontBreakConstrainedForcedTables/>
+ <w:DontVertAlignInTxbx/>
+ <w:Word11KerningPairs/>
+ <w:CachedColBalance/>
+ </w:Compatibility>
+ <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
+ <m:mathPr>
+ <m:mathFont m:val=3D"Cambria Math"/>
+ <m:brkBin m:val=3D"before"/>
+ <m:brkBinSub m:val=3D"&#45;-"/>
+ <m:smallFrac m:val=3D"off"/>
+ <m:dispDef/>
+ <m:lMargin m:val=3D"0"/>
+ <m:rMargin m:val=3D"0"/>
+ <m:defJc m:val=3D"centerGroup"/>
+ <m:wrapIndent m:val=3D"1440"/>
+ <m:intLim m:val=3D"subSup"/>
+ <m:naryLim m:val=3D"undOvr"/>
+ </m:mathPr></w:WordDocument>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:LatentStyles DefLockedState=3D"false" DefUnhideWhenUsed=3D"true"=20
+ DefSemiHidden=3D"true" DefQFormat=3D"false" DefPriority=3D"99"=20
+ LatentStyleCount=3D"267">
+ <w:LsdException Locked=3D"false" Priority=3D"0" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Normal"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"heading 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 7"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 8"/>
+ <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" =
+Name=3D"heading 9"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 7"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 8"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 9"/>
+ <w:LsdException Locked=3D"false" Priority=3D"35" QFormat=3D"true" =
+Name=3D"caption"/>
+ <w:LsdException Locked=3D"false" Priority=3D"10" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Title"/>
+ <w:LsdException Locked=3D"false" Priority=3D"1" Name=3D"Default =
+Paragraph Font"/>
+ <w:LsdException Locked=3D"false" Priority=3D"11" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Subtitle"/>
+ <w:LsdException Locked=3D"false" Priority=3D"22" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Strong"/>
+ <w:LsdException Locked=3D"false" Priority=3D"20" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Emphasis"/>
+ <w:LsdException Locked=3D"false" Priority=3D"59" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Table Grid"/>
+ <w:LsdException Locked=3D"false" UnhideWhenUsed=3D"false" =
+Name=3D"Placeholder Text"/>
+ <w:LsdException Locked=3D"false" Priority=3D"1" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"No Spacing"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 1"/>
+ <w:LsdException Locked=3D"false" UnhideWhenUsed=3D"false" =
+Name=3D"Revision"/>
+ <w:LsdException Locked=3D"false" Priority=3D"34" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"List Paragraph"/>
+ <w:LsdException Locked=3D"false" Priority=3D"29" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Quote"/>
+ <w:LsdException Locked=3D"false" Priority=3D"30" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Intense Quote"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 1"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 2"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 3"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 4"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 5"/>
+ <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light List Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 6"/>
+ <w:LsdException Locked=3D"false" Priority=3D"19" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Subtle Emphasis"/>
+ <w:LsdException Locked=3D"false" Priority=3D"21" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Intense Emphasis"/>
+ <w:LsdException Locked=3D"false" Priority=3D"31" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Subtle Reference"/>
+ <w:LsdException Locked=3D"false" Priority=3D"32" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Intense =
+Reference"/>
+ <w:LsdException Locked=3D"false" Priority=3D"33" SemiHidden=3D"false"=20
+ UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Book Title"/>
+ <w:LsdException Locked=3D"false" Priority=3D"37" =
+Name=3D"Bibliography"/>
+ <w:LsdException Locked=3D"false" Priority=3D"39" QFormat=3D"true" =
+Name=3D"TOC Heading"/>
+ </w:LatentStyles>
+</xml><![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+ @font-face
+ {font-family:"Cambria Math";
+ panose-1:2 4 5 3 5 4 6 3 2 4;
+ mso-font-charset:1;
+ mso-generic-font-family:roman;
+ mso-font-format:other;
+ mso-font-pitch:variable;
+ mso-font-signature:0 0 0 0 0 0;}
+@font-face
+ {font-family:Calibri;
+ panose-1:2 15 5 2 2 2 4 3 2 4;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-pitch:variable;
+ mso-font-signature:-1610611985 1073750139 0 0 159 0;}
+ /* Style Definitions */
+ p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {mso-style-unhide:no;
+ mso-style-qformat:yes;
+ mso-style-parent:"";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:11.0pt;
+ font-family:"Calibri","sans-serif";
+ mso-fareast-font-family:Calibri;
+ mso-fareast-theme-font:minor-latin;
+ mso-bidi-font-family:"Times New Roman";}
+a:link, span.MsoHyperlink
+ {mso-style-noshow:yes;
+ mso-style-priority:99;
+ color:blue;
+ text-decoration:underline;
+ text-underline:single;}
+a:visited, span.MsoHyperlinkFollowed
+ {mso-style-noshow:yes;
+ mso-style-priority:99;
+ color:purple;
+ text-decoration:underline;
+ text-underline:single;}
+span.EmailStyle17
+ {mso-style-type:personal;
+ mso-style-noshow:yes;
+ mso-style-unhide:no;
+ font-family:"Calibri","sans-serif";
+ mso-ascii-font-family:Calibri;
+ mso-hansi-font-family:Calibri;
+ color:windowtext;}
+span.EmailStyle18
+ {mso-style-type:personal-reply;
+ mso-style-noshow:yes;
+ mso-style-unhide:no;
+ mso-ansi-font-size:11.0pt;
+ mso-bidi-font-size:11.0pt;
+ font-family:"Calibri","sans-serif";
+ mso-ascii-font-family:Calibri;
+ mso-ascii-theme-font:minor-latin;
+ mso-hansi-font-family:Calibri;
+ mso-hansi-theme-font:minor-latin;
+ mso-bidi-font-family:"Times New Roman";
+ mso-bidi-theme-font:minor-bidi;
+ color:#5F497A;
+ mso-themecolor:accent4;
+ mso-themeshade:191;}
+.MsoChpDefault
+ {mso-style-type:export-only;
+ mso-default-props:yes;
+ font-size:10.0pt;
+ mso-ansi-font-size:10.0pt;
+ mso-bidi-font-size:10.0pt;}
+@page Section1
+ {size:8.5in 11.0in;
+ margin:1.0in 1.0in 1.0in 1.0in;
+ mso-header-margin:.5in;
+ mso-footer-margin:.5in;
+ mso-paper-source:0;}
+div.Section1
+ {page:Section1;}
+-->
+</style>
+<!--[if gte mso 10]>
+<style>
+ /* Style Definitions */=20
+ table.MsoNormalTable
+ {mso-style-name:"Table Normal";
+ mso-tstyle-rowband-size:0;
+ mso-tstyle-colband-size:0;
+ mso-style-noshow:yes;
+ mso-style-priority:99;
+ mso-style-qformat:yes;
+ mso-style-parent:"";
+ mso-padding-alt:0in 5.4pt 0in 5.4pt;
+ mso-para-margin:0in;
+ mso-para-margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:10.0pt;
+ font-family:"Times New Roman","serif";}
+</style>
+<![endif]--><!--[if gte mso 9]><xml>
+ <o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" />
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <o:shapelayout v:ext=3D"edit">
+ <o:idmap v:ext=3D"edit" data=3D"1" />
+ </o:shapelayout></xml><![endif]-->
+</head>
+
+<body lang=3DEN-US link=3Dblue vlink=3Dpurple =
+style=3D'tab-interval:.5in'>
+
+<div class=3DSection1>
+
+<p class=3DMsoNormal>Thank you for your message. I am currently out of =
+the
+office, with [limited] [no] access to e-mail.<o:p></o:p></p>
+
+<p class=3DMsoNormal><o:p>&nbsp;</o:p></p>
+
+<p class=3DMsoNormal>I will be returning on [day, date].<o:p></o:p></p>
+
+<p class=3DMsoNormal><o:p>&nbsp;</o:p></p>
+
+<p class=3DMsoNormal>If you need assistance before then, you may reach =
+me at
+[phone number].<o:p></o:p></p>
+
+<p class=3DMsoNormal>For urgent issues, please contact [name] at [e-mail =
+address]
+or [telephone number].<o:p></o:p></p>
+
+<p class=3DMsoNormal><o:p>&nbsp;</o:p></p>
+
+<p class=3DMsoNormal>[Signature]<o:p></o:p></p>
+
+<p class=3DMsoNormal><o:p>&nbsp;</o:p></p>
+
+<p class=3DMsoNormal><i style=3D'mso-bidi-font-style:normal'>[Optional: =
+Type your
+favorite quotation or saying here along with the author or =
+source]<o:p></o:p></i></p>
+
+</div>
+
+</body>
+
+</html>
+
+------=_NextPart_000_00AC_01CCB595.AADA0070--
+
diff --git a/spec/fixtures/has_tag_string_tags.yml b/spec/fixtures/has_tag_string_tags.yml
new file mode 100644
index 000000000..fe3d4fd28
--- /dev/null
+++ b/spec/fixtures/has_tag_string_tags.yml
@@ -0,0 +1,36 @@
+lonely_tag:
+ name: lonely_agency
+ id: "1"
+ created_at: 2007-10-24 10:51:01.161639
+ model: PublicBody
+ model_id: 4
+useless_tag_1:
+ name: useless_agency
+ id: "2"
+ created_at: 2007-10-24 10:51:01.161639
+ model: PublicBody
+ model_id: 3
+useless_tag_2:
+ name: useless_agency
+ id: "3"
+ created_at: 2007-10-24 10:51:01.161639
+ model: PublicBody
+ model_id: 4
+useless_tag_3:
+ name: useless_agency
+ id: "4"
+ created_at: 2007-10-24 10:51:01.161639
+ model: PublicBody
+ model_id: 5
+popular_tag_1:
+ name: popular_agency
+ id: "5"
+ created_at: 2007-10-24 10:51:01.161639
+ model: PublicBody
+ model_id: 2
+popular_tag_2:
+ name: popular_agency
+ id: "6"
+ created_at: 2007-10-24 10:51:01.161639
+ model: PublicBody
+ model_id: 3
diff --git a/spec/fixtures/incoming_messages.yml b/spec/fixtures/incoming_messages.yml
index e15a466ca..fca5c716c 100644
--- a/spec/fixtures/incoming_messages.yml
+++ b/spec/fixtures/incoming_messages.yml
@@ -1,7 +1,33 @@
useless_incoming_message:
- id: 1
- info_request_id: 101
- updated_at: 2007-11-13 18:09:20.042061
- raw_email_id: 1
- created_at: 2007-11-13 18:09:20.042061
+ id: 1
+ info_request_id: 101
+ updated_at: 2007-11-13 18:09:20.042061
+ raw_email_id: 1
+ created_at: 2007-11-13 18:09:20.042061
+useful_incoming_message:
+ id: 2
+ info_request_id: 105
+ raw_email_id: 2
+ created_at: 2012-01-26 10:19:23
+ updated_at: 2012-01-26 10:19:23
+
+another_useful_incoming_message:
+ id: 3
+ info_request_id: 106
+ raw_email_id: 3
+ created_at: 2007-11-13 18:09:20
+ updated_at: 2007-11-13 18:09:20
+
+spam_1_incoming_message:
+ id: 4
+ info_request_id: 107
+ raw_email_id: 4
+ created_at: 2008-11-13 18:09:20
+ updated_at: 2008-11-13 18:09:20
+spam_2_incoming_message:
+ id: 5
+ info_request_id: 108
+ raw_email_id: 5
+ created_at: 2008-11-13 19:09:20
+ updated_at: 2008-11-13 19:09:20
diff --git a/spec/fixtures/info_request_events.yml b/spec/fixtures/info_request_events.yml
index 5e3c13083..3266ec634 100644
--- a/spec/fixtures/info_request_events.yml
+++ b/spec/fixtures/info_request_events.yml
@@ -1,41 +1,152 @@
useless_outgoing_message_event:
+ id: 900
params_yaml: "--- \n\
:outgoing_message_id: 1\n"
- id: 900
info_request_id: 101
event_type: sent
created_at: 2007-10-12 01:56:58.586598
described_state:
outgoing_message_id: 1
silly_outgoing_message_event:
+ id: 901
params_yaml: "--- \n\
:outgoing_message_id: 2\n"
- id: 901
info_request_id: 103
event_type: sent
created_at: 2007-10-14 10:41:12.686264
described_state:
outgoing_message_id: 2
useless_incoming_message_event:
+ id: 902
params_yaml: "--- \n\
:incoming_message_id: 1\n"
- id: 902
info_request_id: 101
event_type: response
created_at: 2007-11-13 18:09:20.042061
described_state:
incoming_message_id: 1
silly_comment_event:
+ id: 903
params_yaml: "--- \n\
:comment_id: 1\n"
incoming_message_id:
last_described_at:
described_state:
- id: "903"
- info_request_id: "101"
- comment_id: "1"
+ info_request_id: 101
+ comment_id: 1
calculated_state:
event_type: comment
outgoing_message_id:
created_at: 2008-08-12 23:05:12.500942
+badger_outgoing_message_event:
+ id: 904
+ params_yaml: "--- \n\
+ :outgoing_message_id: 3\n"
+ info_request_id: 104
+ event_type: sent
+ created_at: 2011-10-12 01:56:58.586598
+ described_state: waiting_response
+ calculated_state: waiting_response
+ outgoing_message_id: 3
+
+# These in chronological order
+boring_outgoing_message_event:
+ id: 905
+ params_yaml: "--- \n\
+ :outgoing_message_id: 4\n"
+ outgoing_message_id: 4
+ info_request_id: 105
+ event_type: sent
+ created_at: 2006-01-12 01:56:58.586598
+ described_state: waiting_response
+ calculated_state: waiting_response
+useful_incoming_message_event:
+ id: 906
+ params_yaml: "--- \n\
+ :incoming_message_id: 2\n"
+ incoming_message_id: 2
+ info_request_id: 105
+ event_type: response
+ created_at: 2007-11-13 18:00:20
+ described_state: successful
+ calculated_state: successful
+
+another_boring_outgoing_message_event:
+ id: 907
+ params_yaml: "--- \n\
+ :outgoing_message_id: 5\n"
+ outgoing_message_id: 5
+ info_request_id: 106
+ event_type: sent
+ created_at: 2006-01-12 01:56:58.586598
+ described_state: waiting_response
+ calculated_state: waiting_response
+another_useful_incoming_message_event:
+ id: 908
+ params_yaml: "--- \n\
+ :incoming_message_id: 3\n"
+ incoming_message_id: 3
+ info_request_id: 106
+ event_type: response
+ created_at: 2007-11-13 18:09:20.042061
+ described_state: successful
+ calculated_state: successful
+
+another_comment_event:
+ id: 909
+ info_request_id: 105
+ comment_id: 2
+ params_yaml: "--- \n\
+ :comment_id: 2\n"
+ incoming_message_id:
+ outgoing_message_id:
+ last_described_at:
+ described_state:
+ calculated_state:
+ event_type: comment
+ created_at: 2008-08-12 12:05:12.879634
+
+
+# The spam requests were both successful
+spam_1_outgoing_message_event:
+ id: 910
+ params_yaml: "--- \n\
+ :outgoing_message_id: 6\n"
+ outgoing_message_id: 6
+ info_request_id: 107
+ event_type: sent
+ created_at: 2001-01-02 01:23:45.6789100
+ described_state: waiting_response
+ calculated_state: waiting_response
+spam_1_incoming_message_event:
+ id: 911
+ params_yaml: "--- \n\
+ :incoming_message_id: 4\n"
+ incoming_message_id: 4
+ info_request_id: 107
+ event_type: response
+ created_at: 2001-01-03 01:23:45.6789100
+ described_state: successful
+ calculated_state: successful
+
+spam_2_outgoing_message_event:
+ id: 912
+ params_yaml: "--- \n\
+ :outgoing_message_id: 7\n"
+ outgoing_message_id: 7
+ info_request_id: 108
+ event_type: sent
+ created_at: 2001-01-02 02:23:45.6789100
+ described_state: waiting_response
+ calculated_state: waiting_response
+spam_2_incoming_message_event:
+ id: 913
+ params_yaml: "--- \n\
+ :incoming_message_id: 5\n"
+ incoming_message_id: 5
+ info_request_id: 108
+ event_type: response
+ created_at: 2001-01-03 02:23:45.6789100
+ described_state: successful
+ calculated_state: successful
diff --git a/spec/fixtures/info_requests.yml b/spec/fixtures/info_requests.yml
index c1e3c1910..33e9a16f2 100644
--- a/spec/fixtures/info_requests.yml
+++ b/spec/fixtures/info_requests.yml
@@ -18,5 +18,63 @@ naughty_chicken_request:
public_body_id: 2
user_id: 1
described_state: waiting_response
- awaiting_description: false
+ awaiting_description: false
idhash: e8d18c84
+badger_request:
+ id: 104
+ title: Are you really a badger?
+ url_title: are_you_really_a_badger
+ created_at: 2011-10-13 18:15:57
+ updated_at: 2011-10-13 18:15:57
+ public_body_id: 3
+ user_id: 1
+ described_state: waiting_response
+ awaiting_description: false
+ idhash: e8d18c84
+boring_request:
+ id: 105
+ title: The cost of boring
+ url_title: the_cost_of_boring
+ created_at: 2006-01-12 01:56:58.586598
+ updated_at: 2008-08-12 12:05:12.879634
+ public_body_id: 3
+ user_id: 1
+ described_state: successful
+ awaiting_description: false
+ idhash: 173fd003
+another_boring_request:
+ id: 106
+ title: The cost of boring
+ url_title: the_cost_of_boring_two # Not _2, because we want to avoid the search collapsing these two
+ created_at: 2006-01-12 01:56:58.586598
+ updated_at: 2007-11-13 18:09:20.042061
+ public_body_id: 5
+ user_id: 1
+ described_state: successful
+ awaiting_description: false
+ idhash: 173fd004
+
+# A pair of identical requests (with url_title differing only in the numeric suffix)
+# used to test the request de-duplication features.
+spam_1_request:
+ id: 107
+ title: Cheap v1agra
+ url_title: spam_1
+ created_at: 2010-01-01 01:23:45.6789100
+ created_at: 2010-01-01 01:23:45.6789100
+ public_body_id: 5
+ user_id: 5
+ described_state: successful
+ awaiting_description: false
+ idhash: 173fd005
+spam_2_request:
+ id: 108
+ title: Cheap v1agra
+ url_title: spam_2
+ created_at: 2010-01-01 02:23:45.6789100
+ created_at: 2010-01-01 02:23:45.6789100
+ public_body_id: 6
+ user_id: 5
+ described_state: successful
+ awaiting_description: false
+ idhash: 173fd005
diff --git a/spec/fixtures/outgoing_messages.yml b/spec/fixtures/outgoing_messages.yml
index b89492aa5..d33ca4292 100644
--- a/spec/fixtures/outgoing_messages.yml
+++ b/spec/fixtures/outgoing_messages.yml
@@ -33,4 +33,56 @@ silly_outgoing_message:
last_sent_at: 2007-10-14 10:41:12.686264
created_at: 2007-10-14 01:56:58.586598
what_doing: normal_sort
+badger_outgoing_message:
+ id: 3
+ info_request_id: 104
+ message_type: initial_request
+ status: sent
+ updated_at: 2011-10-14 01:56:58.586598
+ body: "Is it true that you are really a badger, in fact?"
+ last_sent_at: 2011-10-14 10:41:12.686264
+ created_at: 2011-10-14 01:56:58.586598
+ what_doing: normal_sort
+boring_outgoing_message:
+ id: 4
+ info_request_id: 105
+ message_type: initial_request
+ status: sent
+ updated_at: 2012-01-14 01:56:58.586598
+ body: "How much was spent on boring equipment in the 2010-2011 financial year?"
+ last_sent_at: 2012-01-14 10:41:12.686264
+ created_at: 2012-01-14 01:56:58.586598
+ what_doing: normal_sort
+
+another_boring_outgoing_message:
+ id: 5
+ info_request_id: 106
+ message_type: initial_request
+ status: sent
+ body: "How much was spent on boring equipment in the 2010-2011 financial year?"
+ last_sent_at: 2006-01-12 01:57:58.586598
+ created_at: 2006-01-12 01:56:58.586598
+ updated_at: 2006-01-12 01:56:58.586598
+ what_doing: normal_sort
+
+spam_1_outgoing_message:
+ id: 6
+ info_request_id: 107
+ message_type: initial_request
+ status: sent
+ body: "Would you like some cheap v1agra?"
+ last_sent_at: 2007-01-12 01:57:58.586598
+ created_at: 2007-01-12 01:56:58.586598
+ updated_at: 2007-01-12 01:56:58.586598
+ what_doing: normal_sort
+spam_2_outgoing_message:
+ id: 7
+ info_request_id: 108
+ message_type: initial_request
+ status: sent
+ body: "Would you like some cheap v1agra?"
+ last_sent_at: 2007-01-12 02:57:58.586598
+ created_at: 2007-01-12 02:56:58.586598
+ updated_at: 2007-01-12 02:56:58.586598
+ what_doing: normal_sort
diff --git a/spec/fixtures/public_bodies.yml b/spec/fixtures/public_bodies.yml
index 191dd68bb..a0893f1e5 100644
--- a/spec/fixtures/public_bodies.yml
+++ b/spec/fixtures/public_bodies.yml
@@ -16,10 +16,49 @@ humpadink_public_body:
updated_at: 2007-10-25 10:51:01.161639
last_edit_comment: Not sure what this new department does.
request_email: humpadink-requests@localhost
- id: "3"
+ id: 3
version: "2"
last_edit_editor: "francis"
short_name: DfH
url_name: dfh
created_at: 2007-10-25 10:51:01.161639
notes: An albatross told me!!!
+forlorn_public_body:
+ name: "Department of Loneliness"
+ first_letter: D
+ updated_at: 2011-01-26 14:11:02.12345
+ last_edit_comment: 'Aw, bless.'
+ request_email: forlorn-requests@localhost
+ id: 4
+ version: 1
+ last_edit_editor: "robin"
+ short_name: DoL
+ url_name: lonely
+ created_at: 2011-01-26 14:11:02.12345
+ notes: A very lonely public body that no one has corresponded with
+silly_walks_public_body:
+ id: 5
+ version: 1
+ name: "Ministry of Silly Walks"
+ first_letter: M
+ updated_at: 2007-10-25 10:51:01.161639
+ last_edit_comment: Is a comment really required?
+ request_email: silly-walks-requests@localhost
+ last_edit_editor: robin
+ short_name: MSW
+ url_name: msw
+ created_at: 2007-10-25 10:51:01.161639
+ notes: You know the one.
+sensible_walks_public_body:
+ id: 6
+ version: 1
+ name: "Ministry of Sensible Walks"
+ first_letter: M
+ request_email: sensible-walks-requests@localhost
+ short_name: SenseWalk
+ url_name: sensible_walks
+ notes: I bet you’ve never heard of it.
+ updated_at: 2008-10-25 10:51:01.161639
+ last_edit_comment: Another stunning innovation from your friendly national government
+ last_edit_editor: robin
+ created_at: 2008-10-25 10:51:01.161639
diff --git a/spec/fixtures/public_body_translations.yml b/spec/fixtures/public_body_translations.yml
index b5e947044..cbb55bb0c 100644
--- a/spec/fixtures/public_body_translations.yml
+++ b/spec/fixtures/public_body_translations.yml
@@ -24,8 +24,8 @@ humpadink_es_public_body_translation:
name: "El Department for Humpadinking"
first_letter: E
request_email: humpadink-requests@localhost
- id: "3"
- public_body_id: "3"
+ id: 3
+ public_body_id: 3
short_name: eDfH
url_name: edfh
locale: es
@@ -35,9 +35,42 @@ humpadink_en_public_body_translation:
name: "Department for Humpadinking"
first_letter: D
request_email: humpadink-requests@localhost
- id: "4"
- public_body_id: "3"
+ id: 4
+ public_body_id: 3
short_name: DfH
url_name: dfh
locale: en
notes: An albatross told me!!!
+
+forlorn_en_public_body_translation:
+ name: "Department of Loneliness"
+ first_letter: D
+ request_email: forlorn-requests@localhost
+ id: 5
+ public_body_id: 4
+ short_name: DoL
+ url_name: lonely
+ locale: en
+ notes: A very lonely public body that no one has corresponded with
+
+silly_walks_en_public_body_translation:
+ id: 6
+ public_body_id: 5
+ locale: en
+ name: "Ministry of Silly Walks"
+ first_letter: M
+ request_email: silly-walks-requests@localhost
+ short_name: MSW
+ url_name: msw
+ notes: You know the one.
+
+sensible_walks_en_public_body_translation:
+ id: 7
+ public_body_id: 6
+ locale: en
+ name: "Ministry of Sensible Walks"
+ first_letter: M
+ request_email: sensible-walks-requests@localhost
+ short_name: SenseWalk
+ url_name: sensible_walks
+ notes: I bet you’ve never heard of it.
diff --git a/spec/fixtures/raw_emails.yml b/spec/fixtures/raw_emails.yml
index 8ef9248a3..ad2bc0a63 100644
--- a/spec/fixtures/raw_emails.yml
+++ b/spec/fixtures/raw_emails.yml
@@ -1,2 +1,20 @@
-useless_raw_email:
+# The actual email messages are in fixtures/files/raw_emails
+#
+# Note that the words "money" and "bob" are used in some tests
+# of the search functions, so if you use either of these words
+# in the email text then some tests will have to be updated.
+
+useless_raw_email:
id: 1
+
+useful_raw_email:
+ id: 2
+
+another_useful_raw_email:
+ id: 3
+
+spam_1_raw_email:
+ id: 4
+
+spam_2_raw_email:
+ id: 5
diff --git a/spec/fixtures/users.yml b/spec/fixtures/users.yml
index 16ffec034..8620fb3de 100644
--- a/spec/fixtures/users.yml
+++ b/spec/fixtures/users.yml
@@ -53,3 +53,16 @@ unconfirmed_user:
admin_level: 'none'
ban_text: ''
about_me: ''
+robin_user:
+ id: 5
+ name: Robin Houston
+ url_name: robin_houston
+ email: robin@localhost
+ salt: "-6116981980.392287733335677"
+ hashed_password: 6b7cd45a5f35fd83febc0452a799530398bfb6e8 # jonespassword
+ updated_at: 2012-01-01 10:39:15.491593
+ created_at: 2012-01-01 10:39:15.491593
+ email_confirmed: true
+ admin_level: 'none'
+ ban_text: ''
+ about_me: 'I am the best'
diff --git a/spec/helpers/link_to_helper_spec.rb b/spec/helpers/link_to_helper_spec.rb
index aae00c298..3fa91a8f8 100644
--- a/spec/helpers/link_to_helper_spec.rb
+++ b/spec/helpers/link_to_helper_spec.rb
@@ -7,9 +7,14 @@ describe LinkToHelper do
describe 'when creating a url for a request' do
before do
- ActionController::Routing::Routes.filters.clear
@mock_request = mock_model(InfoRequest, :url_title => 'test_title')
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
+ end
+
it 'should return a path like /request/test_title' do
request_url(@mock_request).should == '/request/test_title'
@@ -20,5 +25,17 @@ describe LinkToHelper do
end
end
+
+ describe "when appending something to a URL" do
+ it 'should append to things without query strings' do
+ main_url('/a', '.json').should == 'http://test.localdomain/a.json'
+ end
+ it 'should append to things with query strings' do
+ main_url('/a?z=1', '.json').should == 'http://test.localdomain/a.json?z=1'
+ end
+ it 'should fail silently with invalid URLs' do
+ main_url('/a?z=9%', '.json').should == 'http://test.localdomain/a?z=9%'
+ end
+ end
end
diff --git a/spec/integration/errors_spec.rb b/spec/integration/errors_spec.rb
index bfb7e5fb5..ec2e1c376 100644
--- a/spec/integration/errors_spec.rb
+++ b/spec/integration/errors_spec.rb
@@ -2,22 +2,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "When rendering errors" do
- fixtures [
- :users,
- :public_bodies,
- :public_body_translations,
- :public_body_versions,
- :info_requests,
- :raw_emails,
- :outgoing_messages,
- :incoming_messages,
- :comments,
- :info_request_events,
- :track_things,
- ]
-
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
ActionController::Base.consider_all_requests_local = false
end
@@ -45,5 +31,18 @@ describe "When rendering errors" do
get("/request/#{ir.url_title}")
response.code.should == "500"
end
+ it "should render a 403 for attempts at directory listing for attachments" do
+ # make a fake cache
+ foi_cache_path = File.join(File.dirname(__FILE__), '../../cache')
+ FileUtils.mkdir_p(File.join(foi_cache_path, "views/en/request/101/101/response/1/attach/html/1"))
+ get("/request/101/response/1/attach/html/1/" )
+ response.code.should == "403"
+ get("/request/101/response/1/attach/html" )
+ response.code.should == "403"
+ end
+ it "should render a 404 for non-existent 'details' pages for requests" do
+ get("/details/request/wobble" )
+ response.code.should == "404"
+ end
end
diff --git a/spec/integration/search_request_spec.rb b/spec/integration/search_request_spec.rb
index 07839af32..b62f0a4c4 100644
--- a/spec/integration/search_request_spec.rb
+++ b/spec/integration/search_request_spec.rb
@@ -2,23 +2,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "When searching" do
- fixtures [
- :users,
- :public_bodies,
- :public_body_translations,
- :public_body_versions,
- :info_requests,
- :raw_emails,
- :outgoing_messages,
- :incoming_messages,
- :comments,
- :info_request_events,
- :track_things,
- ]
-
before(:each) do
- emails = raw_emails.clone
- load_raw_emails_data(emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should not strip quotes from quoted query" do
@@ -34,33 +20,46 @@ describe "When searching" do
end
it "should correctly filter searches for requests" do
- request_via_redirect("post", "/search/bob/requests")
+ request_via_redirect("post", "/search/bob/requests")
response.body.should_not include("One person found")
- response.body.should include("FOI requests 1 to 2 of 2")
+ n = 4 # The number of requests that contain the word "bob" somewhere
+ # in the email text. At present this is:
+ # - fancy_dog_request
+ # - naughty_chicken_request
+ # - boring_request
+ # - another_boring_request
+ #
+ # In other words it is all requests made by Bob Smith
+ # except for badger_request, which he did not sign.
+ response.body.should include("FOI requests 1 to #{n} of #{n}")
end
it "should correctly filter searches for users" do
- request_via_redirect("post", "/search/bob/users")
+ request_via_redirect("post", "/search/bob/users")
response.body.should include("One person found")
- response.body.should_not include("FOI requests 1 to 2 of 2")
+ response.body.should_not include("FOI requests 1 to")
end
it "should correctly filter searches for successful requests" do
- request_via_redirect("post", "/search",
+ request_via_redirect("post", "/search/requests",
:query => "bob",
:latest_status => ['successful'])
- response.body.should include("no requests matching your query")
+ n = 2 # The number of *successful* requests that contain the word "bob" somewhere
+ # in the email text. At present this is:
+ # - boring_request
+ # - another_boring_request
+ response.body.should include("FOI requests 1 to #{n} of #{n}")
end
it "should correctly filter searches for comments" do
- request_via_redirect("post", "/search",
+ request_via_redirect("post", "/search/requests",
:query => "daftest",
:request_variety => ['comments'])
response.body.should include("One FOI request found")
- request_via_redirect("post", "/search",
+ request_via_redirect("post", "/search/requests",
:query => "daftest",
:request_variety => ['response','sent'])
- response.body.should include("no requests matching your query")
+ response.body.should include("no results matching your query")
end
end
diff --git a/spec/integration/view_request_spec.rb b/spec/integration/view_request_spec.rb
index cf1e4ca6c..442721890 100644
--- a/spec/integration/view_request_spec.rb
+++ b/spec/integration/view_request_spec.rb
@@ -2,23 +2,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "When viewing requests" do
- fixtures [
- :users,
- :public_bodies,
- :public_body_translations,
- :public_body_versions,
- :info_requests,
- :raw_emails,
- :outgoing_messages,
- :incoming_messages,
- :comments,
- :info_request_events,
- :track_things,
- ]
-
before(:each) do
- emails = raw_emails.clone
- load_raw_emails_data(emails)
+ load_raw_emails_data
end
it "should not make endlessly recursive JSON <link>s" do
diff --git a/spec/lib/sendmail_return_path_spec.rb b/spec/lib/sendmail_return_path_spec.rb
index f1a91240b..7708edb35 100644
--- a/spec/lib/sendmail_return_path_spec.rb
+++ b/spec/lib/sendmail_return_path_spec.rb
@@ -3,6 +3,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "when sending email with an altered return path" do
+ before(:each) { ActionMailer::Base.deliveries = [] }
it "should default to delivery method test" do
ActionMailer::Base.delivery_method.should == :test
diff --git a/spec/lib/tmail_extensions_spec.rb b/spec/lib/tmail_extensions_spec.rb
index 6a55c34da..bd89e6a84 100644
--- a/spec/lib/tmail_extensions_spec.rb
+++ b/spec/lib/tmail_extensions_spec.rb
@@ -6,6 +6,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "when using TMail" do
+ before(:each) do
+ ActionMailer::Base.deliveries.clear
+ end
+
it "should load an email with funny MIME settings" do
# just send it to the holding pen
InfoRequest.holding_pen_request.incoming_messages.size.should == 0
diff --git a/spec/models/foi_attachment_spec.rb b/spec/models/foi_attachment_spec.rb
new file mode 100644
index 000000000..9d44957e4
--- /dev/null
+++ b/spec/models/foi_attachment_spec.rb
@@ -0,0 +1,35 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe FoiAttachment, " when calculating due date" do
+
+ before(:each) do
+ load_raw_emails_data
+ end
+
+ it "sets the body" do
+ attachment = FoiAttachment.new
+ attachment.body = "baz"
+ attachment.body.should == "baz"
+ end
+ it "sets the size" do
+ attachment = FoiAttachment.new
+ attachment.body = "baz"
+ attachment.body.should == "baz"
+ attachment.update_display_size!
+ attachment.display_size.should == "0K"
+ end
+ it "reparses the body if it disappears" do
+ im = incoming_messages(:useless_incoming_message)
+ im.extract_attachments!
+ main = im.get_main_body_text_part
+ orig_body = main.body
+ main.delete_cached_file!
+ lambda {
+ im.get_main_body_text_part.body
+ }.should_not raise_error(Errno::ENOENT)
+ main.delete_cached_file!
+ main = im.get_main_body_text_part
+ main.body.should == orig_body
+
+ end
+end
diff --git a/spec/models/has_tag_string_tag_spec.rb b/spec/models/has_tag_string_tag_spec.rb
index 1acd2e27d..57c301471 100644
--- a/spec/models/has_tag_string_tag_spec.rb
+++ b/spec/models/has_tag_string_tag_spec.rb
@@ -1,7 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe HasTagString::HasTagStringTag, " when fiddling with tag strings " do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "should be able to make a new tag and save it" do
@tag = HasTagString::HasTagStringTag.new
diff --git a/spec/models/holiday_spec.rb b/spec/models/holiday_spec.rb
index 973b067d6..00ebc7279 100644
--- a/spec/models/holiday_spec.rb
+++ b/spec/models/holiday_spec.rb
@@ -1,7 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Holiday, " when calculating due date" do
- fixtures :holidays
def due_date(ymd)
return Holiday.due_date_from(Date.strptime(ymd), 20).strftime("%F")
diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb
index ed31b7c5c..b6fee7898 100644
--- a/spec/models/incoming_message_spec.rb
+++ b/spec/models/incoming_message_spec.rb
@@ -2,14 +2,19 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe IncomingMessage, " when dealing with incoming mail" do
- fixtures :users, :raw_emails, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
@im = incoming_messages(:useless_incoming_message)
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ end
+
+ after(:all) do
+ ActionMailer::Base.deliveries.clear
end
it "should return the mail Date header date for sent at" do
+ @im.parse_raw_email!(true)
+ @im.reload
@im.sent_at.should == @im.mail.date
end
@@ -27,6 +32,31 @@ describe IncomingMessage, " when dealing with incoming mail" do
end
end
+ it "should ensure cached body text has been parsed correctly" do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('quoted-subject-iso8859-1.email', ir.incoming_email)
+ message = ir.incoming_messages[1]
+ message.get_main_body_text_unfolded.should_not include("Email has no body")
+ end
+
+ it "should correctly convert HTML even when there's a meta tag asserting that it is iso-8859-1 which would normally confuse elinks" do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('quoted-subject-iso8859-1.email', ir.incoming_email)
+ message = ir.incoming_messages[1]
+ message.parse_raw_email!
+ message.get_main_body_text_part.charset.should == "iso-8859-1"
+ message.get_main_body_text_internal.should include("política")
+ end
+
+ it "should unquote RFC 2047 headers" do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('quoted-subject-iso8859-1.email', ir.incoming_email)
+ message = ir.incoming_messages[1]
+ message.mail_from.should == "Coordenação de Relacionamento, Pesquisa e Informação/CEDI"
+ message.subject.should == "Câmara Responde: Banco de ideias"
+ end
+
+
it "should fold multiline sections" do
{
"foo\n--------\nconfidential" => "foo\nFOLDED_QUOTED_SECTION\n", # basic test
@@ -102,16 +132,15 @@ describe IncomingMessage, " folding quoted parts of emails" do
end
describe IncomingMessage, " checking validity to reply to" do
- def test_email(result, email, return_path, autosubmitted)
+ def test_email(result, email, return_path, autosubmitted = nil)
@address = mock(TMail::Address)
@address.stub!(:spec).and_return(email)
@return_path = mock(TMail::ReturnPathHeader)
@return_path.stub!(:addr).and_return(return_path)
-
- @autosubmitted = mock(TMail::KeywordsHeader)
- @autosubmitted.stub!(:keys).and_return(autosubmitted)
-
+ if !autosubmitted.nil?
+ @autosubmitted = TMail::UnstructuredHeader.new("auto-submitted", autosubmitted)
+ end
@mail = mock(TMail::Mail)
@mail.stub!(:from_addrs).and_return( [ @address ] )
@mail.stub!(:[]).with("return-path").and_return(@return_path)
@@ -123,45 +152,44 @@ describe IncomingMessage, " checking validity to reply to" do
end
it "says a valid email is fine" do
- test_email(true, "team@mysociety.org", nil, [])
+ test_email(true, "team@mysociety.org", nil)
end
it "says postmaster email is bad" do
- test_email(false, "postmaster@mysociety.org", nil, [])
+ test_email(false, "postmaster@mysociety.org", nil)
end
it "says Mailer-Daemon email is bad" do
- test_email(false, "Mailer-Daemon@mysociety.org", nil, [])
+ test_email(false, "Mailer-Daemon@mysociety.org", nil)
end
it "says case mangled MaIler-DaemOn email is bad" do
- test_email(false, "MaIler-DaemOn@mysociety.org", nil, [])
+ test_email(false, "MaIler-DaemOn@mysociety.org", nil)
end
it "says Auto_Reply email is bad" do
- test_email(false, "Auto_Reply@mysociety.org", nil, [])
+ test_email(false, "Auto_Reply@mysociety.org", nil)
end
it "says DoNotReply email is bad" do
- test_email(false, "DoNotReply@tube.tfl.gov.uk", nil, [])
+ test_email(false, "DoNotReply@tube.tfl.gov.uk", nil)
end
it "says a filled-out return-path is fine" do
- test_email(true, "team@mysociety.org", "Return-path: <foo@baz.com>", [])
+ test_email(true, "team@mysociety.org", "Return-path: <foo@baz.com>")
end
it "says an empty return-path is bad" do
- test_email(false, "team@mysociety.org", "<>", [])
+ test_email(false, "team@mysociety.org", "<>")
end
it "says an auto-submitted keyword is bad" do
- test_email(false, "team@mysociety.org", nil, ["auto-replied"])
+ test_email(false, "team@mysociety.org", nil, "auto-replied")
end
end
describe IncomingMessage, " checking validity to reply to with real emails" do
- fixtures :users, :raw_emails, :public_bodies, :public_body_translations, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
after(:all) do
ActionMailer::Base.deliveries.clear
@@ -185,7 +213,6 @@ describe IncomingMessage, " checking validity to reply to with real emails" do
end
describe IncomingMessage, " when censoring data" do
- fixtures :users, :raw_emails, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
@test_data = "There was a mouse called Stilton, he wished that he was blue."
@@ -206,7 +233,7 @@ describe IncomingMessage, " when censoring data" do
@censor_rule_2.last_edit_comment = "none"
@im.info_request.censor_rules << @censor_rule_2
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should do nothing to a JPEG" do
@@ -293,7 +320,6 @@ describe IncomingMessage, " when censoring data" do
end
describe IncomingMessage, " when censoring whole users" do
- fixtures :users, :raw_emails, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
@test_data = "There was a mouse called Stilton, he wished that he was blue."
@@ -306,7 +332,7 @@ describe IncomingMessage, " when censoring whole users" do
@censor_rule_1.last_edit_editor = "unknown"
@censor_rule_1.last_edit_comment = "none"
@im.info_request.user.censor_rules << @censor_rule_1
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should apply censor rules to HTML files" do
@@ -324,10 +350,9 @@ end
describe IncomingMessage, " when uudecoding bad messages" do
- fixtures :incoming_messages, :raw_emails, :public_bodies, :public_body_translations, :info_requests, :users, :foi_attachments
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should be able to do it at all" do
@@ -368,10 +393,9 @@ describe IncomingMessage, " when uudecoding bad messages" do
end
describe IncomingMessage, "when messages are attached to messages" do
- fixtures :incoming_messages, :raw_emails, :public_bodies, :public_body_translations, :info_requests, :users, :foi_attachments
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should flatten all the attachments out" do
@@ -393,10 +417,9 @@ describe IncomingMessage, "when messages are attached to messages" do
end
describe IncomingMessage, "when Outlook messages are attached to messages" do
- fixtures :incoming_messages, :raw_emails, :public_bodies, :public_body_translations, :info_requests, :users, :foi_attachments
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should flatten all the attachments out" do
@@ -416,10 +439,9 @@ describe IncomingMessage, "when Outlook messages are attached to messages" do
end
describe IncomingMessage, "when TNEF attachments are attached to messages" do
- fixtures :incoming_messages, :raw_emails, :public_bodies, :public_body_translations, :info_requests, :users, :foi_attachments
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should flatten all the attachments out" do
diff --git a/spec/models/info_request_event_spec.rb b/spec/models/info_request_event_spec.rb
index 3229284cc..7352f3be0 100644
--- a/spec/models/info_request_event_spec.rb
+++ b/spec/models/info_request_event_spec.rb
@@ -29,7 +29,8 @@ describe InfoRequestEvent do
describe "should know" do
it "that it's an incoming message" do
- event = InfoRequestEvent.new(:incoming_message => mock_model(IncomingMessage))
+ event = InfoRequestEvent.new()
+ event.stub!(:incoming_message_selective_columns).and_return(1)
event.is_incoming_message?.should be_true
event.is_outgoing_message?.should be_false
event.is_comment?.should be_false
@@ -37,6 +38,7 @@ describe InfoRequestEvent do
it "that it's an outgoing message" do
event = InfoRequestEvent.new(:outgoing_message => mock_model(OutgoingMessage))
+ event.id = 1
event.is_incoming_message?.should be_false
event.is_outgoing_message?.should be_true
event.is_comment?.should be_false
@@ -44,6 +46,7 @@ describe InfoRequestEvent do
it "that it's a comment" do
event = InfoRequestEvent.new(:comment => mock_model(Comment))
+ event.id = 1
event.is_incoming_message?.should be_false
event.is_outgoing_message?.should be_false
event.is_comment?.should be_true
@@ -52,10 +55,9 @@ describe InfoRequestEvent do
end
describe "doing search/index stuff" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
parse_all_incoming_messages
end
@@ -70,6 +72,14 @@ describe InfoRequestEvent do
event.search_text_main.strip.should == "No way! I'm not going to tell you that in a month of Thursdays.\n\nThe Geraldine Quango"
end
+ it 'should get clipped text for incoming messages, and cache it too' do
+ event = info_request_events(:useless_incoming_message_event)
+
+ event.incoming_message_selective_columns("cached_main_body_text_folded").cached_main_body_text_folded = nil
+ event.search_text_main(true).strip.should == "No way! I'm not going to tell you that in a month of Thursdays.\n\nThe Geraldine Quango"
+ event.incoming_message_selective_columns("cached_main_body_text_folded").cached_main_body_text_folded.should_not == nil
+ end
+
end
diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb
index b1baa66a2..a18a4bd1d 100644
--- a/spec/models/info_request_spec.rb
+++ b/spec/models/info_request_spec.rb
@@ -3,11 +3,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe InfoRequest do
describe "guessing a request from an email" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
@im = incoming_messages(:useless_incoming_message)
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it 'should compute a hash' do
@@ -73,8 +72,6 @@ describe InfoRequest do
end
describe " when emailing" do
-
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@info_request = info_requests(:fancy_dog_request)
@@ -154,7 +151,6 @@ describe InfoRequest do
end
describe "when calculating the status" do
- fixtures :holidays, :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@ir = info_requests(:naughty_chicken_request)
@@ -196,8 +192,6 @@ describe InfoRequest do
describe "when using a plugin and calculating the status" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
-
before do
InfoRequest.send(:require, File.expand_path(File.dirname(__FILE__) + '/customstates'))
InfoRequest.send(:include, InfoRequestCustomStates)
@@ -231,7 +225,6 @@ describe InfoRequest do
describe "when calculating the status for a school" do
- fixtures :holidays, :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@ir = info_requests(:naughty_chicken_request)
diff --git a/spec/models/outgoing_mailer_spec.rb b/spec/models/outgoing_mailer_spec.rb
index 75c8053b4..5d1ea2dfb 100644
--- a/spec/models/outgoing_mailer_spec.rb
+++ b/spec/models/outgoing_mailer_spec.rb
@@ -4,9 +4,8 @@ describe OutgoingMailer, " when working out follow up addresses" do
# This is done with fixtures as the code is a bit tangled with the way it
# calls TMail. XXX untangle it and make these tests spread out and using
# mocks. Put parts of the tests in spec/lib/tmail_extensions.rb
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should parse them right" do
@@ -24,6 +23,7 @@ describe OutgoingMailer, " when working out follow up addresses" do
im = ir.incoming_messages[0]
im.raw_email.data = im.raw_email.data.sub("\"FOI Person\" <foiperson@localhost>", "foiperson@localhost")
+ im.parse_raw_email! true
# check the basic entry in the fixture is fine
OutgoingMailer.name_and_email_for_followup(ir, im).should == "foiperson@localhost"
@@ -36,6 +36,7 @@ describe OutgoingMailer, " when working out follow up addresses" do
im = ir.incoming_messages[0]
im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI [ Person")
+ im.parse_raw_email! true
# check the basic entry in the fixture is fine
OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI [ Person\" <foiperson@localhost>"
@@ -48,6 +49,7 @@ describe OutgoingMailer, " when working out follow up addresses" do
im = ir.incoming_messages[0]
im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI \\\" Person")
+ im.parse_raw_email! true
# check the basic entry in the fixture is fine
OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI \\\" Person\" <foiperson@localhost>"
@@ -60,6 +62,7 @@ describe OutgoingMailer, " when working out follow up addresses" do
im = ir.incoming_messages[0]
im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI @ Person")
+ im.parse_raw_email! true
# check the basic entry in the fixture is fine
OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI @ Person\" <foiperson@localhost>"
@@ -70,10 +73,9 @@ describe OutgoingMailer, " when working out follow up addresses" do
end
describe OutgoingMailer, "when working out follow up subjects" do
- fixtures :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
end
it "should prefix the title with 'Freedom of Information request -' for initial requests" do
@@ -116,6 +118,8 @@ describe OutgoingMailer, "when working out follow up subjects" do
om.incoming_message_followup = im
im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: re: Geraldine FOI Code AZXB421")
+ im.parse_raw_email! true
+
OutgoingMailer.subject_for_followup(ir, om).should == "re: Geraldine FOI Code AZXB421"
end
@@ -127,6 +131,8 @@ describe OutgoingMailer, "when working out follow up subjects" do
im.raw_email.data = im.raw_email.data.sub("foiperson@localhost", "postmaster@localhost")
im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Delivery Failed")
+ im.parse_raw_email! true
+
OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?"
end
end
diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb
index 58d9f398e..51bb6fdf5 100644
--- a/spec/models/outgoing_message_spec.rb
+++ b/spec/models/outgoing_message_spec.rb
@@ -1,7 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe OutgoingMessage, " when making an outgoing message" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@om = outgoing_messages(:useless_outgoing_message)
@@ -38,7 +37,6 @@ end
describe IncomingMessage, " when censoring data" do
- fixtures :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@om = outgoing_messages(:useless_outgoing_message)
diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb
index 07e8f291d..db0de78b2 100644
--- a/spec/models/public_body_spec.rb
+++ b/spec/models/public_body_spec.rb
@@ -95,7 +95,6 @@ describe PublicBody, " using machine tags" do
end
describe PublicBody, "when finding_by_tags" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@geraldine = public_bodies(:geraldine_public_body)
@@ -173,7 +172,6 @@ describe PublicBody, " when saving" do
end
describe PublicBody, "when searching" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "should find by existing url name" do
body = PublicBody.find_by_url_name_with_historic('dfh')
@@ -249,10 +247,8 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv("1,aBody", '', 'replace', true, 'someadmin') # true means dry run
errors.should == []
notes.size.should == 2
- notes.should == [
- "line 1: creating new authority 'aBody' (locale: en):\n\t{\"name\":\"aBody\"}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ notes[0].should == "line 1: creating new authority 'aBody' (locale: en):\n\t{\"name\":\"aBody\"}"
+ notes[1].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
end
it "should do a dry run successfully" do
@@ -262,12 +258,12 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin') # true means dry run
errors.should == []
notes.size.should == 4
- notes.should == [
+ notes[0..2].should == [
"line 1: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\"\}",
"line 2: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\"\}",
"line 3: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\"\}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ ]
+ notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
PublicBody.count.should == original_count
end
@@ -279,12 +275,12 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin') # false means real run
errors.should == []
notes.size.should == 4
- notes.should == [
+ notes[0..2].should == [
"line 1: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\"\}",
"line 2: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\"\}",
"line 3: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\"\}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ ]
+ notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
PublicBody.count.should == original_count + 3
end
@@ -296,12 +292,12 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin') # false means real run
errors.should == []
notes.size.should == 4
- notes.should == [
+ notes[0..2].should == [
"line 1: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\"\}",
"line 2: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\"\}",
"line 3: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\"\}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ ]
+ notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
PublicBody.count.should == original_count + 3
end
@@ -312,12 +308,12 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin') # true means dry run
errors.should == []
notes.size.should == 4
- notes.should == [
+ notes[0..2].should == [
"line 2: creating new authority 'North West Fake Authority' (locale: en):\n\t\{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\",\"home_page\":\"http://northwest.org\"\}",
"line 3: creating new authority 'Scottish Fake Authority' (locale: en):\n\t\{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\",\"home_page\":\"http://scottish.org\",\"tag_string\":\"scottish\"\}",
"line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t\{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\",\"tag_string\":\"fake aTag\"\}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ ]
+ notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
PublicBody.count.should == original_count
end
@@ -366,15 +362,15 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', false, 'someadmin', [:en, :es])
errors.should == []
notes.size.should == 7
- notes.should == [
+ notes[0..5].should == [
"line 2: creating new authority 'North West Fake Authority' (locale: en):\n\t{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\",\"home_page\":\"http://northwest.org\"}",
"line 2: creating new authority 'North West Fake Authority' (locale: es):\n\t{\"name\":\"Autoridad del Nordeste\"}",
"line 3: creating new authority 'Scottish Fake Authority' (locale: en):\n\t{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\",\"home_page\":\"http://scottish.org\",\"tag_string\":\"scottish\"}",
"line 3: creating new authority 'Scottish Fake Authority' (locale: es):\n\t{\"name\":\"Autoridad Escocesa\"}",
"line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\",\"tag_string\":\"fake aTag\"}",
"line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: es):\n\t{\"name\":\"Autoridad Irlandesa\"}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ ]
+ notes[6].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
PublicBody.count.should == original_count + 3
@@ -395,12 +391,12 @@ describe PublicBody, " when loading CSV files" do
errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin', ['en', :xx]) # true means dry run
errors.should == []
notes.size.should == 4
- notes.should == [
+ notes[0..2].should == [
"line 2: creating new authority 'North West Fake Authority' (locale: en):\n\t{\"name\":\"North West Fake Authority\",\"request_email\":\"north_west_foi@localhost\",\"home_page\":\"http://northwest.org\"}",
"line 3: creating new authority 'Scottish Fake Authority' (locale: en):\n\t{\"name\":\"Scottish Fake Authority\",\"request_email\":\"scottish_foi@localhost\",\"home_page\":\"http://scottish.org\",\"tag_string\":\"scottish\"}",
"line 4: creating new authority 'Fake Authority of Northern Ireland' (locale: en):\n\t{\"name\":\"Fake Authority of Northern Ireland\",\"request_email\":\"ni_foi@localhost\",\"tag_string\":\"fake aTag\"}",
- "Notes: Some bodies are in database, but not in CSV file:\n Department for Humpadinking\n Geraldine Quango\nYou may want to delete them manually.\n"
- ]
+ ]
+ notes[3].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( [A-Za-z ]+\n)*You may want to delete them manually.\n/
PublicBody.count.should == original_count
end
diff --git a/spec/models/request_mailer_spec.rb b/spec/models/request_mailer_spec.rb
index ef4ed8074..64ac35cf7 100644
--- a/spec/models/request_mailer_spec.rb
+++ b/spec/models/request_mailer_spec.rb
@@ -1,9 +1,9 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe RequestMailer, " when receiving incoming mail" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ ActionMailer::Base.deliveries = []
end
it "should append it to the appropriate request" do
diff --git a/spec/models/track_mailer_spec.rb b/spec/models/track_mailer_spec.rb
index 67a64ee10..4f5499a90 100644
--- a/spec/models/track_mailer_spec.rb
+++ b/spec/models/track_mailer_spec.rb
@@ -155,6 +155,7 @@ describe TrackMailer do
@post_redirect = mock_model(PostRedirect, :save! => true,
:email_token => "token")
PostRedirect.stub!(:new).and_return(@post_redirect)
+ ActionMailer::Base.deliveries = []
end
it 'should deliver one email, with right headers' do
diff --git a/spec/models/track_thing_spec.rb b/spec/models/track_thing_spec.rb
index 4922a96c7..bd122941a 100644
--- a/spec/models/track_thing_spec.rb
+++ b/spec/models/track_thing_spec.rb
@@ -1,7 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe TrackThing, "when tracking changes" do
- fixtures :users, :info_requests, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@track_thing = track_things(:track_fancy_dog_search)
@@ -28,6 +27,13 @@ describe TrackThing, "when tracking changes" do
found_track.should == @track_thing
end
+ it "can display the description of a deleted track_thing" do
+ track_thing = TrackThing.create_track_for_search_query('fancy dog')
+ description = track_thing.track_query_description
+ track_thing.destroy
+ track_thing.track_query_description.should == description
+ end
+
it "will make some sane descriptions of search-based tracks" do
tests = [['bob variety:user', "users matching text 'bob'"],
['bob (variety:sent OR variety:followup_sent OR variety:response OR variety:comment) (latest_status:successful OR latest_status:partially_successful OR latest_status:rejected OR latest_status:not_held)', "requests which are successful or unsuccessful or comments matching text 'bob'"],
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index e0a6c649e..03b2f34f9 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -29,7 +29,7 @@ describe User, "showing the name" do
it 'should show if user has been banned' do
@user.ban_text = "Naughty user"
- @user.name.should == 'Some Name (Banned)'
+ @user.name.should == 'Some Name (Account suspended)'
end
end
@@ -193,7 +193,6 @@ describe User, "when reindexing referencing models" do
end
describe User, "when checking abilities" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@user = users(:bob_smith_user)
@@ -283,7 +282,6 @@ describe User, "when setting a profile photo" do
end
describe User, "when unconfirmed" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before do
@user = users(:unconfirmed_user)
@@ -295,7 +293,6 @@ describe User, "when unconfirmed" do
end
describe User, "when emails have bounced" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
it "should record bounces" do
User.record_bounce_for_email("bob@localhost", "The reason we think the email bounced (e.g. a bounce message)")
diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb
index ec11c944b..81c066184 100644
--- a/spec/models/xapian_spec.rb
+++ b/spec/models/xapian_spec.rb
@@ -1,19 +1,20 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe User, " when indexing users with Xapian" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
- it "should search by name" do
- parse_all_incoming_messages
+ before(:each) do
+ load_raw_emails_data
rebuild_xapian_index
- # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
+ end
+
+ it "should search by name" do
+ # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
xapian_object = InfoRequest.full_search([User], "Silly", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == users(:silly_name_user)
end
it "should search by 'about me' text" do
- rebuild_xapian_index
user = users(:bob_smith_user)
# def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
@@ -35,59 +36,51 @@ describe User, " when indexing users with Xapian" do
end
describe PublicBody, " when indexing public bodies with Xapian" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should search index the main name field" do
- rebuild_xapian_index
-
xapian_object = InfoRequest.full_search([PublicBody], "humpadinking", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body)
end
it "should search index the notes field" do
- rebuild_xapian_index
-
xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body)
end
it "should delete public bodies from the index when they are destroyed" do
- rebuild_xapian_index
-
xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body)
- public_bodies(:humpadink_public_body).destroy
+ public_bodies(:forlorn_public_body).destroy
update_xapian_index
- xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 0
+ xapian_object = InfoRequest.full_search([PublicBody], "lonely", 'created_at', true, nil, 100, 1)
+ xapian_object.results.should == []
end
end
describe PublicBody, " when indexing requests by body they are to" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should find requests to the body" do
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 4
end
it "should update index correctly when URL name of body changes" do
# initial search
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 4
models_found_before = xapian_object.results.map { |x| x[:model] }
@@ -112,8 +105,6 @@ describe PublicBody, " when indexing requests by body they are to" do
# if you index via the Xapian TermGenerator, it ignores terms of this length,
# this checks we're using Document:::add_term() instead
it "should work with URL names that are longer than 64 characters" do
- rebuild_xapian_index
-
# change the URL name of the body
body = public_bodies(:geraldine_public_body)
body.short_name = 'The Uncensored, Complete Name of the Quasi-Autonomous Public Body Also Known As Geraldine'
@@ -133,28 +124,25 @@ describe PublicBody, " when indexing requests by body they are to" do
end
describe User, " when indexing requests by user they are from" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should find requests from the user" do
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 4
+ xapian_object.results.map{|x|x[:model]}.should =~ InfoRequestEvent.all(:conditions => "info_request_id in (select id from info_requests where user_id = #{users(:bob_smith_user).id})")
end
it "should find just the sent message events from a particular user" do
- rebuild_xapian_index
# def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith variety:sent", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 2
- xapian_object.results[1][:model].should == info_request_events(:useless_outgoing_message_event)
- xapian_object.results[0][:model].should == info_request_events(:silly_outgoing_message_event)
+ xapian_object.results.map{|x|x[:model]}.should =~ InfoRequestEvent.all(:conditions => "info_request_id in (select id from info_requests where user_id = #{users(:bob_smith_user).id}) and event_type = 'sent'")
+ xapian_object.results[2][:model].should == info_request_events(:useless_outgoing_message_event)
+ xapian_object.results[1][:model].should == info_request_events(:silly_outgoing_message_event)
end
it "should not find it when one of the request's users is changed" do
- rebuild_xapian_index
silly_user = users(:silly_name_user)
naughty_chicken_request = info_requests(:naughty_chicken_request)
naughty_chicken_request.user = silly_user
@@ -164,13 +152,10 @@ describe User, " when indexing requests by user they are from" do
# def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, 'request_collapse', 100, 1)
- xapian_object.results.size.should == 1
- xapian_object.results[0][:model].should == info_request_events(:silly_comment_event)
+ xapian_object.results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(:conditions => "user_id = #{users(:bob_smith_user).id}")
end
it "should not get confused searching for requests when one user has a name which has same stem as another" do
- rebuild_xapian_index
-
bob_smith_user = users(:bob_smith_user)
bob_smith_user.name = "John King"
bob_smith_user.url_name.should == 'john_king'
@@ -196,9 +181,8 @@ describe User, " when indexing requests by user they are from" do
it "should update index correctly when URL name of user changes" do
# initial search
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 4
+ xapian_object.results.map{|x|x[:model]}.should =~ InfoRequestEvent.all(:conditions => "info_request_id in (select id from info_requests where user_id = #{users(:bob_smith_user).id})")
models_found_before = xapian_object.results.map { |x| x[:model] }
# change the URL name of the body
@@ -212,28 +196,24 @@ describe User, " when indexing requests by user they are from" do
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 0
xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:robert_smith", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 4
models_found_after = xapian_object.results.map { |x| x[:model] }
-
models_found_before.should == models_found_after
end
end
describe User, " when indexing comments by user they are by" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should find requests from the user" do
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
end
it "should update index correctly when URL name of user changes" do
# initial search
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
models_found_before = xapian_object.results.map { |x| x[:model] }
@@ -257,13 +237,12 @@ describe User, " when indexing comments by user they are by" do
end
describe InfoRequest, " when indexing requests by their title" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should find events for the request" do
- rebuild_xapian_index
xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event)
@@ -271,7 +250,6 @@ describe InfoRequest, " when indexing requests by their title" do
it "should update index correctly when URL title of request changes" do
# change the URL name of the body
- rebuild_xapian_index
ir = info_requests(:naughty_chicken_request)
ir.title = 'Really naughty'
ir.save!
@@ -288,13 +266,12 @@ describe InfoRequest, " when indexing requests by their title" do
end
describe InfoRequest, " when indexing requests by tag" do
- fixtures :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should find request by tag, even when changes" do
- rebuild_xapian_index
ir = info_requests(:naughty_chicken_request)
ir.tag_string = 'bunnyrabbit'
ir.save!
@@ -310,13 +287,12 @@ describe InfoRequest, " when indexing requests by tag" do
end
describe PublicBody, " when indexing authorities by tag" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should find request by tag, even when changes" do
- rebuild_xapian_index
body = public_bodies(:geraldine_public_body)
body.tag_string = 'mice:3'
body.save!
@@ -335,13 +311,12 @@ describe PublicBody, " when indexing authorities by tag" do
end
describe PublicBody, " when only indexing selected things on a rebuild" do
- fixtures :public_bodies, :public_body_translations, :public_body_versions, :users, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things
before(:each) do
- load_raw_emails_data(raw_emails)
+ load_raw_emails_data
+ rebuild_xapian_index
end
it "should only index what we ask it to" do
- rebuild_xapian_index
body = public_bodies(:geraldine_public_body)
body.tag_string = 'mice:3'
body.name = 'frobzn'
@@ -357,7 +332,7 @@ describe PublicBody, " when only indexing selected things on a rebuild" do
xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 0
xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 2
+ xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all
# only reindex 'tag' and text
dropfirst = true
terms = "U"
@@ -380,7 +355,7 @@ describe PublicBody, " when only indexing selected things on a rebuild" do
xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 2
+ xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all
# only reindex 'variety' term, blowing away existing data
dropfirst = true
rebuild_xapian_index(terms, values, texts, dropfirst)
@@ -389,18 +364,7 @@ describe PublicBody, " when only indexing selected things on a rebuild" do
xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 0
xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
- xapian_object.results.size.should == 2
+ xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all
end
end
-
-
-
-
-
-
-
-
-
-
-
diff --git a/spec/script/handle-mail-replies_spec.rb b/spec/script/handle-mail-replies_spec.rb
index eae0b516b..8ed83b31f 100644
--- a/spec/script/handle-mail-replies_spec.rb
+++ b/spec/script/handle-mail-replies_spec.rb
@@ -54,5 +54,15 @@ describe "When filtering" do
r = mail_reply_test("track-response-messageclass-oof.email")
r.status.should == 2
end
+
+ it "should detect an Outlook(?)-style out-of-office" do
+ r = mail_reply_test("track-response-outlook-oof.email")
+ r.status.should == 2
+ end
+
+ it "should detect an ABCMail-style out-of-office" do
+ r = mail_reply_test("track-response-abcmail-oof.email")
+ r.status.should == 2
+ end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 5c5cd9a7f..c00da48bc 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,6 @@
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
# from the project root directory.
-ENV["RAILS_ENV"] ||= 'test'
+ENV["RAILS_ENV"] = 'test'
require File.expand_path(File.join('..', '..', 'config', 'environment'), __FILE__)
require 'spec/autorun'
require 'spec/rails'
@@ -24,6 +24,7 @@ Spec::Runner.configure do |config|
# fixture_path must end in a separator
config.fixture_path = File.join(Rails.root, 'spec', 'fixtures') + File::SEPARATOR
+ config.global_fixtures = :users, :public_bodies, :public_body_translations, :public_body_versions, :info_requests, :raw_emails, :incoming_messages, :outgoing_messages, :comments, :info_request_events, :track_things, :foi_attachments, :has_tag_string_tags, :holidays, :track_things_sent_emails
# == Fixtures
#
@@ -78,7 +79,6 @@ def load_file_fixture(file_name)
end
def rebuild_xapian_index(terms = true, values = true, texts = true, dropfirst = true)
- parse_all_incoming_messages
if dropfirst
begin
ActsAsXapian.readable_init
@@ -86,7 +86,9 @@ def rebuild_xapian_index(terms = true, values = true, texts = true, dropfirst =
rescue RuntimeError
end
ActsAsXapian.writable_init
+ ActsAsXapian.writable_db.close
end
+ parse_all_incoming_messages
verbose = false
# safe_rebuild=true, which involves forking to avoid memory leaks, doesn't work well with rspec.
# unsafe is significantly faster, and we can afford possible memory leaks while testing.
@@ -96,7 +98,7 @@ end
def update_xapian_index
verbose = false
- ActsAsXapian.update_index(flush_to_disk=true, verbose)
+ ActsAsXapian.update_index(flush_to_disk=false, verbose)
end
# Validate an entire HTML page
@@ -106,7 +108,7 @@ def validate_html(html)
File.open(tempfilename, "w+") do |f|
f.puts html
end
- if not system($html_validation_script, tempfilename)
+ if not system($html_validation_script, *($html_validation_script_options +[tempfilename]))
raise "HTML validation error in " + tempfilename + " HTTP status: " + @response.response_code.to_s
end
File.unlink(tempfilename)
@@ -120,30 +122,47 @@ def validate_as_body(html)
end
def basic_auth_login(request, username = nil, password = nil)
- username = MySociety::Config.get('ADMIN_USERNAME') if username.nil?
+ username = MySociety::Config.get('ADMIN_USERNAME') if username.nil?
password = MySociety::Config.get('ADMIN_PASSWORD') if password.nil?
request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("#{username}:#{password}")
end
# Monkeypatch! Validate HTML in tests.
-$html_validation_script = "/usr/bin/validate" # from Debian package wdg-html-validator
+utility_search_path = MySociety::Config.get("UTILITY_SEARCH_PATH", ["/usr/bin", "/usr/local/bin"])
+$html_validation_script_found = false
+utility_search_path.each do |d|
+ $html_validation_script = File.join(d, "validate")
+ $html_validation_script_options = ["--charset=utf-8"]
+ if File.file? $html_validation_script and File.executable? $html_validation_script
+ $html_validation_script_found = true
+ break
+ end
+end
if $tempfilecount.nil?
$tempfilecount = 0
- if File.exist?($html_validation_script)
+ if $html_validation_script_found
module ActionController
module TestProcess
# Hook into the process function, so can automatically get HTML after each request
alias :original_process :process
-
+ def is_fragment
+ # XXX there must be a better way of doing this!
+ return @request.query_parameters["action"] == "search_typeahead"
+ end
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
self.original_process(action, parameters, session, flash, http_method)
-
+ # don't validate auto-generated HTML
+ return if @request.query_parameters["action"] == "get_attachment_as_html"
# XXX Is there a better way to check this than calling a private method?
return unless @response.template.controller.instance_eval { integrate_views? }
-
# And then if HTML, not a redirect (302, 301)
if @response.content_type == "text/html" && ! [301,302,401].include?(@response.response_code)
+ if !is_fragment
validate_html(@response.body)
+ else
+ # it's a partial
+ validate_as_body(@response.body)
+ end
end
end
end
@@ -161,15 +180,22 @@ def safe_mock_model(model, args = {})
mock
end
-def load_raw_emails_data(raw_emails)
- raw_email = raw_emails(:useless_raw_email)
- begin
- raw_email.destroy_file_representation!
- rescue Errno::ENOENT
+def load_raw_emails_data
+ raw_emails_yml = File.join(Spec::Runner.configuration.fixture_path, "raw_emails.yml")
+ for raw_email_id in YAML::load_file(raw_emails_yml).map{|k,v| v["id"]} do
+ raw_email = RawEmail.find(raw_email_id)
+ raw_email.data = load_file_fixture("raw_emails/%d.email" % [raw_email_id])
end
- raw_email.data = load_file_fixture("useless_raw_email.email")
end
def parse_all_incoming_messages
IncomingMessage.find(:all).each{|x| x.parse_raw_email!}
end
+
+def load_test_categories
+ PublicBodyCategories.add(:en, [
+ "Local and regional",
+ [ "local_council", "Local councils", "a local council" ],
+ "Miscellaneous",
+ [ "other", "Miscellaneous", "miscellaneous" ],])
+end
diff --git a/spec/views/request/list.rhtml_spec.rb b/spec/views/request/list.rhtml_spec.rb
index 1f86ec641..c7067294f 100644
--- a/spec/views/request/list.rhtml_spec.rb
+++ b/spec/views/request/list.rhtml_spec.rb
@@ -33,6 +33,7 @@ describe "when listing recent requests" do
it "should be successful" do
assigns[:list_results] = [ make_mock_event, make_mock_event ]
assigns[:matches_estimated] = 2
+ assigns[:show_no_more_than] = 100
render "request/list"
response.should have_tag("div.request_listing")
response.should_not have_tag("p", /No requests of this sort yet/m)
@@ -41,6 +42,7 @@ describe "when listing recent requests" do
it "should cope with no results" do
assigns[:list_results] = [ ]
assigns[:matches_estimated] = 0
+ assigns[:show_no_more_than] = 0
render "request/list"
response.should have_tag("p", /No requests of this sort yet/m)
response.should_not have_tag("div.request_listing")
diff --git a/spec/views/request/show.rhtml_spec.rb b/spec/views/request/show.rhtml_spec.rb
index adb244f47..ef7d1a47c 100644
--- a/spec/views/request/show.rhtml_spec.rb
+++ b/spec/views/request/show.rhtml_spec.rb
@@ -84,10 +84,15 @@ describe 'when viewing an information request' do
describe 'when there is a last response' do
before do
- ActionController::Routing::Routes.filters.clear
@mock_response = mock_model(IncomingMessage)
@mock_request.stub!(:get_last_response).and_return(@mock_response)
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
+ end
+
it 'should show a link to follow up the last response with clarification' do
request_page
@@ -100,9 +105,14 @@ describe 'when viewing an information request' do
describe 'when there is no last response' do
before do
- ActionController::Routing::Routes.filters.clear
@mock_request.stub!(:get_last_response).and_return(nil)
+ @old_filters = ActionController::Routing::Routes.filters
+ ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
end
+ after do
+ ActionController::Routing::Routes.filters = @old_filters
+ end
+
it 'should show a link to follow up the request without reference to a specific response' do
request_page