aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock1
-rw-r--r--app/controllers/admin_public_body_controller.rb5
-rw-r--r--app/controllers/public_body_controller.rb124
-rw-r--r--config/general.yml-example5
-rw-r--r--doc/THEMES.md2
-rw-r--r--lib/configuration.rb1
-rw-r--r--lib/tasks/gettext.rake42
-rw-r--r--public/stylesheets/admin.css77
-rw-r--r--public/stylesheets/alt.css232
-rwxr-xr-xscript/generate_pot.sh22
-rw-r--r--spec/controllers/public_body_controller_spec.rb74
-rw-r--r--spec/models/xapian_spec.rb31
-rw-r--r--vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb43
14 files changed, 247 insertions, 413 deletions
diff --git a/Gemfile b/Gemfile
index a323981d3..5fcedc84f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -55,6 +55,7 @@ group :test do
gem 'fakeweb'
gem 'coveralls', :require => false
gem 'webrat'
+ gem 'nokogiri'
end
group :development do
diff --git a/Gemfile.lock b/Gemfile.lock
index 8d5059d7e..15c5245ff 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -270,6 +270,7 @@ DEPENDENCIES
net-http-local
net-purge
newrelic_rpm
+ nokogiri
pg
rack
rails (= 3.1.12)
diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb
index ec2a08dbc..e0da234b0 100644
--- a/app/controllers/admin_public_body_controller.rb
+++ b/app/controllers/admin_public_body_controller.rb
@@ -14,6 +14,7 @@ class AdminPublicBodyController < AdminController
def _lookup_query_internal
@locale = self.locale_from_params()
+ underscore_locale = @locale.gsub '-', '_'
I18n.with_locale(@locale) do
@query = params[:query]
if @query == ""
@@ -23,10 +24,10 @@ class AdminPublicBodyController < AdminController
if @page == ""
@page = nil
end
- @public_bodies = PublicBody.joins(:translations).where(@query.nil? ? "public_body_translations.locale = '#{@locale}'" :
+ @public_bodies = PublicBody.joins(:translations).where(@query.nil? ? "public_body_translations.locale = '#{underscore_locale}'" :
["(lower(public_body_translations.name) like lower('%'||?||'%') or
lower(public_body_translations.short_name) like lower('%'||?||'%') or
- lower(public_body_translations.request_email) like lower('%'||?||'%' )) AND (public_body_translations.locale = '#{@locale}')", @query, @query, @query]).paginate :order => "public_body_translations.name", :page => @page, :per_page => 100
+ lower(public_body_translations.request_email) like lower('%'||?||'%' )) AND (public_body_translations.locale = '#{underscore_locale}')", @query, @query, @query]).paginate :order => "public_body_translations.name", :page => @page, :per_page => 100
end
@public_bodies_by_tag = PublicBody.find_by_tag(@query)
end
diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb
index 9f692c5ba..02f0ceb19 100644
--- a/app/controllers/public_body_controller.rb
+++ b/app/controllers/public_body_controller.rb
@@ -86,34 +86,45 @@ class PublicBodyController < ApplicationController
def list
long_cache
# XXX move some of these tag SQL queries into has_tag_string.rb
- @query = "%#{params[:public_body_query].nil? ? "" : params[:public_body_query]}%"
+
+ like_query = params[:public_body_query]
+ like_query = "" if like_query.nil?
+ like_query = "%#{like_query}%"
+
@tag = params[:tag]
- @locale = self.locale_from_params()
- default_locale = I18n.default_locale.to_s
- locale_condition = "(upper(public_body_translations.name) LIKE upper(?)
- OR upper(public_body_translations.notes) LIKE upper (?))
- AND public_body_translations.locale = ?
- AND public_bodies.id <> #{PublicBody.internal_admin_body.id}"
+
+ @locale = self.locale_from_params
+ underscore_locale = @locale.gsub '-', '_'
+ underscore_default_locale = I18n.default_locale.to_s.gsub '-', '_'
+
+ where_condition = "public_bodies.id <> #{PublicBody.internal_admin_body.id}"
+ where_parameters = []
+
+ first_letter = false
+
+ base_tag_condition = " AND (SELECT count(*) FROM has_tag_string_tags" \
+ " WHERE has_tag_string_tags.model_id = public_bodies.id" \
+ " AND has_tag_string_tags.model = 'PublicBody'"
+
+ # Restrict the public bodies shown according to the tag
+ # parameter supplied in the URL:
if @tag.nil? or @tag == "all"
@tag = "all"
- conditions = [locale_condition, @query, @query, default_locale]
elsif @tag == 'other'
category_list = PublicBodyCategories::get().tags().map{|c| "'"+c+"'"}.join(",")
- conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
- and has_tag_string_tags.model = \'PublicBody\'
- and has_tag_string_tags.name in (' + category_list + ')) = 0', @query, @query, default_locale]
+ where_condition += base_tag_condition + " AND has_tag_string_tags.name in (#{category_list})) = 0"
elsif @tag.size == 1
@tag.upcase!
- conditions = [locale_condition + ' AND public_body_translations.first_letter = ?', @query, @query, default_locale, @tag]
+ # The first letter queries have to be done on
+ # translations, so just indicate to add that later:
+ first_letter = true
elsif @tag.include?(":")
name, value = HasTagString::HasTagStringTag.split_tag_into_name_value(@tag)
- conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
- and has_tag_string_tags.model = \'PublicBody\'
- and has_tag_string_tags.name = ? and has_tag_string_tags.value = ?) > 0', @query, @query, default_locale, name, value]
+ where_condition += base_tag_condition + " AND has_tag_string_tags.name = ? AND has_tag_string_tags.value = ?) > 0"
+ where_parameters.concat [name, value]
else
- conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
- and has_tag_string_tags.model = \'PublicBody\'
- and has_tag_string_tags.name = ?) > 0', @query, @query, default_locale, @tag]
+ where_condition += base_tag_condition + " AND has_tag_string_tags.name = ?) > 0"
+ where_parameters.concat [@tag]
end
if @tag == "all"
@@ -128,10 +139,45 @@ class PublicBodyController < ApplicationController
@description = _("in the category ‘{{category_name}}’", :category_name=>category_name)
end
end
+
I18n.with_locale(@locale) do
- @public_bodies = PublicBody.where(conditions).joins(:translations).order("public_body_translations.name").paginate(
- :page => params[:page], :per_page => 100
- )
+
+ if AlaveteliConfiguration::public_body_list_fallback_to_default_locale
+ # Unfortunately, when we might fall back to the
+ # default locale, this is a rather complex query:
+ query = %Q{
+ SELECT public_bodies.*, COALESCE(current_locale.name, default_locale.name) AS display_name
+ FROM public_bodies
+ LEFT OUTER JOIN public_body_translations as current_locale
+ ON (public_bodies.id = current_locale.public_body_id
+ AND current_locale.locale = ? AND #{get_public_body_list_translated_condition 'current_locale', first_letter})
+ LEFT OUTER JOIN public_body_translations as default_locale
+ ON (public_bodies.id = default_locale.public_body_id
+ AND default_locale.locale = ? AND #{get_public_body_list_translated_condition 'default_locale', first_letter})
+ WHERE #{where_condition} AND COALESCE(current_locale.name, default_locale.name) IS NOT NULL
+ ORDER BY display_name}
+ sql = [query, underscore_locale, like_query, like_query]
+ sql.push @tag if first_letter
+ sql += [underscore_default_locale, like_query, like_query]
+ sql.push @tag if first_letter
+ sql += where_parameters
+ @public_bodies = PublicBody.paginate_by_sql(
+ sql,
+ :page => params[:page],
+ :per_page => 100)
+ else
+ # The simpler case where we're just searching in the current locale:
+ where_condition = get_public_body_list_translated_condition('public_body_translations', first_letter, true) +
+ ' AND ' + where_condition
+ where_sql = [where_condition, like_query, like_query]
+ where_sql.push @tag if first_letter
+ where_sql += [underscore_locale] + where_parameters
+ @public_bodies = PublicBody.where(where_sql) \
+ .joins(:translations) \
+ .order("public_body_translations.name") \
+ .paginate(:page => params[:page], :per_page => 100)
+ end
+
respond_to do |format|
format.html { render :template => "public_body/list" }
end
@@ -165,27 +211,27 @@ class PublicBodyController < ApplicationController
[[total_column,
[{
- :title => 'Public bodies with the most requests',
- :y_axis => 'Number of requests',
+ :title => _('Public bodies with the most requests'),
+ :y_axis => _('Number of requests'),
:highest => true}]],
['info_requests_successful_count',
[{
- :title => 'Public bodies with the most successful requests',
- :y_axis => 'Percentage of total requests',
+ :title => _('Public bodies with the most successful requests'),
+ :y_axis => _('Percentage of total requests'),
:highest => true},
{
- :title => 'Public bodies with the fewest successful requests',
- :y_axis => 'Percentage of total requests',
+ :title => _('Public bodies with the fewest successful requests'),
+ :y_axis => _('Percentage of total requests'),
:highest => false}]],
['info_requests_overdue_count',
[{
- :title => 'Public bodies with most overdue requests',
- :y_axis => 'Percentage of requests that are overdue',
+ :title => _('Public bodies with most overdue requests'),
+ :y_axis => _('Percentage of requests that are overdue'),
:highest => true}]],
['info_requests_not_held_count',
[{
- :title => 'Public bodies that most frequently replied with "Not Held"',
- :y_axis => 'Percentage of total requests',
+ :title => _('Public bodies that most frequently replied with "Not Held"'),
+ :y_axis => _('Percentage of total requests'),
:highest => true}]]].each do |column, graphs_properties|
graphs_properties.each do |graph_properties|
@@ -207,7 +253,7 @@ class PublicBodyController < ApplicationController
data_to_draw = {
'id' => "#{column}-#{highest ? 'highest' : 'lowest'}",
- 'x_axis' => 'Public Bodies',
+ 'x_axis' => _('Public Bodies'),
'y_axis' => graph_properties[:y_axis],
'errorbars' => percentages,
'title' => graph_properties[:title]}
@@ -236,4 +282,18 @@ class PublicBodyController < ApplicationController
@xapian_requests = perform_search_typeahead(query, PublicBody)
render :partial => "public_body/search_ahead"
end
+
+ private
+ def get_public_body_list_translated_condition(table, first_letter=false, locale=nil)
+ result = "(upper(#{table}.name) LIKE upper(?)" \
+ " OR upper(#{table}.notes) LIKE upper (?))"
+ if first_letter
+ result += " AND #{table}.first_letter = ?"
+ end
+ if locale
+ result += " AND #{table}.locale = ?"
+ end
+ result
+ end
+
end
diff --git a/config/general.yml-example b/config/general.yml-example
index 37b0c2fc9..5f3697a36 100644
--- a/config/general.yml-example
+++ b/config/general.yml-example
@@ -200,3 +200,8 @@ PUBLIC_BODY_STATISTICS_PAGE: false
# The page of statistics for public bodies will only consider public
# bodies that have had at least this number of requests:
MINIMUM_REQUESTS_FOR_STATISTICS: 50
+
+# If only some of the public bodies have been translated into every
+# available locale, you can allow a fallback to the default locale for
+# listing of public bodies.
+PUBLIC_BODY_LIST_FALLBACK_TO_DEFAULT_LOCALE: false
diff --git a/doc/THEMES.md b/doc/THEMES.md
index bae7d7665..d6109cdc5 100644
--- a/doc/THEMES.md
+++ b/doc/THEMES.md
@@ -64,7 +64,7 @@ add custom help pages, as described below.
# 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.
+Alaveteli site live in `app/views/`. They use Rails' ERB syntax.
For example, the template for the home page lives at
`app/views/general/frontpage.html.erb`, and the template for the "about
us" page is at `app/views/help/about.html.erb`.
diff --git a/lib/configuration.rb b/lib/configuration.rb
index d6fd8765f..ab985c8bf 100644
--- a/lib/configuration.rb
+++ b/lib/configuration.rb
@@ -49,6 +49,7 @@ module AlaveteliConfiguration
:NEW_RESPONSE_REMINDER_AFTER_DAYS => [3, 10, 24],
:OVERRIDE_ALL_PUBLIC_BODY_REQUEST_EMAILS => '',
:PUBLIC_BODY_STATISTICS_PAGE => false,
+ :PUBLIC_BODY_LIST_FALLBACK_TO_DEFAULT_LOCALE => false,
:RAW_EMAILS_LOCATION => 'files/raw_emails',
:READ_ONLY => '',
:RECAPTCHA_PRIVATE_KEY => 'x',
diff --git a/lib/tasks/gettext.rake b/lib/tasks/gettext.rake
index ace7205ae..366dfbe88 100644
--- a/lib/tasks/gettext.rake
+++ b/lib/tasks/gettext.rake
@@ -9,27 +9,31 @@ namespace :gettext do
end
end
- desc "Update pot file only, without fuzzy guesses (these are done by Transifex)"
- task :findpot => :environment do
+ desc "Update pot/po files for a theme."
+ task :find_theme => :environment do
+ theme = ENV['THEME']
+ unless theme
+ puts "Usage: Specify an Alaveteli-theme with THEME=[theme directory name]"
+ exit(0)
+ end
load_gettext
- $LOAD_PATH << File.join(File.dirname(__FILE__),'..','..','lib')
- require 'gettext_i18n_rails/haml_parser'
- files = files_to_translate
+ msgmerge = Rails.application.config.gettext_i18n_rails.msgmerge
+ msgmerge ||= %w[--sort-output --no-location --no-wrap]
+ GetText.update_pofiles_org(
+ text_domain,
+ theme_files_to_translate(theme),
+ "version 0.0.1",
+ :po_root => theme_locale_path(theme),
+ :msgmerge => msgmerge
+ )
+ end
- #write found messages to tmp.pot
- temp_pot = "tmp.pot"
- GetText::rgettext(files, temp_pot)
+ def theme_files_to_translate(theme)
+ Dir.glob("{vendor/plugins/#{theme}/lib}/**/*.{rb,erb}")
+ end
- #merge tmp.pot and existing pot
- FileUtils.mkdir_p('locale')
- GetText::msgmerge("locale/app.pot", temp_pot, "alaveteli", :po_root => 'locale', :msgmerge=>[ :no_wrap, :sort_output ])
- Dir.glob("locale/*/app.po") do |po_file|
- GetText::msgmerge(po_file, temp_pot, "alaveteli", :po_root => 'locale', :msgmerge=>[ :no_wrap, :sort_output ])
- end
- File.delete(temp_pot)
- end
+ def theme_locale_path(theme)
+ File.join(Rails.root, "vendor", "plugins", theme, "locale-theme")
+ end
- def files_to_translate
- Dir.glob("{app,lib,config,locale}/**/*.{rb,erb,haml,rhtml}")
- end
end
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css
deleted file mode 100644
index 7f8d646d3..000000000
--- a/public/stylesheets/admin.css
+++ /dev/null
@@ -1,77 +0,0 @@
-/* FOIFA admin CSS */
-
-h2 {
- margin-top: 0.2em;
- margin-bottom: 0.5em;
-}
-
-table {
- border-collapse: collapse;
- margin-bottom: 1em;
-}
-
-td, th {
- border: solid 1px #000000;
-}
-td {
- vertical-align: top
-}
-td {
- max-width: 30em;
- overflow: auto;
-}
-
-tr.odd {
- background-color: #bbbbbb;
-}
-
-tr.even {
- background-color: #dddddd;
-}
-
-.entry_changed {
- font-weight: bold;
-}
-
-form {
- margin-bottom: 1em;
-}
-
-#notice {
- color: green;
- border: solid 1px green;
- padding: 1em;
-}
-#error, #errorExplanation {
- color: red;
- border: solid 1px red;
- padding: 1em;
-}
-#tag_help {
- float: right;
- width: 25%;
- margin-top: 0;
-}
-#public_body_form {
- float: left;
- width: 70%;
-}
-
-.forms_on_one_line {
- display: inline;
-}
-
-.user_photo_on_admin {
- float: right;
-}
-
-.user_photo_on_admin img {
- width: 96px;
- height: 96px;
- vertical-align: middle;
- border: 1px solid #dddddd;
- margin-right: 5px;
- padding: 2px;
-}
-
-
diff --git a/public/stylesheets/alt.css b/public/stylesheets/alt.css
deleted file mode 100644
index bf6ba2d16..000000000
--- a/public/stylesheets/alt.css
+++ /dev/null
@@ -1,232 +0,0 @@
-/*------------------------------------------------ global */
-body
-{
- padding: 0px;
- margin: 0px;
- text-align: center;
- font-family: Tahoma, Geneva, sans-serif;
-}
-
-/*------------------------------------------------ banner */
-
-#banner
-{
- position: relative;
- top: 0px;
- left: 0px;
- width: 100%;
- height: 200px;
- margin: 0px;
- background-color: #F0F0F0;
- background-image: url(../images/navimg/bnnr-ifyoudontask.png);
- background-repeat: no-repeat;
- background-position: center top;
- border-color: #993233;
- border-width: 0 0 3px 0;
- border-style: solid;
-}
-
-/*------------------------------------------------ header; not needed? */
-#header
-{ display: none; }
-
-/*------------------------------------------------ search */
-
-#navigation_search
-{
- position: absolute;
- width: 100%;
- left: 0px;
- top: 175px;
- z-index: 150;
- text-align: right;
- -moz-opacity: 0.7!important;
- filter: alpha(opacity= 70)!important;
- opacity: 0.7!important;
-}
- #navigation_search input
- {
- border-color: #010101;
- border-width: 1px;
- border-style: solid;
- background-color: #fff;
- color: #000;
- }
- #navigation_search input#navigation_search_query
- {
- width: 8em;
- }
-
-#navigation_search p { margin: 0 0.6em 0 0; }
-
-/*------------------------------------------------ topnav */
-#topnav
-{
- position: relative;
- top: 0px;
- left: 0px;
- width: 100%;
- height: auto;
- overflow: auto;
- padding: 0px 0px 0px 0px;
- z-index: 100;
- background-color: #000;
- font-size: 0.9em;
-}
-
- #topnav ul
- {
- list-style: none;
- margin: 0px;
- padding: 0px;
- }
-
- #topnav li
- {
- float: left;
- }
-
- #topnav li a, #topnav li a:visited
- {
- display: block;
- margin: 0px;
- padding: 0.15em 0.6em 0.25em 0.8em;
- color: #ADADAD;
- text-decoration: none;
- }
-
- #topnav li a:hover
- { color: #fff; }
-
- #topnav li a:active { }
-
- #topnav li a.on, #topnav li a.on:visited
- {
- font-weight: bold;
- color: #000;
- }
-
- #topnav li a.on:hover {}
-
- #topnav li a.on:active {}
-
-/*-------------------------- login/signup */
-#logged_in_bar
-{
- float: right;
- clear: none;
- font-size: 0.9em;
- z-index: 200;
- padding: 0.20em 10px 0.25em 1em;
- color: #FFF;
-}
- #logged_in_bar a, #logged_in_bar a:visited { color: #92B3FF; }
-
-/*------------------------------------------------ temp stuff */
-#staging, #alpha_notice
-{ display: none;}
-
-#staging
-{
- border-color: #FF201D;
- border-width: 1px;
- border-style: dotted;
- clear: both;
- text-align: center;
- color: #FF201D;
- margin-top: 40px;
-}
-
-#alpha_notice
-{
- padding: 0 20px 0 20px;
- border-color: #FF201D;
- border-width: 1px;
- border-style: dotted;
- background-color: #f0f0f0;
-}
-
-/*------------------------------------------------ wrapper*/
-
-#wrapper
-{
- position: relative;
- clear: both;
- top: 0em;
- padding: 0px;
- margin: 0px auto 1.2em auto;
- max-width: 50em;
- /* = 800px at default size? so 1em = 16px*/
- _width: 50em;
- text-align: left;
-}
-
-/*------------------------------------------------ content */
-
-#content
-{
- position: relative;
- padding: 2em 1em 1em 1em;
-}
-
-h1, h2, h3
-{
- font-family: Trebuchet, Trebuchet MS, Helvetica, sans-serif;
- /*Arial Black, Gadget, sans-serif*/
- font-weight: bold;
- line-height: 1em;
- letter-spacing: 0em;
- color: #555;
-}
- h1 { font-size: 1.8em;}
- h2 { font-size: 1.4em;}
- h3 { font-size: 1em;}
-
-h4, h5, h6
-{}
-
-
-/*---------------- content : recent requests sidebar */
-#find_information
-{
- width: 10.5em;
- float: right;
- clear: none;
- background-color: #e0e0e0;
- background-image: url(../images/navimg/sidebag-bg-wide.png);
- background-repeat: no-repeat;
- background-position: center top;
- padding: 105px 0.25em 0.25em 0.35em;
-}
- #find_information h1
- { font-size: 1.2em; line-height: 0.85em; margin-top: 0px;}
-
- #find_information p
- { font-size: 0.8em; line-height: 1em; }
-
- #find_information input#query
- { width: 12em; }
-
-/*---------------- content : find body */
-#make_requests
-{
- float: left;
- clear: none;
- width: 34em;
- text-align: center;
-}
-
-/*------------------------------------------------ footer */
-
-#footer
-{
- clear: both;
- position: relative;
- background-color: #F0F0F0;
- border-color: #993233;
- border-width: 3px 0 0 0;
- border-style: solid;
- margin: 1em 0 0 0;
- padding: 0.5em 0 0.5em 0;
- font-size: 0.85em;
-} \ No newline at end of file
diff --git a/script/generate_pot.sh b/script/generate_pot.sh
deleted file mode 100755
index c0540c3d9..000000000
--- a/script/generate_pot.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-echo "This is NOT a completed script! Just use it as reference for what to do from the command line, or fix it until it works!"
-exit 1
-
-cd `dirname $0`
-# grab latest po files from Transifex
-tx pull -a -f
-git status | grep app.po | awk '{print $3}' | xargs git add
-git commit -m "Backup latest po files from Transifex"
-
-# now regenerate POT and PO files from Alaveteli source
-bundle exec rake gettext:store_model_attributes
-bundle exec rake gettext:findpot
-
-# upload the result to Transifex
-tx push -t
-
-# re-download (it removes the fuzzy strings and normalises it to the format last committed)
-tx pull -a -f
-git status | grep app.po | awk '{print $3}' | xargs git add
-git commit -m "Updated POT"
diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb
index 92130f3d0..2d1b1466f 100644
--- a/spec/controllers/public_body_controller_spec.rb
+++ b/spec/controllers/public_body_controller_spec.rb
@@ -1,6 +1,8 @@
# coding: utf-8
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'nokogiri'
+
describe PublicBodyController, "when showing a body" do
render_views
@@ -78,24 +80,80 @@ describe PublicBodyController, "when listing bodies" do
response.should be_success
end
- it "should list all bodies from default locale, even when there are no translations for selected locale" do
- I18n.with_locale(:en) do
- @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
+ def make_single_language_example(locale)
+ result = nil
+ I18n.with_locale(locale) do
+ case locale
+ when :en
+ result = PublicBody.new(:name => 'English only',
+ :short_name => 'EO')
+ when :es
+ result = PublicBody.new(:name => 'Español Solamente',
+ :short_name => 'ES')
+ else
+ raise StandardError.new "Unknown locale #{locale}"
+ end
+ result.request_email = "#{locale}@example.org"
+ result.last_edit_editor = 'test'
+ result.last_edit_comment = ''
+ result.save
end
+ result
+ end
+
+ it "with no fallback, should only return bodies from the current locale" do
+ @english_only = make_single_language_example :en
+ @spanish_only = make_single_language_example :es
+ get :list, {:locale => 'es'}
+ assigns[:public_bodies].include?(@english_only).should == false
+ assigns[:public_bodies].include?(@spanish_only).should == true
+ end
+
+ it "if fallback is requested, should list all bodies from default locale, even when there are no translations for selected locale" do
+ AlaveteliConfiguration.stub!(:public_body_list_fallback_to_default_locale).and_return(true)
+ @english_only = make_single_language_example :en
get :list, {:locale => 'es'}
assigns[:public_bodies].include?(@english_only).should == true
end
+ it 'if fallback is requested, should still list public bodies only with translations in the current locale' do
+ AlaveteliConfiguration.stub!(:public_body_list_fallback_to_default_locale).and_return(true)
+ @spanish_only = make_single_language_example :es
+ get :list, {:locale => 'es'}
+ assigns[:public_bodies].include?(@spanish_only).should == true
+ end
+
+ it "if fallback is requested, make sure that there are no duplicates listed" do
+ AlaveteliConfiguration.stub!(:public_body_list_fallback_to_default_locale).and_return(true)
+ get :list, {:locale => 'es'}
+ pb_ids = assigns[:public_bodies].map { |pb| pb.id }
+ unique_pb_ids = pb_ids.uniq
+ pb_ids.sort.should === unique_pb_ids.sort
+ end
+
it 'should show public body names in the selected locale language if present' do
get :list, {:locale => 'es'}
response.should contain('El Department for Humpadinking')
end
+ it 'should not show the internal admin authority' do
+ PublicBody.internal_admin_body
+ get :list, {:locale => 'en'}
+ response.should_not contain('Internal admin authority')
+ end
+
+ it 'should order on the translated name, even with the fallback' do
+ # The names of each public body is in:
+ # <span class="head"><a>Public Body Name</a></span>
+ # ... eo extract all of those, and check that they are ordered:
+ AlaveteliConfiguration.stub!(:public_body_list_fallback_to_default_locale).and_return(true)
+ get :list, {:locale => 'es'}
+ parsed = Nokogiri::HTML(response.body)
+ public_body_names = parsed.xpath '//span[@class="head"]/a/text()'
+ public_body_names = public_body_names.map { |pb| pb.to_s }
+ public_body_names.should == public_body_names.sort
+ end
+
it 'should show public body names in the selected locale language if present for a locale with underscores' do
AlaveteliLocalization.set_locales('he_IL en', 'en')
get :list, {:locale => 'he_IL'}
diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb
index 7aab9cdc6..c7c21e3a0 100644
--- a/spec/models/xapian_spec.rb
+++ b/spec/models/xapian_spec.rb
@@ -400,3 +400,34 @@ describe ActsAsXapian::Search, "#words_to_highlight" do
end
end
+
+describe InfoRequestEvent, " when faced with a race condition during xapian_mark_needs_index" do
+
+ before(:each) do
+ load_raw_emails_data
+ get_fixtures_xapian_index
+ # Use the before create job hook to simulate a race condition with another process
+ # by creating an acts_as_xapian_job record for the same model
+ class InfoRequestEvent
+ def xapian_before_create_job_hook(action, model, model_id)
+ ActsAsXapian::ActsAsXapianJob.create!(:model => model,
+ :model_id => model_id,
+ :action => action)
+ end
+ end
+ end
+
+ after(:each) do
+ # Reset the before create job hook
+ class InfoRequestEvent
+ def xapian_before_create_job_hook(action, model, model_id)
+ end
+ end
+ end
+
+ it 'should not raise an error but should fail silently' do
+ ir = info_requests(:naughty_chicken_request)
+ ir.reindex_request_events
+ 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 f2cd1075c..fcf7a778d 100644
--- a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
+++ b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
@@ -913,16 +913,11 @@ module ActsAsXapian
# Used to mark changes needed by batch indexer
def xapian_mark_needs_index
- model = self.class.base_class.to_s
- model_id = self.id
- ActiveRecord::Base.transaction do
- found = ActsAsXapianJob.delete_all([ "model = ? and model_id = ?", model, model_id])
- job = ActsAsXapianJob.new
- job.model = model
- job.model_id = model_id
- job.action = 'update'
- job.save!
- end
+ xapian_create_job('update', self.class.base_class.to_s, self.id)
+ end
+
+ def xapian_mark_needs_destroy
+ xapian_create_job('destroy', self.class.base_class.to_s, self.id)
end
# Allow reindexing to be skipped if a flag is set
@@ -931,18 +926,26 @@ module ActsAsXapian
xapian_mark_needs_index
end
- def xapian_mark_needs_destroy
- model = self.class.base_class.to_s
- model_id = self.id
- ActiveRecord::Base.transaction do
- found = ActsAsXapianJob.delete_all([ "model = ? and model_id = ?", model, model_id])
- job = ActsAsXapianJob.new
- job.model = model
- job.model_id = model_id
- job.action = 'destroy'
- job.save!
+ def xapian_create_job(action, model, model_id)
+ begin
+ ActiveRecord::Base.transaction do
+ ActsAsXapianJob.delete_all([ "model = ? and model_id = ?", model, model_id])
+ xapian_before_create_job_hook(action, model, model_id)
+ ActsAsXapianJob.create!(:model => model,
+ :model_id => model_id,
+ :action => action)
+ end
+ rescue ActiveRecord::RecordNotUnique => e
+ # Given the error handling in ActsAsXapian::update_index, we can just fail silently if
+ # another process has inserted an acts_as_xapian_jobs record for this model.
+ raise unless (e.message =~ /duplicate key value violates unique constraint "index_acts_as_xapian_jobs_on_model_and_model_id"/)
end
end
+
+ # A hook method that can be used in tests to simulate e.g. an external process inserting a record
+ def xapian_before_create_job_hook(action, model, model_id)
+ end
+
end
######################################################################