aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--README.md17
-rw-r--r--app/controllers/application_controller.rb15
-rw-r--r--app/controllers/general_controller.rb20
-rw-r--r--app/controllers/reports_controller.rb31
-rw-r--r--app/controllers/request_controller.rb37
-rw-r--r--app/controllers/user_controller.rb6
-rw-r--r--app/mailers/track_mailer.rb6
-rw-r--r--app/models/info_request.rb87
-rw-r--r--app/models/info_request_event.rb2
-rw-r--r--app/models/outgoing_message.rb22
-rw-r--r--app/views/general/_stylesheet_includes.html.erb5
-rw-r--r--app/views/general/custom_css.html.erb1
-rw-r--r--app/views/layouts/no_chrome.html.erb17
-rw-r--r--app/views/public_body/_search_ahead.html.erb5
-rw-r--r--app/views/public_body/show.html.erb7
-rw-r--r--app/views/reports/new.html.erb26
-rw-r--r--app/views/request/_sidebar.html.erb2
-rw-r--r--app/views/request/new_please_describe.html.erb2
-rw-r--r--app/views/request/select_authority.html.erb21
-rw-r--r--config/general.yml-example5
-rw-r--r--config/packages1
-rw-r--r--config/packages_development9
-rw-r--r--config/routes.rb14
-rw-r--r--doc/THEMES.md12
-rw-r--r--lib/configuration.rb1
-rw-r--r--lib/tasks/themes.rake12
-rw-r--r--lib/tasks/translation.rake12
-rw-r--r--public/stylesheets/ie6-custom.css1
-rw-r--r--public/stylesheets/main.css5
-rw-r--r--spec/controllers/general_controller_spec.rb1
-rw-r--r--spec/controllers/reports_controller_spec.rb104
-rw-r--r--spec/controllers/request_controller_spec.rb312
-rw-r--r--spec/mailers/outgoing_mailer_spec.rb111
-rw-r--r--spec/mailers/track_mailer_spec.rb8
-rw-r--r--spec/models/info_request_spec.rb31
-rw-r--r--spec/models/outgoing_message_spec.rb19
-rw-r--r--spec/models/xapian_spec.rb129
-rw-r--r--spec/spec_helper.rb12
-rw-r--r--spec/views/reports/new.erb_spec.rb29
-rw-r--r--vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb5
41 files changed, 698 insertions, 467 deletions
diff --git a/.travis.yml b/.travis.yml
index 4fd2a59f7..051dc0fae 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,12 @@
language: ruby
branches:
only:
- - develop
- master
- rails-3-develop
rvm:
- 1.8.7
- 1.9.3
before_install:
- - gem update --system 1.8.5
- - gem update --system 1.6.2
- gem install rake --version=0.9.2.2
- git submodule update --init --recursive
- psql -c "create database foi_test template template0 encoding 'SQL_ASCII';" -U postgres
diff --git a/README.md b/README.md
index 9cdb766bb..8dc3125a1 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Welcome to Alaveteli!
-[![Build Status](https://secure.travis-ci.org/mysociety/alaveteli.png)](http://travis-ci.org/mysociety/alaveteli) [![Dependency Status](https://gemnasium.com/mysociety/alaveteli.png)](https://gemnasium.com/mysociety/alaveteli) [![Coverage Status](https://coveralls.io/repos/mysociety/alaveteli/badge.png?branch=master)](https://coveralls.io/r/mysociety/alaveteli) [![Code Climate](https://codeclimate.com/github/mysociety/alaveteli.png)](https://codeclimate.com/github/mysociety/alaveteli)
+[![Build Status](https://secure.travis-ci.org/mysociety/alaveteli.png)](http://travis-ci.org/mysociety/alaveteli) [![Dependency Status](https://gemnasium.com/mysociety/alaveteli.png)](https://gemnasium.com/mysociety/alaveteli) [![Coverage Status](https://coveralls.io/repos/mysociety/alaveteli/badge.png?branch=rails-3-develop)](https://coveralls.io/r/mysociety/alaveteli) [![Code Climate](https://codeclimate.com/github/mysociety/alaveteli.png)](https://codeclimate.com/github/mysociety/alaveteli)
This is an open source project to create a standard, internationalised
platform for making Freedom of Information (FOI) requests in different
@@ -24,6 +24,21 @@ There's background information and a more documentation on
of useful information (including a blog) on
[the project website](http://alaveteli.org)
+## How to contribute
+
+If you find what looks like a bug:
+
+* Check the [GitHub issue tracker](http://github.com/mysociety/alaveteli/issues/)
+ to see if anyone else has reported issue.
+* If you don't see anything, create an issue with information on how to reproduce it.
+
+If you want to contribute an enhancement or a fix:
+
+* Fork the project on GitHub.
+* Make your changes with tests.
+* Commit the changes without making changes to any files that aren't related to your enhancement or fix.
+* Send a pull request.
+
Looking for the latest stable release? It's on the
[master branch](https://github.com/mysociety/alaveteli/tree/master).
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index d1d702616..dffc16b63 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -361,12 +361,15 @@ class ApplicationController < ActionController::Base
# Peform the search
@per_page = per_page
- if this_page.nil?
- @page = get_search_page_from_params
- else
- @page = this_page
- end
- result = InfoRequest.full_search(models, @query, order, ascending, collapse, @per_page, @page)
+ @page = this_page || get_search_page_from_params
+
+ result = ActsAsXapian::Search.new(models, @query,
+ :offset => (@page - 1) * @per_page,
+ :limit => @per_page,
+ :sort_by_prefix => order,
+ :sort_by_ascending => ascending,
+ :collapse_by_prefix => collapse
+ )
result.results # Touch the results to load them, otherwise accessing them from the view
# might fail later if the database has subsequently been reopened.
return result
diff --git a/app/controllers/general_controller.rb b/app/controllers/general_controller.rb
index 9d0f91dda..15f5df840 100644
--- a/app/controllers/general_controller.rb
+++ b/app/controllers/general_controller.rb
@@ -153,7 +153,7 @@ class GeneralController < ApplicationController
# structured query which should show newest first, rather than a free text search
# where we want most relevant as default.
begin
- dummy_query = ::ActsAsXapian::Search.new([InfoRequestEvent], @query, :limit => 1)
+ dummy_query = ActsAsXapian::Search.new([InfoRequestEvent], @query, :limit => 1)
rescue => e
flash[:error] = "Your query was not quite right. " + CGI.escapeHTML(e.to_str)
redirect_to search_url("")
@@ -169,10 +169,8 @@ class GeneralController < ApplicationController
# Query each type separately for separate display (XXX we are calling
# perform_search multiple times and it clobbers per_page for each one,
# so set as separate var)
- requests_per_page = 25
- if params[:requests_per_page]
- requests_per_page = params[:requests_per_page].to_i
- end
+ requests_per_page = params[:requests_per_page] ? params[:requests_per_page].to_i : 25
+
@this_page_hits = @total_hits = @xapian_requests_hits = @xapian_bodies_hits = @xapian_users_hits = 0
if @requests
@xapian_requests = perform_search([InfoRequestEvent], @query, @sortby, 'request_collapse', requests_per_page)
@@ -211,18 +209,6 @@ class GeneralController < ApplicationController
@feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ]
end
- # Jump to a random request
- def random_request
- info_request = InfoRequest.random
- redirect_to request_url(info_request)
- end
-
- def custom_css
- long_cache
- @locale = self.locale_from_params()
- render(:layout => false, :content_type => 'text/css')
- end
-
# Handle requests for non-existent URLs - will be handled by ApplicationController::render_exception
def not_found
raise RouteNotFound
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
new file mode 100644
index 000000000..a1dd53125
--- /dev/null
+++ b/app/controllers/reports_controller.rb
@@ -0,0 +1,31 @@
+class ReportsController < ApplicationController
+ def create
+ @info_request = InfoRequest.find_by_url_title!(params[:request_id])
+ @reason = params[:reason]
+ @message = params[:message]
+ if @reason.empty?
+ flash[:error] = _("Please choose a reason")
+ render "new"
+ return
+ end
+
+ if !authenticated_user
+ flash[:notice] = _("You need to be logged in to report a request for administrator attention")
+ elsif @info_request.attention_requested
+ flash[:notice] = _("This request has already been reported for administrator attention")
+ else
+ @info_request.report!(@reason, @message, @user)
+ flash[:notice] = _("This request has been reported for administrator attention")
+ end
+ redirect_to request_url(@info_request)
+ end
+
+ def new
+ @info_request = InfoRequest.find_by_url_title!(params[:request_id])
+ if authenticated?(
+ :web => _("To report this request"),
+ :email => _("Then you can report the request '{{title}}'", :title => @info_request.title),
+ :email_subject => _("Report an offensive or unsuitable request"))
+ end
+ end
+end
diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb
index a455d1725..42693f867 100644
--- a/app/controllers/request_controller.rb
+++ b/app/controllers/request_controller.rb
@@ -100,7 +100,7 @@ class RequestController < ApplicationController
# ... requests that have similar imporant terms
begin
limit = 10
- @xapian_similar = ::ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events,
+ @xapian_similar = ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events,
:limit => limit, :collapse_by_prefix => 'request_collapse')
@xapian_similar_more = (@xapian_similar.matches_estimated > limit)
rescue
@@ -146,7 +146,7 @@ class RequestController < ApplicationController
if !@info_request.user_can_view?(authenticated_user)
return render_hidden
end
- @xapian_object = ::ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events,
+ @xapian_object = ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events,
:offset => (@page - 1) * @per_page, :limit => @per_page, :collapse_by_prefix => 'request_collapse')
@matches_estimated = @xapian_object.matches_estimated
@show_no_more_than = (@matches_estimated > MAX_RESULTS) ? MAX_RESULTS : @matches_estimated
@@ -461,9 +461,19 @@ class RequestController < ApplicationController
when 'rejected'
_("Oh no! Sorry to hear that your request was refused. Here is what to do now.")
when 'successful'
- _("<p>We're glad you got all the information that you wanted. If you write about or make use of the information, please come back and add an annotation below saying what you did.</p><p>If you found {{site_name}} useful, <a href=\"{{donation_url}}\">make a donation</a> to the charity which runs it.</p>", :site_name=>site_name, :donation_url => "http://www.mysociety.org/donate/")
+ if AlaveteliConfiguration::donation_url.blank?
+ _("<p>We're glad you got all the information that you wanted. If you write about or make use of the information, please come back and add an annotation below saying what you did.</p>")
+ else
+ _("<p>We're glad you got all the information that you wanted. If you write about or make use of the information, please come back and add an annotation below saying what you did.</p><p>If you found {{site_name}} useful, <a href=\"{{donation_url}}\">make a donation</a> to the charity which runs it.</p>",
+ :site_name => site_name, :donation_url => AlaveteliConfiguration::donation_url)
+ end
when 'partially_successful'
- _("<p>We're glad you got some of the information that you wanted. If you found {{site_name}} useful, <a href=\"{{donation_url}}\">make a donation</a> to the charity which runs it.</p><p>If you want to try and get the rest of the information, here's what to do now.</p>", :site_name=>site_name, :donation_url=>"http://www.mysociety.org/donate/")
+ if AlaveteliConfiguration::donation_url.blank?
+ _("<p>We're glad you got some of the information that you wanted.</p><p>If you want to try and get the rest of the information, here's what to do now.</p>")
+ else
+ _("<p>We're glad you got some of the information that you wanted. If you found {{site_name}} useful, <a href=\"{{donation_url}}\">make a donation</a> to the charity which runs it.</p><p>If you want to try and get the rest of the information, here's what to do now.</p>",
+ :site_name => site_name, :donation_url => AlaveteliConfiguration::donation_url)
+ end
when 'waiting_clarification'
_("Please write your follow up message containing the necessary clarifications below.")
when 'gone_postal'
@@ -676,25 +686,6 @@ class RequestController < ApplicationController
end
end
- def report_request
- info_request = InfoRequest.find_by_url_title!(params[:url_title])
- return if !authenticated?(
- :web => _("To report this FOI request"),
- :email => _("Then you can report the request '{{title}}'", :title => info_request.title),
- :email_subject => _("Report an offensive or unsuitable request")
- )
-
- if !info_request.attention_requested
- info_request.set_described_state('attention_requested', @user)
- info_request.attention_requested = true # tells us if attention has ever been requested
- info_request.save!
- flash[:notice] = _("This request has been reported for administrator attention")
- else
- flash[:notice] = _("This request has already been reported for administrator attention")
- end
- redirect_to request_url(info_request)
- end
-
# special caching code so mime types are handled right
around_filter :cache_attachments, :only => [ :get_attachment, :get_attachment_as_html ]
def cache_attachments
diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb
index b7912b528..1ccab3003 100644
--- a/app/controllers/user_controller.rb
+++ b/app/controllers/user_controller.rb
@@ -119,7 +119,11 @@ class UserController < ApplicationController
@track_things = TrackThing.find(:all, :conditions => ["tracking_user_id = ? and track_medium = ?", @display_user.id, 'email_daily'], :order => 'created_at desc')
for track_thing in @track_things
# XXX factor out of track_mailer.rb
- xapian_object = InfoRequest.full_search([InfoRequestEvent], track_thing.track_query, 'described_at', true, nil, 20, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], track_thing.track_query,
+ :sort_by_prefix => 'described_at',
+ :sort_by_ascending => true,
+ :collapse_by_prefix => nil,
+ :limit => 20)
feed_results += xapian_object.results.map {|x| x[:model]}
end
end
diff --git a/app/mailers/track_mailer.rb b/app/mailers/track_mailer.rb
index 391143214..1bd8a7e23 100644
--- a/app/mailers/track_mailer.rb
+++ b/app/mailers/track_mailer.rb
@@ -67,7 +67,11 @@ class TrackMailer < ApplicationMailer
# Query for things in this track. We use described_at for the
# ordering, so we catch anything new (before described), or
# anything whose new status has been described.
- xapian_object = InfoRequest.full_search([InfoRequestEvent], track_thing.track_query, 'described_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], track_thing.track_query,
+ :sort_by_prefix => 'described_at',
+ :sort_by_ascending => true,
+ :collapse_by_prefix => nil,
+ :limit => 100)
# Go through looking for unalerted things
alert_results = []
for result in xapian_object.results
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index c549d6f5d..46c247fa9 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -108,6 +108,12 @@ class InfoRequest < ActiveRecord::Base
states
end
+ # Possible reasons that a request could be reported for administrator attention
+ def report_reasons
+ ["Contains defamatory material", "Not a valid request", "Request for personal information",
+ "Contains personal information", "Vexatious", "Other"]
+ end
+
def must_be_valid_state
errors.add(:described_state, "is not a valid state") if
!InfoRequest.enumerate_states.include? described_state
@@ -150,6 +156,10 @@ class InfoRequest < ActiveRecord::Base
end
end
+ def user_json_for_api
+ is_external? ? { :name => user_name || _("Anonymous user") } : user.json_for_api
+ end
+
@@custom_states_loaded = false
begin
if !Rails.env.test?
@@ -189,21 +199,6 @@ class InfoRequest < ActiveRecord::Base
self.comments.find(:all, :conditions => 'visible')
end
- # Central function to do all searches
- # (Not really the right place to put it, but everything can get it here, and it
- # does *mainly* find info requests, via their events, so hey)
- def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
- offset = (page - 1) * per_page
-
- return ::ActsAsXapian::Search.new(
- models, query,
- :offset => offset, :limit => per_page,
- :sort_by_prefix => order,
- :sort_by_ascending => ascending,
- :collapse_by_prefix => collapse
- )
- end
-
# If the URL name has changed, then all request: queries will break unless
# we update index for every event. Also reindex if prominence changes.
after_update :reindex_some_request_events
@@ -232,17 +227,6 @@ class InfoRequest < ActiveRecord::Base
end
end
- # For debugging
- def InfoRequest.profile_search(query)
- t = Time.now.usec
- for i in (1..10)
- t = Time.now.usec - t
- secs = t / 1000000.0
- STDOUT.write secs.to_s + " query " + i.to_s + "\n"
- results = InfoRequest.full_search([InfoRequestEvent], query, "created_at", true, nil, 25, 1).results
- end
- end
-
public
# When name is changed, also change the url name
def title=(title)
@@ -351,7 +335,10 @@ public
# copying an email, and that doesn't matter)
def InfoRequest.find_by_incoming_email(incoming_email)
id, hash = InfoRequest._extract_id_hash_from_email(incoming_email)
- return self.find_by_magic_email(id, hash)
+ if hash_from_id(id) == hash
+ # Not using find(id) because we don't exception raised if nothing found
+ find_by_id(id)
+ end
end
# Return list of info requests which *might* be right given email address
@@ -566,6 +553,15 @@ public
['requires_admin', 'error_message', 'attention_requested'].include?(described_state)
end
+ # Report this request for administrator attention
+ def report!(reason, message, user)
+ ActiveRecord::Base.transaction do
+ set_described_state('attention_requested', user, "Reason: #{reason}\n\n#{message}")
+ self.attention_requested = true # tells us if attention has ever been requested
+ save!
+ end
+ end
+
# change status, including for last event for later historical purposes
def set_described_state(new_state, set_by = nil, message = "")
old_described_state = described_state
@@ -913,24 +909,6 @@ public
return Digest::SHA1.hexdigest(id.to_s + AlaveteliConfiguration::incoming_email_secret)[0,8]
end
- # Called by find_by_incoming_email - and used to be called by separate
- # function for envelope from address, until we abandoned it.
- def InfoRequest.find_by_magic_email(id, hash)
- expected_hash = InfoRequest.hash_from_id(id)
- #print "expected: " + expected_hash + "\nhash: " + hash + "\n"
- if hash != expected_hash
- return nil
- else
- begin
- return self.find(id)
- rescue ActiveRecord::RecordNotFound
- # so error email is sent to admin, rather than the exception sending weird
- # error to the public body.
- return nil
- end
- end
- end
-
# Used to find when event last changed
def InfoRequest.last_event_time_clause(event_type=nil)
event_type_clause = ''
@@ -1081,25 +1059,6 @@ public
InfoRequest.update_all "allow_new_responses_from = 'nobody' where updated_at < (now() - interval '1 year') and allow_new_responses_from in ('anybody', 'authority_only') and url_title <> 'holding_pen'"
end
- # Returns a random FOI request
- def InfoRequest.random
- max_id = InfoRequest.connection.select_value('select max(id) as a from info_requests').to_i
- info_request = nil
- count = 0
- while info_request.nil?
- if count > 100
- return nil
- end
- id = rand(max_id) + 1
- begin
- count += 1
- info_request = find(id, :conditions => ["prominence = 'normal'"])
- rescue ActiveRecord::RecordNotFound
- end
- end
- return info_request
- end
-
def json_for_api(deep)
ret = {
:id => self.id,
diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb
index 469aabc4a..0967e3940 100644
--- a/app/models/info_request_event.rb
+++ b/app/models/info_request_event.rb
@@ -420,7 +420,7 @@ class InfoRequestEvent < ActiveRecord::Base
if deep
ret[:info_request] = self.info_request.json_for_api(false)
ret[:public_body] = self.info_request.public_body.json_for_api
- ret[:user] = self.info_request.user.json_for_api
+ ret[:user] = self.info_request.user_json_for_api
end
return ret
diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb
index dbe2cf1ca..aedfb9cad 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -23,6 +23,14 @@
# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class OutgoingMessage < ActiveRecord::Base
+ include Rails.application.routes.url_helpers
+ include LinkToHelper
+ self.default_url_options[:host] = AlaveteliConfiguration::domain
+ # https links in emails if forcing SSL
+ if AlaveteliConfiguration::force_ssl
+ self.default_url_options[:protocol] = "https"
+ end
+
strip_attributes!
belongs_to :info_request
@@ -80,15 +88,15 @@ class OutgoingMessage < ActiveRecord::Base
end
if self.what_doing == 'internal_review'
- "Please pass this on to the person who conducts Freedom of Information reviews." +
+ _("Please pass this on to the person who conducts Freedom of Information reviews.") +
"\n\n" +
- "I am writing to request an internal review of " +
- self.info_request.public_body.name +
- "'s handling of my FOI request " +
- "'" + self.info_request.title + "'." +
+ _("I am writing to request an internal review of {{public_body_name}}'s handling of my FOI request '{{info_request_title}}'.",
+ :public_body_name => self.info_request.public_body.name,
+ :info_request_title => self.info_request.title) +
"\n\n\n\n [ " + self.get_internal_review_insert_here_note + " ] \n\n\n\n" +
- "A full history of my FOI request and all correspondence is available on the Internet at this address:\n" +
- "http://" + AlaveteliConfiguration::domain + "/request/" + self.info_request.url_title
+ _("A full history of my FOI request and all correspondence is available on the Internet at this address: {{url}}",
+ :url => request_url(self.info_request)) +
+ "\n"
else
""
end
diff --git a/app/views/general/_stylesheet_includes.html.erb b/app/views/general/_stylesheet_includes.html.erb
index 5b6e12258..9dd1f357d 100644
--- a/app/views/general/_stylesheet_includes.html.erb
+++ b/app/views/general/_stylesheet_includes.html.erb
@@ -8,14 +8,9 @@
<!--[if LT IE 7]>
<style type="text/css">@import url("/stylesheets/ie6.css");</style>
<![endif]-->
- <!--[if LT IE 7]>
- <style type="text/css">@import url("/stylesheets/ie6-custom.css");</style>
- <![endif]-->
<!--[if LT IE 8]>
<style type="text/css">@import url("/stylesheets/ie7.css");</style>
<![endif]-->
- <!-- the following method for customising CSS is deprecated; see `doc/THEMES.md` for detail -->
- <%= stylesheet_link_tag 'custom', :title => "Main", :rel => "stylesheet" %>
<% if AlaveteliConfiguration::force_registration_on_new_request %>
<%= stylesheet_link_tag 'jquery.fancybox-1.3.4', :rel => "stylesheet" %>
<% end %>
diff --git a/app/views/general/custom_css.html.erb b/app/views/general/custom_css.html.erb
deleted file mode 100644
index 0def82ed0..000000000
--- a/app/views/general/custom_css.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-// this should be overridden in a local "theme" plugin
diff --git a/app/views/layouts/no_chrome.html.erb b/app/views/layouts/no_chrome.html.erb
index 120ba6f28..d7918cffc 100644
--- a/app/views/layouts/no_chrome.html.erb
+++ b/app/views/layouts/no_chrome.html.erb
@@ -12,19 +12,16 @@
<script type="text/javascript" src="/javascripts/jquery.js"></script>
- <%= stylesheet_link_tag 'main', :title => "Main", :rel => "stylesheet" %>
- <%= stylesheet_link_tag 'fonts', :rel => "stylesheet" %>
- <%= stylesheet_link_tag 'theme', :rel => "stylesheet" %>
- <!--[if LT IE 7]>
- <style type="text/css">@import url("/stylesheets/ie6.css");</style>
- <![endif]-->
- <!--[if LT IE 7]>
- <style type="text/css">@import url("/stylesheets/ie6-custom.css");</style>
+ <%= stylesheet_link_tag 'main', :title => "Main", :rel => "stylesheet" %>
+ <%= stylesheet_link_tag 'fonts', :rel => "stylesheet" %>
+ <%= stylesheet_link_tag 'theme', :rel => "stylesheet" %>
+ <!--[if LT IE 7]>
+ <style type="text/css">@import url("/stylesheets/ie6.css");</style>
<![endif]-->
<%= stylesheet_link_tag 'custom', :title => "Main", :rel => "stylesheet" %>
</head>
<body>
- <div class="entirebody">
+ <div class="entirebody">
<div id="content">
<% if flash[:notice] %>
<div id="notice"><%= flash[:notice] %></div>
@@ -39,4 +36,4 @@
</div>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/app/views/public_body/_search_ahead.html.erb b/app/views/public_body/_search_ahead.html.erb
index b1af2464d..3d1dc8f93 100644
--- a/app/views/public_body/_search_ahead.html.erb
+++ b/app/views/public_body/_search_ahead.html.erb
@@ -1,4 +1,4 @@
-<div>
+
<% if !@xapian_requests.nil? %>
<% if @xapian_requests.results.size > 0 %>
<h3><%= _('Top search results:') %></h3>
@@ -10,12 +10,11 @@
<% end %>
<div id="authority_search_ahead_results">
<% for result in @xapian_requests.results %>
- <%= render :partial => 'body_listing_single', :locals => { :public_body => result[:model] } %>
+ <%= render :partial => 'public_body/body_listing_single', :locals => { :public_body => result[:model] } %>
<% end %>
</div>
<%= will_paginate WillPaginate::Collection.new(@page, @per_page, @xapian_requests.matches_estimated), :params => {:controller=>"request", :action => "select_authority"} %>
<% end %>
-</div>
diff --git a/app/views/public_body/show.html.erb b/app/views/public_body/show.html.erb
index fa6243b47..47075a1f5 100644
--- a/app/views/public_body/show.html.erb
+++ b/app/views/public_body/show.html.erb
@@ -56,12 +56,7 @@
<div id="stepwise_make_request">
<% if @public_body.is_requestable? || @public_body.not_requestable_reason == 'bad_contact' %>
- <% if @public_body.eir_only? %>
- <%= _('Make a new <strong>Environmental Information</strong> request')%>
- <% else %>
- <%= _('Make a new <strong>Freedom of Information</strong> request to {{public_body}}', :public_body => h(@public_body.name))%>
- <% end %>
- &nbsp;<%= link_to _("Start"), new_request_to_body_url(:url_name => @public_body.url_name), :class => "link_button_green" %>
+ <%= link_to _("Make a request to this authority"), new_request_to_body_path(:url_name => @public_body.url_name), :class => "link_button_green" %>
<% elsif @public_body.has_notes? %>
<%= @public_body.notes_as_html.html_safe %>
<% elsif @public_body.not_requestable_reason == 'not_apply' %>
diff --git a/app/views/reports/new.html.erb b/app/views/reports/new.html.erb
new file mode 100644
index 000000000..7d558ab4e
--- /dev/null
+++ b/app/views/reports/new.html.erb
@@ -0,0 +1,26 @@
+<h1>Report request: <%= @info_request.title %></h1>
+
+<% if @info_request.attention_requested %>
+ <p><%= _("This request has already been reported for administrator attention") %></p>
+<% else %>
+ <p>
+ Reporting a request notifies the site administrators. They will respond as soon as possible.
+ </p>
+ <p>Why specifically do you consider this request unsuitable?</p>
+
+ <%= form_tag request_report_path(:request_id => @info_request.url_title) do %>
+ <p>
+ <label class="form_label" for="reason">Reason:</label>
+ <%= select_tag :reason, options_for_select(@info_request.report_reasons, @reason), :prompt => "Choose a reason" %>
+ </p>
+ <p>
+ <label class="form_label" for="message">Please tell us more:</label>
+ <%= text_area_tag :message, @message, :rows => 10, :cols => 60 %>
+ </p>
+
+ <div class="form_button">
+ <%= submit_tag _("Report request") %>
+ </div>
+
+ <% end %>
+<% end %>
diff --git a/app/views/request/_sidebar.html.erb b/app/views/request/_sidebar.html.erb
index 4bc8826fd..aba5c2fb3 100644
--- a/app/views/request/_sidebar.html.erb
+++ b/app/views/request/_sidebar.html.erb
@@ -30,7 +30,7 @@
<% else %>
<p><%= _('Requests for personal information and vexatious requests are not considered valid for FOI purposes (<a href="/help/about">read more</a>).') %></p>
<p><%= _('If you believe this request is not suitable, you can report it for attention by the site administrators') %></p>
- <%= button_to _("Report this request"), report_path(:url_title => @info_request.url_title), :class => "link_button_green" %>
+ <%= link_to _("Report this request"), new_request_report_path(:request_id => @info_request.url_title) %>
<% end %>
<% end %>
<h2><%= _("Act on what you've learnt") %></h2>
diff --git a/app/views/request/new_please_describe.html.erb b/app/views/request/new_please_describe.html.erb
index 5a67d01f9..8da4eb555 100644
--- a/app/views/request/new_please_describe.html.erb
+++ b/app/views/request/new_please_describe.html.erb
@@ -1,4 +1,4 @@
-<% @title = "First, did your other requests succeed?" %>
+<% @title = _("First, did your other requests succeed?") %>
<h1><%=@title%></h1>
diff --git a/app/views/request/select_authority.html.erb b/app/views/request/select_authority.html.erb
index c01e2776f..75c51fc57 100644
--- a/app/views/request/select_authority.html.erb
+++ b/app/views/request/select_authority.html.erb
@@ -42,26 +42,9 @@
<%= submit_tag _('Search') %>
</div>
<% end %>
- <div id="typeahead_response">
- <% if !@xapian_requests.nil? %>
- <% if @xapian_requests.results.size > 0 %>
- <h3><%= _('Top search results:') %></h3>
- <p>
- <%= _('Select one to see more information about the authority.')%>
- </p>
- <% else %>
- <h3><%= _('No results found.') %></h3>
- <% end %>
- <div id="authority_search_ahead_results">
- <% for result in @xapian_requests.results %>
- <%= render :partial => 'public_body/body_listing_single', :locals => { :public_body => result[:model] } %>
- <% end %>
- </div>
-
- <% end %>
-
-
+ <div id="typeahead_response">
+ <%= render :partial => 'public_body/search_ahead' %>
</div>
</div>
diff --git a/config/general.yml-example b/config/general.yml-example
index 17e1aa552..0753af46b 100644
--- a/config/general.yml-example
+++ b/config/general.yml-example
@@ -187,3 +187,8 @@ MTA_LOG_PATH: '/var/log/exim4/exim-mainlog-*'
# Whether we are using "exim" or "postfix" for our MTA
MTA_LOG_TYPE: "exim"
+
+# URL where people can donate to the organisation running the site. If set,
+# this will be included in the message people see when their request is
+# successful.
+DONATION_URL: "http://www.mysociety.org/donate/"
diff --git a/config/packages b/config/packages
index fc67cda6b..f4d0a674c 100644
--- a/config/packages
+++ b/config/packages
@@ -20,7 +20,6 @@ gnuplot-nox
php5-cli
sharutils
unzip
-wdg-html-validator
mutt
tnef (>= 1.4.5)
gettext
diff --git a/config/packages_development b/config/packages_development
new file mode 100644
index 000000000..14ca815a2
--- /dev/null
+++ b/config/packages_development
@@ -0,0 +1,9 @@
+# This is a list of packages needed on a fresh Ubuntu installation for
+# development.
+#
+# It assumes you're using RVM or a similar Ruby manager and have already
+# run `bundle install`.
+#
+# To install, paste this list after `sudo apt-get install` and run.
+
+postgresql sharutils pdftk elinks php5-cli tnef python-yaml
diff --git a/config/routes.rb b/config/routes.rb
index 1895543d7..062973e37 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -14,7 +14,6 @@ Alaveteli::Application.routes.draw do
#### General contoller
match '/' => 'general#frontpage', :as => :frontpage
match '/blog' => 'general#blog', :as => :blog
- match '/stylesheets/custom.css' => 'general#custom_css', :as => :custom_css
match '/search' => 'general#search_redirect', :as => :search_redirect
match '/search/all' => 'general#search_redirect', :as => :search_redirect
# XXX combined is the search query, and then if sorted a "/newest" at the end.
@@ -24,8 +23,6 @@ Alaveteli::Application.routes.draw do
match '/search/*combined/all' => 'general#search', :as => :search_general, :view => 'all'
match '/search(/*combined)' => 'general#search', :as => :search_general
match '/advancedsearch' => 'general#search_redirect', :as => :advanced_search, :advanced => true
-
- match '/random' => 'general#random_request', :as => :random_request
#####
##### Request controller
@@ -59,15 +56,12 @@ Alaveteli::Application.routes.draw do
match '/upload/request/:url_title' => 'request#upload_response', :as => :upload_response
match '/request/:url_title/download' => 'request#download_entire_request', :as => :download_entire_request
-
- # It would be nice to add :conditions => { :method => :post } to this next one,
- # because it ought not really to be available as a GET request since it changes
- # the server state. Unfortunately this doesn’t play well with the PostRedirect
- # mechanism, which assumes all post-login actions are available via GET, so we
- # refrain.
- match '/request/:url_title/report' => 'request#report_request', :as => :report
####
+ resources :request, :only => [] do
+ resource :report, :only => [:new, :create]
+ end
+
#### User controller
# Use /profile for things to do with the currently signed in user.
# Use /user/XXXX for things that anyone can see about that user.
diff --git a/doc/THEMES.md b/doc/THEMES.md
index 8c4b927da..bae7d7665 100644
--- a/doc/THEMES.md
+++ b/doc/THEMES.md
@@ -36,15 +36,15 @@ places:
This document is about what you can do in a theme.
-By default, the sample theme ("alavetelitheme") has already been
-installed. See the setting `THEME_URLS` in `general.yml` for an
+By default, the sample theme ("alavetelitheme") has already been
+installed. See the setting `THEME_URLS` in `general.yml` for an
explanation.
You can also install the sample theme by hand, by running:
- bundle exec rails plugin install git://github.com/mysociety/alavetelitheme.git -r rails-3
+ bundle exec rails plugin install git://github.com/mysociety/alavetelitheme.git
-The sample theme contains examples for nearly everything you might
+The sample theme contains examples for nearly everything you might
want to customise. You should probably make a copy, rename it, and
use that as the basis for your own theme.
@@ -61,7 +61,7 @@ changing much in the core theme. The ideal would be if you are able
to rebrand the site by only changing the CSS. You will also need to
add custom help pages, as described below.
-# Branding the site
+# Branding the site
The core templates that comprise the layout and user interface of an
Alaveteli site live in `app/views/`. They are use Rails' ERB syntax.
@@ -158,7 +158,7 @@ unused).
`alavetelitheme/lib/config/custom-routes.rb` allows you to extend the base routes in
Alaveteli. The example in `alavetelitheme` adds an extra help page.
You can also use this to override the behaviour of specific pages if
-necessary.
+necessary.
# Adding or overriding models and controllers
diff --git a/lib/configuration.rb b/lib/configuration.rb
index 88890856b..03c4ac616 100644
--- a/lib/configuration.rb
+++ b/lib/configuration.rb
@@ -28,6 +28,7 @@ module AlaveteliConfiguration
:DEFAULT_LOCALE => '',
:DISABLE_EMERGENCY_USER => false,
:DOMAIN => 'localhost:3000',
+ :DONATION_URL => '',
:EXCEPTION_NOTIFICATIONS_FROM => '',
:EXCEPTION_NOTIFICATIONS_TO => '',
:FORCE_REGISTRATION_ON_NEW_REQUEST => false,
diff --git a/lib/tasks/themes.rake b/lib/tasks/themes.rake
index cbd3d123e..a8d16f108 100644
--- a/lib/tasks/themes.rake
+++ b/lib/tasks/themes.rake
@@ -9,15 +9,17 @@ namespace :themes do
File.join(plugin_dir, theme_name)
end
+ def checkout(commitish)
+ puts "Checking out #{commitish}" if verbose
+ system "git checkout #{commitish}"
+ end
+
def checkout_tag(version)
- checkout_command = "git checkout #{usage_tag(version)}"
- success = system(checkout_command)
- puts "Using tag #{usage_tag(version)}" if verbose && success
- success
+ checkout usage_tag(version)
end
def checkout_remote_branch(branch)
- system("git checkout origin/#{branch}")
+ checkout "origin/#{branch}"
end
def usage_tag(version)
diff --git a/lib/tasks/translation.rake b/lib/tasks/translation.rake
index 351faef2c..6458d9268 100644
--- a/lib/tasks/translation.rake
+++ b/lib/tasks/translation.rake
@@ -142,13 +142,11 @@ namespace :translation do
output_file)
# track mailer
- xapian_object = InfoRequest.full_search([InfoRequestEvent],
- track_thing.track_query,
- 'described_at',
- true,
- nil,
- 100,
- 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], track_thing.track_query,
+ :sort_by_prefix => 'described_at',
+ :sort_by_ascending => true,
+ :collapse_by_prefix => nil,
+ :limit => 100)
event_digest_email = TrackMailer.event_digest(info_request.user,
[[track_thing,
xapian_object.results,
diff --git a/public/stylesheets/ie6-custom.css b/public/stylesheets/ie6-custom.css
deleted file mode 100644
index 64d632e72..000000000
--- a/public/stylesheets/ie6-custom.css
+++ /dev/null
@@ -1 +0,0 @@
-/* drop your local IE-specific CSS overrides in here */
diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css
index 2823f3978..6f6d7b365 100644
--- a/public/stylesheets/main.css
+++ b/public/stylesheets/main.css
@@ -183,16 +183,11 @@ margin:18px 0 36px;
}
#stepwise_make_request {
-background-color:#BBB;
-border:1px solid #222;
-border-radius:5px;
--moz-border-radius:5px;
color:#222;
font-size:1.1em;
text-align:left;
width:412px;
margin:0 14em 40px 0;
-padding:10px 12px;
}
#stepwise_make_request_view_email {
diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb
index 4a1c8b134..bce12248b 100644
--- a/spec/controllers/general_controller_spec.rb
+++ b/spec/controllers/general_controller_spec.rb
@@ -348,4 +348,3 @@ describe GeneralController, 'when using xapian search' do
end
end
-
diff --git a/spec/controllers/reports_controller_spec.rb b/spec/controllers/reports_controller_spec.rb
new file mode 100644
index 000000000..fa8c72eaa
--- /dev/null
+++ b/spec/controllers/reports_controller_spec.rb
@@ -0,0 +1,104 @@
+require 'spec_helper'
+
+describe ReportsController, "when reporting a request when not logged in" do
+ it "should only allow logged-in users to report requests" do
+ post :create, :request_id => info_requests(:badger_request).url_title, :reason => "my reason"
+
+ flash[:notice].should =~ /You need to be logged in/
+ response.should redirect_to show_request_path(:url_title => info_requests(:badger_request).url_title)
+ end
+end
+
+describe ReportsController, "when reporting a request (logged in)" do
+ render_views
+
+ before do
+ @user = users(:robin_user)
+ session[:user_id] = @user.id
+ end
+
+ it "should 404 for non-existent requests" do
+ lambda {
+ post :create, :request_id => "hjksfdhjk_louytu_qqxxx"
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it "should mark a request as having been reported" do
+ ir = info_requests(:badger_request)
+ title = ir.url_title
+ ir.attention_requested.should == false
+
+ post :create, :request_id => title, :reason => "my reason"
+ response.should redirect_to show_request_path(:url_title => title)
+
+ ir.reload
+ ir.attention_requested.should == true
+ ir.described_state.should == "attention_requested"
+ end
+
+ it "should pass on the reason and message" do
+ info_request = mock_model(InfoRequest, :url_title => "foo", :attention_requested= => nil, :save! => nil)
+ InfoRequest.should_receive(:find_by_url_title!).with("foo").and_return(info_request)
+ info_request.should_receive(:report!).with("Not valid request", "It's just not", @user)
+ post :create, :request_id => "foo", :reason => "Not valid request", :message => "It's just not"
+ end
+
+ it "should not allow a request to be reported twice" do
+ title = info_requests(:badger_request).url_title
+
+ post :create, :request_id => title, :reason => "my reason"
+ response.should redirect_to show_request_url(:url_title => title)
+
+ post :create, :request_id => title, :reason => "my reason"
+ response.should redirect_to show_request_url(:url_title => title)
+ flash[:notice].should =~ /has already been reported/
+ end
+
+ it "should send an email from the reporter to admins" do
+ ir = info_requests(:badger_request)
+ title = ir.url_title
+ post :create, :request_id => title, :reason => "my reason"
+ deliveries = ActionMailer::Base.deliveries
+ deliveries.size.should == 1
+ mail = deliveries[0]
+ mail.subject.should =~ /attention_requested/
+ mail.from.should include(@user.email)
+ mail.body.should include(@user.name)
+ end
+
+ it "should force the user to pick a reason" do
+ info_request = mock_model(InfoRequest, :report! => nil, :url_title => "foo",
+ :report_reasons => ["Not FOIish enough"])
+ InfoRequest.should_receive(:find_by_url_title!).with("foo").and_return(info_request)
+
+ post :create, :request_id => "foo", :reason => ""
+ response.should render_template("new")
+ flash[:error].should == "Please choose a reason"
+ end
+end
+
+describe ReportsController, "#new_report_request" do
+ let(:info_request) { mock_model(InfoRequest, :url_title => "foo") }
+ before :each do
+ InfoRequest.should_receive(:find_by_url_title!).with("foo").and_return(info_request)
+ end
+
+ context "not logged in" do
+ it "should require the user to be logged in" do
+ get :new, :request_id => "foo"
+ response.should_not render_template("new")
+ end
+ end
+
+ context "logged in" do
+ before :each do
+ session[:user_id] = users(:bob_smith_user).id
+ end
+ it "should show the form" do
+ get :new, :request_id => "foo"
+ response.should render_template("new")
+ end
+ end
+end
+
+
diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index 83e2b1767..a4e6fcffc 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -93,8 +93,10 @@ describe RequestController, "when listing recent requests" do
:results => (1..25).to_a.map { |m| { :model => m } },
:matches_estimated => 1000000)
- InfoRequest.should_receive(:full_search).
- with([InfoRequestEvent]," (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)", "created_at", anything, anything, anything, anything).
+ ActsAsXapian::Search.should_receive(:new).
+ with([InfoRequestEvent]," (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)",
+ :sort_by_prefix => "created_at", :offset => 0, :limit => 25, :sort_by_ascending => true,
+ :collapse_by_prefix => "request_collapse").
and_return(xap_results)
get :list, :view => 'all'
assigns[:list_results].size.should == 25
@@ -134,7 +136,7 @@ describe RequestController, "when changing things that appear on the request pag
it "should purge the downstream cache when a followup is made" do
session[:user_id] = users(:bob_smith_user).id
ir = info_requests(:fancy_dog_request)
- post :show_response, :outgoing_message => { :body => "What a useless response! You suck.", :what_doing => 'normal_sort' }, :id => ir.id, :incoming_message_id => incoming_messages(:useless_incoming_message), :submitted_followup => 1
+ post :show_response, :outgoing_message => { :body => "What a useless response! You suck.", :what_doing => 'normal_sort' }, :id => ir.id, :submitted_followup => 1
PurgeRequest.all().first.model_id.should == ir.id
end
it "should purge the downstream cache when the request is categorised" do
@@ -239,6 +241,36 @@ describe RequestController, "when showing one request" do
end
end
+ context "when the request has not yet been reported" do
+ it "should allow the user to report" do
+ title = info_requests(:badger_request).url_title
+ get :show, :url_title => title
+ response.should_not contain("This request has been reported")
+ response.should contain("Offensive?")
+ end
+ end
+
+ context "when the request has been reported for admin attention" do
+ before :each do
+ info_requests(:fancy_dog_request).report!("", "", nil)
+ end
+ it "should inform the user" do
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
+ response.should contain("This request has been reported")
+ response.should_not contain("Offensive?")
+ end
+
+ context "and then deemed okay and left to complete" do
+ before :each do
+ info_requests(:fancy_dog_request).set_described_state("successful")
+ end
+ it "should let the user know that the administrators have not hidden this request" do
+ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog'
+ response.body.should =~ (/the site administrators.*have not hidden it/)
+ end
+ end
+ end
+
describe 'when the request is being viewed by an admin' do
describe 'if the request is awaiting description' do
@@ -1605,7 +1637,7 @@ describe RequestController, "when classifying an information request" do
end
end
- describe 'when redirecting after a successful status update by the request owner' do
+ describe 'after a successful status update by the request owner' do
before do
@request_owner = users(:bob_smith_user)
@@ -1632,87 +1664,161 @@ describe RequestController, "when classifying an information request" do
response.should redirect_to("http://test.host/#{redirect_path}")
end
- it 'should redirect to the "request url" with a message in the right tense when status is updated to "waiting response" and the response is not overdue' do
- @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date+1)
- @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40)
+ context 'when status is updated to "waiting_response"' do
- expect_redirect("waiting_response", "request/#{@dog_request.url_title}")
- flash[:notice].should match(/should get a response/)
- end
+ it 'should redirect to the "request url" with a message in the right tense when
+ the response is not overdue' do
+ @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date+1)
+ @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40)
- it 'should redirect to the "request url" with a message in the right tense when status is updated to "waiting response" and the response is overdue' do
- @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-1)
- @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40)
- expect_redirect('waiting_response', request_url)
- flash[:notice].should match(/should have got a response/)
- end
+ expect_redirect("waiting_response", "request/#{@dog_request.url_title}")
+ flash[:notice].should match(/should get a response/)
+ end
- it 'should redirect to the "request url" with a message in the right tense when status is updated to "waiting response" and the response is overdue' do
- @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-2)
- @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date-1)
- expect_redirect('waiting_response', unhappy_url)
- flash[:notice].should match(/is long overdue/)
- flash[:notice].should match(/by more than 40 working days/)
- flash[:notice].should match(/within 20 working days/)
- end
+ it 'should redirect to the "request url" with a message in the right tense when
+ the response is overdue' do
+ @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-1)
+ @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date+40)
+ expect_redirect('waiting_response', request_url)
+ flash[:notice].should match(/should have got a response/)
+ end
- it 'should redirect to the "request url" when status is updated to "not held"' do
- expect_redirect('not_held', request_url)
+ it 'should redirect to the "request url" with a message in the right tense when
+ the response is overdue' do
+ @dog_request.stub!(:date_response_required_by).and_return(Time.now.to_date-2)
+ @dog_request.stub!(:date_very_overdue_after).and_return(Time.now.to_date-1)
+ expect_redirect('waiting_response', unhappy_url)
+ flash[:notice].should match(/is long overdue/)
+ flash[:notice].should match(/by more than 40 working days/)
+ flash[:notice].should match(/within 20 working days/)
+ end
end
- it 'should redirect to the "request url" when status is updated to "successful"' do
- expect_redirect('successful', request_url)
- end
+ context 'when status is updated to "not held"' do
+
+ it 'should redirect to the "request url"' do
+ expect_redirect('not_held', request_url)
+ end
- it 'should redirect to the "unhappy url" when status is updated to "rejected"' do
- expect_redirect('rejected', "help/unhappy/#{@dog_request.url_title}")
end
- it 'should redirect to the "unhappy url" when status is updated to "partially successful"' do
- expect_redirect('partially_successful', "help/unhappy/#{@dog_request.url_title}")
+ context 'when status is updated to "successful"' do
+
+ it 'should redirect to the "request url"' do
+ expect_redirect('successful', request_url)
+ end
+
+ it 'should show a message including the donation url if there is one' do
+ AlaveteliConfiguration.stub!(:donation_url).and_return('http://donations.example.com')
+ post_status('successful')
+ flash[:notice].should match('make a donation')
+ flash[:notice].should match('http://donations.example.com')
+ end
+
+ it 'should show a message without reference to donations if there is no
+ donation url' do
+ AlaveteliConfiguration.stub!(:donation_url).and_return('')
+ post_status('successful')
+ flash[:notice].should_not match('make a donation')
+ end
+
end
- it 'should redirect to the "response url" when status is updated to "waiting clarification" and there is a last response' do
- incoming_message = mock_model(IncomingMessage)
- @dog_request.stub!(:get_last_response).and_return(incoming_message)
- expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response/#{incoming_message.id}")
+ context 'when status is updated to "waiting clarification"' do
+
+ it 'should redirect to the "response url" when there is a last response' do
+ incoming_message = mock_model(IncomingMessage)
+ @dog_request.stub!(:get_last_response).and_return(incoming_message)
+ expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response/#{incoming_message.id}")
+ end
+
+ it 'should redirect to the "response no followup url" when there are no events
+ needing description' do
+ @dog_request.stub!(:get_last_response).and_return(nil)
+ expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response")
+ end
+
end
- it 'should redirect to the "response no followup url" when status is updated to "waiting clarification" and there are no events needing description' do
- @dog_request.stub!(:get_last_response).and_return(nil)
- expect_redirect('waiting_clarification', "request/#{@dog_request.id}/response")
+ context 'when status is updated to "rejected"' do
+
+ it 'should redirect to the "unhappy url"' do
+ expect_redirect('rejected', "help/unhappy/#{@dog_request.url_title}")
+ end
+
end
- it 'should redirect to the "respond to last url" when status is updated to "gone postal"' do
- expect_redirect('gone_postal', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}?gone_postal=1")
+ context 'when status is updated to "partially successful"' do
+
+ it 'should redirect to the "unhappy url"' do
+ expect_redirect('partially_successful', "help/unhappy/#{@dog_request.url_title}")
+ end
+
+ it 'should show a message including the donation url if there is one' do
+ AlaveteliConfiguration.stub!(:donation_url).and_return('http://donations.example.com')
+ post_status('successful')
+ flash[:notice].should match('make a donation')
+ flash[:notice].should match('http://donations.example.com')
+ end
+
+ it 'should show a message without reference to donations if there is no
+ donation url' do
+ AlaveteliConfiguration.stub!(:donation_url).and_return('')
+ post_status('successful')
+ flash[:notice].should_not match('make a donation')
+ end
+
end
- it 'should redirect to the "request url" when status is updated to "internal review"' do
- expect_redirect('internal_review', request_url)
+ context 'when status is updated to "gone postal"' do
+
+ it 'should redirect to the "respond to last url"' do
+ expect_redirect('gone_postal', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}?gone_postal=1")
+ end
+
end
- it 'should redirect to the "request url" when status is updated to "requires admin"' do
- post :describe_state, :incoming_message => {
- :described_state => 'requires_admin',
- :message => "A message" },
- :id => @dog_request.id,
- :last_info_request_event_id => @dog_request.last_event_id_needing_description
- response.should redirect_to show_request_url(:url_title => @dog_request.url_title)
+ context 'when status updated to "internal review"' do
+
+ it 'should redirect to the "request url"' do
+ expect_redirect('internal_review', request_url)
+ end
+
end
- it 'should redirect to the "request url" when status is updated to "error message"' do
- post :describe_state, :incoming_message => {
- :described_state => 'error_message',
- :message => "A message" },
- :id => @dog_request.id,
- :last_info_request_event_id => @dog_request.last_event_id_needing_description
- response.should redirect_to show_request_url(:url_title => @dog_request.url_title)
+ context 'when status is updated to "requires admin"' do
+
+ it 'should redirect to the "request url"' do
+ post :describe_state, :incoming_message => {
+ :described_state => 'requires_admin',
+ :message => "A message" },
+ :id => @dog_request.id,
+ :last_info_request_event_id => @dog_request.last_event_id_needing_description
+ response.should redirect_to show_request_url(:url_title => @dog_request.url_title)
+ end
+
end
- it 'should redirect to the "respond to last url url" when status is updated to "user_withdrawn"' do
- expect_redirect('user_withdrawn', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}")
+ context 'when status is updated to "error message"' do
+
+ it 'should redirect to the "request url"' do
+ post :describe_state, :incoming_message => {
+ :described_state => 'error_message',
+ :message => "A message" },
+ :id => @dog_request.id,
+ :last_info_request_event_id => @dog_request.last_event_id_needing_description
+ response.should redirect_to show_request_url(:url_title => @dog_request.url_title)
+ end
+
end
+ context 'when status is updated to "user_withdrawn"' do
+
+ it 'should redirect to the "respond to last url url" ' do
+ expect_redirect('user_withdrawn', "request/#{@dog_request.id}/response/#{@dog_request.get_last_response.id}")
+ end
+
+ end
end
end
@@ -2342,91 +2448,6 @@ describe RequestController, "when showing similar requests" do
end
-
-describe RequestController, "when reporting a request when not logged in" do
- it "should only allow logged-in users to report requests" do
- get :report_request, :url_title => info_requests(:badger_request).url_title
- post_redirect = PostRedirect.get_last_post_redirect
- response.should redirect_to(:controller => 'user', :action => 'signin', :token => post_redirect.token)
- end
-end
-
-describe RequestController, "when reporting a request (logged in)" do
- render_views
-
- before do
- @user = users(:robin_user)
- session[:user_id] = @user.id
- end
-
- it "should 404 for non-existent requests" do
- lambda {
- post :report_request, :url_title => "hjksfdhjk_louytu_qqxxx"
- }.should raise_error(ActiveRecord::RecordNotFound)
- end
-
- it "should mark a request as having been reported" do
- ir = info_requests(:badger_request)
- title = ir.url_title
- get :show, :url_title => title
- assigns[:info_request].attention_requested.should == false
-
- post :report_request, :url_title => title
- response.should redirect_to(:action => :show, :url_title => title)
-
- get :show, :url_title => title
- response.should be_success
- assigns[:info_request].attention_requested.should == true
- assigns[:info_request].described_state.should == "attention_requested"
- end
-
- it "should not allow a request to be reported twice" do
- title = info_requests(:badger_request).url_title
-
- post :report_request, :url_title => title
- response.should redirect_to(:action => :show, :url_title => title)
- get :show, :url_title => title
- response.should be_success
- response.body.should include("has been reported")
-
- post :report_request, :url_title => title
- response.should redirect_to(:action => :show, :url_title => title)
- get :show, :url_title => title
- response.should be_success
- response.body.should include("has already been reported")
- end
-
- it "should let users know a request has been reported" do
- title = info_requests(:badger_request).url_title
- get :show, :url_title => title
- response.body.should include("Offensive?")
-
- post :report_request, :url_title => title
- response.should redirect_to(:action => :show, :url_title => title)
-
- get :show, :url_title => title
- response.body.should_not include("Offensive?")
- response.body.should include("This request has been reported")
-
- info_requests(:badger_request).set_described_state("successful")
- get :show, :url_title => title
- response.body.should_not include("This request has been reported")
- response.body.should =~ (/the site administrators.*have not hidden it/)
- end
-
- it "should send an email from the reporter to admins" do
- ir = info_requests(:badger_request)
- title = ir.url_title
- post :report_request, :url_title => title
- deliveries = ActionMailer::Base.deliveries
- deliveries.size.should == 1
- mail = deliveries[0]
- mail.subject.should =~ /attention_requested/
- mail.from.should include(@user.email)
- mail.body.should include(@user.name)
- end
-end
-
describe RequestController, "when caching fragments" do
it "should not fail with long filenames" do
long_name = "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah.txt"
@@ -2454,4 +2475,3 @@ describe RequestController, "when caching fragments" do
end
-
diff --git a/spec/mailers/outgoing_mailer_spec.rb b/spec/mailers/outgoing_mailer_spec.rb
index 5d1ea2dfb..a11d56dd3 100644
--- a/spec/mailers/outgoing_mailer_spec.rb
+++ b/spec/mailers/outgoing_mailer_spec.rb
@@ -1,73 +1,66 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
-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
- before(:each) do
- load_raw_emails_data
+describe OutgoingMailer, " when working out follow up names and addresses" do
+
+ before do
+ @info_request = mock_model(InfoRequest,
+ :recipient_name_and_email => 'test <test@example.com>',
+ :recipient_email => 'test@example.com')
+ @info_request.stub_chain(:public_body, :name).and_return("Test Authority")
+ @incoming_message = mock_model(IncomingMessage,
+ :from_email => 'specific@example.com',
+ :safe_mail_from => 'Specific Person')
end
- it "should parse them right" do
- ir = info_requests(:fancy_dog_request)
- im = ir.incoming_messages[0]
-
- # check the basic entry in the fixture is fine
- OutgoingMailer.name_and_email_for_followup(ir, im).should == "FOI Person <foiperson@localhost>"
- OutgoingMailer.name_for_followup(ir, im).should == "FOI Person"
- OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost"
+ def expect_address(info_request, incoming_message, expected_result)
+ mail = create_message_from(from_line)
+ name = MailHandler.get_from_name(mail)
+ email = MailHandler.get_from_address(mail)
+ address = MailHandler.address_from_name_and_email(name, email).to_s
+ [name, email, address].should == expected_result
end
- it "should work when there is only an email address" do
- ir = info_requests(:fancy_dog_request)
- im = ir.incoming_messages[0]
+ describe 'if there is no incoming message being replied to' do
- im.raw_email.data = im.raw_email.data.sub("\"FOI Person\" <foiperson@localhost>", "foiperson@localhost")
- im.parse_raw_email! true
+ it 'should return the name and email address of the public body' do
+ OutgoingMailer.name_and_email_for_followup(@info_request, nil).should == 'test <test@example.com>'
+ OutgoingMailer.name_for_followup(@info_request, nil).should == 'Test Authority'
+ OutgoingMailer.email_for_followup(@info_request, nil).should == 'test@example.com'
+ end
- # check the basic entry in the fixture is fine
- OutgoingMailer.name_and_email_for_followup(ir, im).should == "foiperson@localhost"
- OutgoingMailer.name_for_followup(ir, im).should == "Geraldine Quango"
- OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost"
end
- it "should quote funny characters" do
- ir = info_requests(:fancy_dog_request)
- im = ir.incoming_messages[0]
+ describe 'if the incoming message being replied to is not valid to reply to' do
- im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI [ Person")
- im.parse_raw_email! true
+ before do
+ @incoming_message.stub!(:valid_to_reply_to?).and_return(false)
+ end
- # check the basic entry in the fixture is fine
- OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI [ Person\" <foiperson@localhost>"
- OutgoingMailer.name_for_followup(ir, im).should == "FOI [ Person"
- OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost"
+ it 'should return the safe name and email address of the public body' do
+ OutgoingMailer.name_and_email_for_followup(@info_request, @incoming_message).should == 'test <test@example.com>'
+ OutgoingMailer.name_for_followup(@info_request, @incoming_message).should == 'Test Authority'
+ OutgoingMailer.email_for_followup(@info_request, @incoming_message).should == 'test@example.com'
+ end
end
- it "should quote quotes" do
- ir = info_requests(:fancy_dog_request)
- im = ir.incoming_messages[0]
+ describe 'if the incoming message is valid to reply to' do
- im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI \\\" Person")
- im.parse_raw_email! true
+ before do
+ @incoming_message.stub!(:valid_to_reply_to?).and_return(true)
+ end
- # check the basic entry in the fixture is fine
- OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI \\\" Person\" <foiperson@localhost>"
- OutgoingMailer.name_for_followup(ir, im).should == "FOI \" Person"
- OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost"
- end
+ it 'should return the name and email address from the incoming message' do
+ OutgoingMailer.name_and_email_for_followup(@info_request, @incoming_message).should == 'Specific Person <specific@example.com>'
+ OutgoingMailer.name_for_followup(@info_request, @incoming_message).should == 'Specific Person'
+ OutgoingMailer.email_for_followup(@info_request, @incoming_message).should == 'specific@example.com'
+ end
- it "should quote @ signs" do
- ir = info_requests(:fancy_dog_request)
- im = ir.incoming_messages[0]
+ it 'should return the name of the public body if the incoming message does not have
+ a safe name' do
+ @incoming_message.stub!(:safe_mail_from).and_return(nil)
+ OutgoingMailer.name_for_followup(@info_request, @incoming_message).should == 'Test Authority'
+ end
- 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>"
- OutgoingMailer.name_for_followup(ir, im).should == "FOI @ Person"
- OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost"
end
end
@@ -79,21 +72,21 @@ describe OutgoingMailer, "when working out follow up subjects" do
end
it "should prefix the title with 'Freedom of Information request -' for initial requests" do
- ir = info_requests(:fancy_dog_request)
+ ir = info_requests(:fancy_dog_request)
im = ir.incoming_messages[0]
ir.email_subject_request.should == "Freedom of Information request - Why do you have & such a fancy dog?"
end
it "should use 'Re:' and inital request subject for followups which aren't replies to particular messages" do
- ir = info_requests(:fancy_dog_request)
+ ir = info_requests(:fancy_dog_request)
om = outgoing_messages(:useless_outgoing_message)
OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?"
end
it "should prefix with Re: the subject of the message being replied to" do
- ir = info_requests(:fancy_dog_request)
+ ir = info_requests(:fancy_dog_request)
im = ir.incoming_messages[0]
om = outgoing_messages(:useless_outgoing_message)
om.incoming_message_followup = im
@@ -102,7 +95,7 @@ describe OutgoingMailer, "when working out follow up subjects" do
end
it "should not add Re: prefix if there already is such a prefix" do
- ir = info_requests(:fancy_dog_request)
+ ir = info_requests(:fancy_dog_request)
im = ir.incoming_messages[0]
om = outgoing_messages(:useless_outgoing_message)
om.incoming_message_followup = im
@@ -112,19 +105,19 @@ describe OutgoingMailer, "when working out follow up subjects" do
end
it "should not add Re: prefix if there already is a lower case re: prefix" do
- ir = info_requests(:fancy_dog_request)
+ ir = info_requests(:fancy_dog_request)
im = ir.incoming_messages[0]
om = outgoing_messages(:useless_outgoing_message)
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
it "should use 'Re:' and initial request subject when replying to failed delivery notifications" do
- ir = info_requests(:fancy_dog_request)
+ ir = info_requests(:fancy_dog_request)
im = ir.incoming_messages[0]
om = outgoing_messages(:useless_outgoing_message)
om.incoming_message_followup = im
diff --git a/spec/mailers/track_mailer_spec.rb b/spec/mailers/track_mailer_spec.rb
index a3b849980..509d08331 100644
--- a/spec/mailers/track_mailer_spec.rb
+++ b/spec/mailers/track_mailer_spec.rb
@@ -69,11 +69,15 @@ describe TrackMailer do
@xapian_search = mock('xapian search', :results => [])
@found_event = mock_model(InfoRequestEvent, :described_at => @track_thing.created_at + 1.day)
@search_result = {:model => @found_event}
- InfoRequest.stub!(:full_search).and_return(@xapian_search)
+ ActsAsXapian::Search.stub!(:new).and_return(@xapian_search)
end
it 'should ask for the events returned by the tracking query' do
- InfoRequest.should_receive(:full_search).with([InfoRequestEvent], 'test query', 'described_at', true, nil, 100, 1).and_return(@xapian_search)
+ ActsAsXapian::Search.should_receive(:new).with([InfoRequestEvent], 'test query',
+ :sort_by_prefix => 'described_at',
+ :sort_by_ascending => true,
+ :collapse_by_prefix => nil,
+ :limit => 100).and_return(@xapian_search)
TrackMailer.alert_tracks
end
diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb
index 9b87f909e..f9ca44657 100644
--- a/spec/models/info_request_spec.rb
+++ b/spec/models/info_request_spec.rb
@@ -564,6 +564,26 @@ describe InfoRequest do
end
end
+ describe 'when generating json for the api' do
+
+ before do
+ @user = mock_model(User, :json_for_api => { :id => 20,
+ :url_name => 'alaveteli_user',
+ :name => 'Alaveteli User',
+ :ban_text => '',
+ :about_me => 'Hi' })
+ end
+
+ it 'should return full user info for an internal request' do
+ @info_request = InfoRequest.new(:user => @user)
+ @info_request.user_json_for_api.should == { :id => 20,
+ :url_name => 'alaveteli_user',
+ :name => 'Alaveteli User',
+ :ban_text => '',
+ :about_me => 'Hi' }
+ end
+ end
+
describe 'when working out a subject for a followup emails' do
it "should not be confused by an nil subject in the incoming message" do
@@ -575,6 +595,15 @@ describe InfoRequest do
subject.should match(/^Re: Freedom of Information request.*fancy dog/)
end
- end
+ it "should return a hash with the user's name for an external request" do
+ @info_request = InfoRequest.new(:external_url => 'http://www.example.com',
+ :external_user_name => 'External User')
+ @info_request.user_json_for_api.should == {:name => 'External User'}
+ end
+ it 'should return "Anonymous user" for an anonymous external user' do
+ @info_request = InfoRequest.new(:external_url => 'http://www.example.com')
+ @info_request.user_json_for_api.should == {:name => 'Anonymous user'}
+ end
+ end
end
diff --git a/spec/models/outgoing_message_spec.rb b/spec/models/outgoing_message_spec.rb
index 51bb6fdf5..60164fb31 100644
--- a/spec/models/outgoing_message_spec.rb
+++ b/spec/models/outgoing_message_spec.rb
@@ -16,7 +16,7 @@ describe OutgoingMessage, " when making an outgoing message" do
it "should not index the email addresses" do
# also used for track emails
@outgoing_message.get_text_for_indexing.should_not include("foo@bar.com")
- end
+ end
it "should not display email addresses on page" do
@outgoing_message.get_body_for_html_display.should_not include("foo@bar.com")
@@ -33,6 +33,23 @@ describe OutgoingMessage, " when making an outgoing message" do
it "should work out a salutation" do
@om.get_salutation.should == "Dear Geraldine Quango,"
end
+
+ it 'should produce the expected text for an internal review request' do
+ public_body = mock_model(PublicBody, :name => 'A test public body')
+ info_request = mock_model(InfoRequest, :public_body => public_body,
+ :url_title => 'a_test_title',
+ :title => 'A test title',
+ :apply_censor_rules_to_text! => nil)
+ outgoing_message = OutgoingMessage.new({
+ :status => 'ready',
+ :message_type => 'followup',
+ :what_doing => 'internal_review',
+ :info_request => info_request
+ })
+ expected_text = "I am writing to request an internal review of A test public body's handling of my FOI request 'A test title'."
+ outgoing_message.body.should include(expected_text)
+ end
+
end
diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb
index 8c99d550f..c40334142 100644
--- a/spec/models/xapian_spec.rb
+++ b/spec/models/xapian_spec.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe User, " when indexing users with Xapian" do
@@ -8,8 +9,7 @@ describe User, " when indexing users with Xapian" do
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 = ActsAsXapian::Search.new([User], "Silly", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == users(:silly_name_user)
end
@@ -17,8 +17,7 @@ describe User, " when indexing users with Xapian" do
it "should search by 'about me' text" do
user = users(:bob_smith_user)
- # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
- xapian_object = InfoRequest.full_search([User], "stuff", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([User], "stuff", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == user
@@ -26,10 +25,10 @@ describe User, " when indexing users with Xapian" do
user.save!
update_xapian_index
- xapian_object = InfoRequest.full_search([User], "stuff", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([User], "stuff", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([User], "aardvark", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([User], "aardvark", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == user
end
@@ -42,26 +41,26 @@ describe PublicBody, " when indexing public bodies with Xapian" do
end
it "should search index the main name field" do
- xapian_object = InfoRequest.full_search([PublicBody], "humpadinking", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "humpadinking", :limit => 100)
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
- xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "albatross", :limit => 100)
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
- xapian_object = InfoRequest.full_search([PublicBody], "albatross", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "albatross", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == public_bodies(:humpadink_public_body)
public_bodies(:forlorn_public_body).destroy
update_xapian_index
- xapian_object = InfoRequest.full_search([PublicBody], "lonely", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "lonely", :limit => 100)
xapian_object.results.should == []
end
@@ -75,13 +74,13 @@ describe PublicBody, " when indexing requests by body they are to" do
end
it "should find requests to the body" do
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100)
xapian_object.results.size.should == PublicBody.find_by_url_name("tgq").info_requests.map(&:info_request_events).flatten.size
end
it "should update index correctly when URL name of body changes" do
# initial search
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100)
xapian_object.results.size.should == PublicBody.find_by_url_name("tgq").info_requests.map(&:info_request_events).flatten.size
models_found_before = xapian_object.results.map { |x| x[:model] }
@@ -93,9 +92,9 @@ describe PublicBody, " when indexing requests by body they are to" do
update_xapian_index
# check we get results expected
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:gq", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:gq", :limit => 100)
xapian_object.results.size.should == PublicBody.find_by_url_name("gq").info_requests.map(&:info_request_events).flatten.size
models_found_after = xapian_object.results.map { |x| x[:model] }
@@ -113,11 +112,11 @@ describe PublicBody, " when indexing requests by body they are to" do
update_xapian_index
# check we get results expected
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:tgq", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:tgq", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:gq", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:gq", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_from:" + body.url_name, 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_from:#{body.url_name}", :limit => 100)
xapian_object.results.size.should == public_bodies(:geraldine_public_body).info_requests.map(&:info_request_events).flatten.size
models_found_after = xapian_object.results.map { |x| x[:model] }
end
@@ -130,13 +129,14 @@ describe User, " when indexing requests by user they are from" do
end
it "should find requests from the user" do
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith",
+ :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100)
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
- # 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 = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith variety:sent",
+ :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100)
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)
@@ -150,8 +150,9 @@ describe User, " when indexing requests by user they are from" do
update_xapian_index
- # 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 = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith",
+ :sort_by_prefix => 'created_at', :sort_by_ascending => true,
+ :collapse_by_prefix => 'request_collapse', :limit => 100)
xapian_object.results.map{|x|x[:model].info_request}.should =~ InfoRequest.all(:conditions => "user_id = #{users(:bob_smith_user).id}")
end
@@ -172,8 +173,7 @@ describe User, " when indexing requests by user they are from" do
update_xapian_index
- # def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:john_k", 'created_at', true, 'request_collapse', 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:john_k", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model].should == info_request_events(:silly_outgoing_message_event)
end
@@ -181,7 +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
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith",
+ :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100)
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] }
@@ -193,9 +194,10 @@ describe User, " when indexing requests by user they are from" do
update_xapian_index
# check we get results expected
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:bob_smith", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:bob_smith", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "requested_by:robert_smith", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "requested_by:robert_smith",
+ :sort_by_prefix => 'created_at', :sort_by_ascending => true, :limit => 100)
models_found_after = xapian_object.results.map { |x| x[:model] }
models_found_before.should == models_found_after
end
@@ -208,13 +210,13 @@ describe User, " when indexing comments by user they are by" do
end
it "should find requests from the user" do
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_emnameem", :limit => 100)
xapian_object.results.size.should == 1
end
it "should update index correctly when URL name of user changes" do
# initial search
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_emnameem", :limit => 100)
xapian_object.results.size.should == 1
models_found_before = xapian_object.results.map { |x| x[:model] }
@@ -226,9 +228,9 @@ describe User, " when indexing comments by user they are by" do
update_xapian_index
# check we get results expected
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_emnameem", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_emnameem", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "commented_by:silly_name", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "commented_by:silly_name", :limit => 100)
xapian_object.results.size.should == 1
models_found_after = xapian_object.results.map { |x| x[:model] }
@@ -243,7 +245,7 @@ describe InfoRequest, " when indexing requests by their title" do
end
it "should find events for the request" do
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event)
end
@@ -257,9 +259,9 @@ describe InfoRequest, " when indexing requests by their title" do
update_xapian_index
# check we get results expected
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "request:how_much_public_money_is_wasted_o", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "request:really_naughty", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "request:really_naughty", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event)
end
@@ -277,11 +279,11 @@ describe InfoRequest, " when indexing requests by tag" do
ir.save!
update_xapian_index
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "tag:bunnyrabbit", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "tag:bunnyrabbit", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == info_request_events(:silly_outgoing_message_event)
- xapian_object = InfoRequest.full_search([InfoRequestEvent], "tag:orangeaardvark", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([InfoRequestEvent], "tag:orangeaardvark", :limit => 100)
xapian_object.results.size.should == 0
end
end
@@ -298,14 +300,14 @@ describe PublicBody, " when indexing authorities by tag" do
body.save!
update_xapian_index
- xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == public_bodies(:geraldine_public_body)
- xapian_object = InfoRequest.full_search([PublicBody], "tag:mice:3", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice:3", :limit => 100)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == public_bodies(:geraldine_public_body)
- xapian_object = InfoRequest.full_search([PublicBody], "tag:orangeaardvark", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:orangeaardvark", :limit => 100)
xapian_object.results.size.should == 0
end
end
@@ -327,11 +329,11 @@ describe PublicBody, " when only indexing selected things on a rebuild" do
values = false
texts = false
rebuild_xapian_index(terms, values, texts, dropfirst)
- xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100)
xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all
# only reindex 'tag' and text
dropfirst = true
@@ -339,32 +341,57 @@ describe PublicBody, " when only indexing selected things on a rebuild" do
values = false
texts = true
rebuild_xapian_index(terms, values, texts, dropfirst)
- xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100)
xapian_object.results.size.should == 1
- xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100)
xapian_object.results.size.should == 1
- xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100)
xapian_object.results.size.should == 0
# only reindex 'variety' term, but keeping the existing data in-place
dropfirst = false
terms = "V"
texts = false
rebuild_xapian_index(terms, values, texts, dropfirst)
- xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100)
xapian_object.results.size.should == 1
- xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100)
xapian_object.results.size.should == 1
- xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100)
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)
- xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "tag:mice", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([PublicBody], "frobzn", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "frobzn", :limit => 100)
xapian_object.results.size.should == 0
- xapian_object = InfoRequest.full_search([PublicBody], "variety:authority", 'created_at', true, nil, 100, 1)
+ xapian_object = ActsAsXapian::Search.new([PublicBody], "variety:authority", :limit => 100)
xapian_object.results.map{|x|x[:model]}.should =~ PublicBody.all
end
end
+# I would expect ActsAsXapian to have some tests under vendor/plugins/acts_as_xapian, but
+# it looks like this is not the case. Putting a test here instead.
+describe ActsAsXapian::Search, "#words_to_highlight" do
+ it "should return a list of words used in the search" do
+ s = ActsAsXapian::Search.new([PublicBody], "albatross words", :limit => 100)
+ s.words_to_highlight.should == ["albatross", "words"]
+ end
+
+ it "should remove any operators" do
+ s = ActsAsXapian::Search.new([PublicBody], "albatross words tag:mice", :limit => 100)
+ s.words_to_highlight.should == ["albatross", "words"]
+ end
+
+ # This is the current behaviour but it seems a little simplistic to me
+ it "should separate punctuation" do
+ s = ActsAsXapian::Search.new([PublicBody], "The doctor's patient", :limit => 100)
+ s.words_to_highlight.should == ["The", "doctor", "s", "patient"]
+ end
+
+ it "should handle non-ascii characters" do
+ s = ActsAsXapian::Search.new([PublicBody], "adatigénylés words tag:mice", :limit => 100)
+ s.words_to_highlight.should == ["adatigénylés", "words"]
+ end
+
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 57ab88da2..a3b06cea8 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,7 +1,19 @@
require 'rubygems'
require 'spork'
+
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
+require 'simplecov'
+require 'coveralls'
+# Generate coverage locally in html as well as in coveralls.io
+SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
+ SimpleCov::Formatter::HTMLFormatter,
+ Coveralls::SimpleCov::Formatter
+]
+SimpleCov.start('rails') do
+ add_filter 'commonlib'
+ add_filter 'vendor/plugins'
+end
Spork.prefork do
# Loading more in this block will cause your tests to run faster. However,
diff --git a/spec/views/reports/new.erb_spec.rb b/spec/views/reports/new.erb_spec.rb
new file mode 100644
index 000000000..66b738261
--- /dev/null
+++ b/spec/views/reports/new.erb_spec.rb
@@ -0,0 +1,29 @@
+require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__)
+
+describe 'reports/new.html.erb' do
+ let(:info_request) { mock_model(InfoRequest, :url_title => "foo", :report_reasons => ["Weird"]) }
+ before :each do
+ assign(:info_request, info_request)
+ end
+
+ it "should show a form" do
+ render
+ rendered.should have_selector("form")
+ end
+
+ context "request has already been reported" do
+ before :each do
+ info_request.stub!(:attention_requested).and_return(true)
+ end
+
+ it "should not show a form" do
+ render
+ rendered.should_not have_selector("form")
+ end
+
+ it "should say it's already been reported" do
+ render
+ rendered.should contain("This request has already been reported")
+ end
+ end
+end
diff --git a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
index 1e5df8de4..f2cd1075c 100644
--- a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
+++ b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
# acts_as_xapian/lib/acts_as_xapian.rb:
# Xapian full text search in Ruby on Rails.
#
@@ -472,7 +473,9 @@ module ActsAsXapian
# date ranges or similar. Use this for cheap highlighting with
# TextHelper::highlight, and excerpt.
def words_to_highlight
- query_nopunc = self.query_string.gsub(/[^a-z0-9:\.\/_]/i, " ")
+ # TODO: In Ruby 1.9 we can do matching of any unicode letter with \p{L}
+ # But we still need to support ruby 1.8 for the time being so...
+ query_nopunc = self.query_string.gsub(/[^ёЁа-яА-Яa-zA-Zà-üÀ-Ü0-9:\.\/_]/iu, " ")
query_nopunc = query_nopunc.gsub(/\s+/, " ")
words = query_nopunc.split(" ")
# Remove anything with a :, . or / in it