aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/assets/stylesheets/responsive/_attachments_layout.scss10
-rw-r--r--app/controllers/api_controller.rb166
-rw-r--r--app/models/info_request.rb10
-rw-r--r--app/views/admin_general/index.html.erb2
-rw-r--r--app/views/request/_sidebar_request_listing.html.erb2
-rw-r--r--app/views/request/_view_html_stylesheet.html.erb13
-rwxr-xr-xconfig/alert-tracks-debian.ugly13
-rw-r--r--config/deploy.rb2
-rw-r--r--config/general.yml-example1
-rw-r--r--config/httpd-force-ssl.conf.example5
-rw-r--r--config/httpd-ssl.conf.example24
-rw-r--r--config/httpd.conf-example222
-rw-r--r--config/packages55
-rw-r--r--config/packages.debian-squeeze57
-rw-r--r--config/packages.debian-wheezy50
-rw-r--r--config/packages.ubuntu-precise48
-rwxr-xr-x[-rw-r--r--]config/purge-varnish-debian.ugly12
-rw-r--r--config/routes.rb1
-rwxr-xr-xconfig/sysvinit-passenger.ugly59
-rwxr-xr-xconfig/sysvinit-thin.ugly68
-rwxr-xr-xconfig/sysvinit.example53
-rw-r--r--db/migrate/20140801132719_add_index_to_info_request_events.rb5
-rw-r--r--doc/CHANGES.md5
-rw-r--r--lib/tasks/config_files.rake32
-rw-r--r--lib/tasks/stats.rake4
-rw-r--r--locale/ca/app.po383
-rw-r--r--locale/cy/app.po6
-rw-r--r--public/down.default.html13
-rwxr-xr-xscript/site-specific-install.sh11
-rw-r--r--spec/controllers/api_controller_spec.rb832
30 files changed, 1287 insertions, 877 deletions
diff --git a/app/assets/stylesheets/responsive/_attachments_layout.scss b/app/assets/stylesheets/responsive/_attachments_layout.scss
index 1eedc601b..070c288b8 100644
--- a/app/assets/stylesheets/responsive/_attachments_layout.scss
+++ b/app/assets/stylesheets/responsive/_attachments_layout.scss
@@ -61,6 +61,14 @@
}
}
-
+#wrapper_google_embed iframe {
+ min-height: 400px;
+ @include respond-min($main_menu-mobile_menu_cutoff ){
+ min-height: 800px;
+ @include lte-ie7{
+ height:800px !important;
+ }
+ }
+}
diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb
index e6b0c121a..6f83d89d6 100644
--- a/app/controllers/api_controller.rb
+++ b/app/controllers/api_controller.rb
@@ -1,5 +1,9 @@
class ApiController < ApplicationController
before_filter :check_api_key
+ before_filter :check_external_request,
+ :only => [:add_correspondence, :update_state]
+ before_filter :check_request_ownership,
+ :only => [:add_correspondence, :update_state]
def show_request
@request = InfoRequest.find(params[:id])
@@ -9,16 +13,11 @@ class ApiController < ApplicationController
:id => @request.id,
:url => make_url("request", @request.url_title),
:title => @request.title,
-
:created_at => @request.created_at,
:updated_at => @request.updated_at,
-
:status => @request.calculate_status,
-
:public_body_url => make_url("body", @request.public_body.url_name),
-
:request_email => @request.incoming_email,
-
:request_text => @request.last_event_forming_initial_request.outgoing_message.body,
}
if @request.user
@@ -73,35 +72,19 @@ class ApiController < ApplicationController
'url' => make_url("request", request.url_title),
'id' => request.id
}
-
end
def add_correspondence
- request = InfoRequest.find_by_id(params[:id])
- if request.nil?
- render :json => { "errors" => ["Could not find request #{params[:id]}"] }, :status => 404
- return
- end
-
json = ActiveSupport::JSON.decode(params[:correspondence_json])
attachments = params[:attachments]
direction = json["direction"]
body = json["body"]
sent_at = json["sent_at"]
+ new_state = params["state"]
errors = []
- if !request.is_external?
- render :json => { "errors" => ["Request #{params[:id]} cannot be updated using the API"] }, :status => 500
- return
- end
-
- if request.public_body_id != @public_body.id
- render :json => { "errors" => ["You do not own request #{params[:id]}"] }, :status => 500
- return
- end
-
if !["request", "response"].include?(direction)
errors << "The direction parameter must be 'request' or 'response'"
end
@@ -116,6 +99,10 @@ class ApiController < ApplicationController
errors << "You cannot attach files to messages in the 'request' direction"
end
+ if new_state && !InfoRequest.allowed_incoming_states.include?(new_state)
+ errors << "'#{new_state}' is not a valid request state"
+ end
+
if !errors.empty?
render :json => { "errors" => errors }, :status => 500
return
@@ -125,16 +112,16 @@ class ApiController < ApplicationController
# In the 'request' direction, i.e. what we (Alaveteli) regard as outgoing
outgoing_message = OutgoingMessage.new(
- :info_request => request,
+ :info_request => @request,
:status => 'ready',
:message_type => 'followup',
:body => body,
:last_sent_at => sent_at,
:what_doing => 'normal_sort'
)
- request.outgoing_messages << outgoing_message
- request.save!
- request.log_event("followup_sent",
+ @request.outgoing_messages << outgoing_message
+ @request.save!
+ @request.log_event("followup_sent",
:api => true,
:email => nil,
:outgoing_message_id => outgoing_message.id,
@@ -154,12 +141,48 @@ class ApiController < ApplicationController
)
end
- mail = RequestMailer.external_response(request, body, sent_at, attachment_hashes)
+ mail = RequestMailer.external_response(@request, body, sent_at, attachment_hashes)
+
+ @request.receive(mail, mail.encoded, true)
- request.receive(mail, mail.encoded, true)
+ if new_state
+ # we've already checked above that the status is valid
+ # so no need to check a second time
+ event = @request.log_event("status_update",
+ { :script => "#{@public_body.name} via API",
+ :old_described_state => @request.described_state,
+ :described_state => new_state,
+ })
+ @request.set_described_state(new_state)
+ end
end
render :json => {
- 'url' => make_url("request", request.url_title),
+ 'url' => make_url("request", @request.url_title),
+ }
+ end
+
+ def update_state
+ new_state = params["state"]
+
+ if InfoRequest.allowed_incoming_states.include?(new_state)
+ ActiveRecord::Base.transaction do
+ event = @request.log_event("status_update",
+ { :script => "#{@public_body.name} on behalf of requester via API",
+ :old_described_state => @request.described_state,
+ :described_state => new_state,
+ })
+ @request.set_described_state(new_state)
+ end
+ else
+ render :json => {
+ "errors" => ["'#{new_state}' is not a valid request state" ]
+ },
+ :status => 500
+ return
+ end
+
+ render :json => {
+ 'url' => make_url("request", @request.url_title),
}
end
@@ -168,51 +191,48 @@ class ApiController < ApplicationController
raise PermissionDenied.new("#{@public_body.id} != #{params[:id]}") if @public_body.id != params[:id].to_i
since_date_str = params[:since_date]
- if since_date_str.nil?
- @events = InfoRequestEvent.find_by_sql([
- %(select info_request_events.*
- from info_requests
- join info_request_events on info_requests.id = info_request_events.info_request_id
- where info_requests.public_body_id = ?
- and info_request_events.event_type in (
- 'sent', 'followup_sent', 'resent', 'followup_resent'
- )
- order by info_request_events.created_at desc
- ), @public_body.id
- ])
- else
+ since_event_id = params[:since_event_id]
+
+ event_type_clause = "event_type in ('sent', 'followup_sent', 'resent', 'followup_resent')"
+
+ @events = InfoRequestEvent.where(event_type_clause) \
+ .joins(:info_request) \
+ .where("public_body_id = ?", @public_body.id) \
+ .includes([{:info_request => :user}, :outgoing_message]) \
+ .order('info_request_events.created_at DESC')
+
+ if since_date_str
begin
- since_date = Date.strptime(since_date_str, "%Y-%m-%d")
+ since_date = Date.strptime(since_date_str, "%Y-%m-%d")
rescue ArgumentError
- render :json => {"errors" => [
- "Parameter since_date must be in format yyyy-mm-dd (not '#{since_date_str}')" ] },
- :status => 500
- return
+ render :json => {"errors" => [
+ "Parameter since_date must be in format yyyy-mm-dd (not '#{since_date_str}')" ] },
+ :status => 500
+ return
end
- @events = InfoRequestEvent.find_by_sql([
- %(select info_request_events.*
- from info_requests
- join info_request_events on info_requests.id = info_request_events.info_request_id
- where info_requests.public_body_id = ?
- and info_request_events.event_type in (
- 'sent', 'followup_sent', 'resent', 'followup_resent'
- )
- and info_request_events.created_at >= ?
- order by info_request_events.created_at desc
- ), @public_body.id, since_date
- ])
+ @events = @events.where("info_request_events.created_at >= ?", since_date)
+ end
+
+ # We take a "since" parameter that allows the client
+ # to restrict to events more recent than a certain other event
+ if since_event_id
+ begin
+ event = InfoRequestEvent.find(since_event_id)
+ rescue ActiveRecord::RecordNotFound
+ render :json => {"errors" => [
+ "Event ID #{since_event_id} not found" ] },
+ :status => 500
+ return
+ end
+ @events = @events.where("info_request_events.created_at > ?", event.created_at)
end
+
+
if feed_type == "atom"
render :template => "api/request_events", :formats => ['atom'], :layout => false
elsif feed_type == "json"
- # For the JSON feed, we take a "since" parameter that allows the client
- # to restrict to events more recent than a certain other event
- if params[:since_event_id]
- @since_event_id = params[:since_event_id].to_i
- end
@event_data = []
@events.each do |event|
- break if event.id == @since_event_id
request = event.info_request
this_event = {
@@ -224,7 +244,6 @@ class ApiController < ApplicationController
:request_email => request.incoming_email,
:title => request.title,
:body => event.outgoing_message.body,
-
:user_name => request.user_name,
}
if request.user
@@ -246,6 +265,21 @@ class ApiController < ApplicationController
raise PermissionDenied if @public_body.nil?
end
+ def check_external_request
+ @request = InfoRequest.find_by_id(params[:id])
+ if @request.nil?
+ render :json => { "errors" => ["Could not find request #{params[:id]}"] }, :status => 404
+ elsif !@request.is_external?
+ render :json => { "errors" => ["Request #{params[:id]} cannot be updated using the API"] }, :status => 403
+ end
+ end
+
+ def check_request_ownership
+ if @request.public_body_id != @public_body.id
+ render :json => { "errors" => ["You do not own request #{params[:id]}"] }, :status => 403
+ end
+ end
+
private
def make_url(*args)
"http://" + AlaveteliConfiguration::domain + "/" + args.join("/")
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index a2112a210..aed651ad3 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -115,6 +115,16 @@ class InfoRequest < ActiveRecord::Base
states
end
+ # Subset of states accepted via the API
+ def self.allowed_incoming_states
+ [
+ 'waiting_response',
+ 'rejected',
+ 'successful',
+ 'partially_successful'
+ ]
+ end
+
# Possible reasons that a request could be reported for administrator attention
def report_reasons
[_("Contains defamatory material"),
diff --git a/app/views/admin_general/index.html.erb b/app/views/admin_general/index.html.erb
index 2202663be..f29258162 100644
--- a/app/views/admin_general/index.html.erb
+++ b/app/views/admin_general/index.html.erb
@@ -39,7 +39,7 @@
<% if message.get_body_for_quoting.strip.size == 0 %>
<%= link_to "(no body)", admin_request_show_raw_email_path(message.raw_email_id) %>
<% else %>
- <%= link_to excerpt(message.get_body_for_quoting, "", 60), admin_request_show_raw_email_path(message.raw_email_id) %>
+ <%= link_to excerpt(message.get_body_for_quoting, "", :radius => 60), admin_request_show_raw_email_path(message.raw_email_id) %>
<% end %>
</td>
<td class="span2">
diff --git a/app/views/request/_sidebar_request_listing.html.erb b/app/views/request/_sidebar_request_listing.html.erb
index ec5a5813d..64fe39341 100644
--- a/app/views/request/_sidebar_request_listing.html.erb
+++ b/app/views/request/_sidebar_request_listing.html.erb
@@ -4,7 +4,7 @@
<%= request_link(info_request) %>
</span>
<span class="desc">
- <%=h excerpt(info_request.initial_request_text, "", 100) %>
+ <%=h excerpt(info_request.initial_request_text, "", :radius => 100) %>
</span>
<span class="bottomline">
<strong>
diff --git a/app/views/request/_view_html_stylesheet.html.erb b/app/views/request/_view_html_stylesheet.html.erb
index 6746cf71b..f3d8799da 100644
--- a/app/views/request/_view_html_stylesheet.html.erb
+++ b/app/views/request/_view_html_stylesheet.html.erb
@@ -1,5 +1,16 @@
<% if AlaveteliConfiguration::responsive_styling || params[:responsive] %>
- <%= render :partial => 'general/responsive_stylesheets' %>
+ <!--[if LTE IE 7]>
+ <link href="/assets/responsive/application-lte-ie7.css" media="all" rel="stylesheet" title="Main" type="text/css" />
+ <![endif]-->
+
+ <!--[if IE 8]>
+ <link href="/assets/responsive/application-ie8.css" media="all" rel="stylesheet" title="Main" type="text/css" />
+ <![endif]-->
+
+ <!--[if GT IE 8]><!-->
+ <link href="/assets/responsive/application.css" media="all" rel="stylesheet" title="Main" type="text/css" />
+ <!--<![endif]-->
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<% else %>
<link type="text/css" title="Main" rel="stylesheet" media="screen" href="/assets/application.css">
diff --git a/config/alert-tracks-debian.ugly b/config/alert-tracks-debian.ugly
index c7d82d8c8..f1ca68b03 100755
--- a/config/alert-tracks-debian.ugly
+++ b/config/alert-tracks-debian.ugly
@@ -13,10 +13,12 @@
# !!(*= $daemon_name *)!! Start the Alaveteli email alert daemon
NAME=!!(*= $daemon_name *)!!
-DAEMON=!!(*= $vhost_dir *)!!/alaveteli/script/runner
+DAEMON=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/runner
DAEMON_ARGS="--daemon TrackMailer.alert_tracks_loop"
-PIDFILE=!!(*= $vhost_dir *)!!/alert-tracks.pid
-LOGFILE=!!(*= $vhost_dir *)!!/alaveteli/log/alert-tracks.log
+PIDDIR=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/tmp/pids
+PIDFILE=$PIDDIR/!!(*= $daemon_name *)!!.pid
+LOGDIR=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/log
+LOGFILE=$LOGDIR/!!(*= $daemon_name *)!!.log
DUSER=!!(*= $user *)!!
# Set RAILS_ENV - not needed if using config/rails_env.rb
# RAILS_ENV=your_rails_env
@@ -27,10 +29,14 @@ trap "" 1
export PIDFILE LOGFILE
quietly_start_daemon() {
+ mkdir -p {$LOGDIR,$PIDDIR}
+ chown $DUSER:$DUSER {$LOGDIR,$PIDDIR}
/sbin/start-stop-daemon --quiet --start --pidfile "$PIDFILE" --chuid "$DUSER" --startas "$DAEMON" -- $DAEMON_ARGS
}
start_daemon() {
+ mkdir -p {$LOGDIR,$PIDDIR}
+ chown $DUSER:$DUSER {$LOGDIR,$PIDDIR}
/sbin/start-stop-daemon --start --pidfile "$PIDFILE" --chuid "$DUSER" --startas "$DAEMON" -- $DAEMON_ARGS
}
@@ -81,4 +87,3 @@ else
echo " failed"
exit 1
fi
-
diff --git a/config/deploy.rb b/config/deploy.rb
index 9cc847dba..afc586ecf 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -57,6 +57,7 @@ namespace :deploy do
"#{release_path}/files" => "#{shared_path}/files",
"#{release_path}/cache" => "#{shared_path}/cache",
"#{release_path}/log" => "#{shared_path}/log",
+ "#{release_path}/tmp/pids" => "#{shared_path}/tmp/pids",
"#{release_path}/lib/acts_as_xapian/xapiandbs" => "#{shared_path}/xapiandbs",
}
@@ -68,6 +69,7 @@ namespace :deploy do
run "mkdir -p #{shared_path}/files"
run "mkdir -p #{shared_path}/cache"
run "mkdir -p #{shared_path}/log"
+ run "mkdir -p #{shared_path}/tmp/pids"
run "mkdir -p #{shared_path}/xapiandbs"
end
end
diff --git a/config/general.yml-example b/config/general.yml-example
index a6f68c52e..0f32f6192 100644
--- a/config/general.yml-example
+++ b/config/general.yml-example
@@ -246,6 +246,7 @@ SHARED_DIRECTORIES:
- cache/
- lib/acts_as_xapian/xapiandbs/
- log/
+ - tmp/pids
- vendor/bundle
- public/assets
diff --git a/config/httpd-force-ssl.conf.example b/config/httpd-force-ssl.conf.example
new file mode 100644
index 000000000..0e89afe62
--- /dev/null
+++ b/config/httpd-force-ssl.conf.example
@@ -0,0 +1,5 @@
+# Rewrite all proxied HTTP requests to HTTPS.
+# Only include if FORCE_SSL: true is set in general.yml
+# Expected to be found at /etc/apache2/vhost.d/alaveteli
+RewriteCond %{HTTP:X-Forwarded-Proto} !https
+RewriteRule /(.*) https://www.example.com/$1 [L,R=permanent]
diff --git a/config/httpd-ssl.conf.example b/config/httpd-ssl.conf.example
new file mode 100644
index 000000000..8f099b8a6
--- /dev/null
+++ b/config/httpd-ssl.conf.example
@@ -0,0 +1,24 @@
+# VirtualHost for HTTPS requests
+<VirtualHost *:443>
+ ServerName www.example.com
+
+ ErrorLog /var/log/apache2/alaveteli_error.log
+ CustomLog /var/log/apache2/alaveteli_access.log combined
+
+ ProxyRequests Off
+ ProxyPreserveHost On
+ ProxyPass / http://localhost:80/
+ ProxyPassReverse / http://localhost:80/
+ RequestHeader set X-Forwarded-Proto 'https'
+
+ SSLEngine on
+ SSLProtocol all -SSLv2
+ SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM
+
+ SSLCertificateFile /etc/ssl/certs/www.example.com.cert
+ SSLCertificateKeyFile /etc/ssl/private/www.example.com.key
+ # SSLCertificateChainFile /etc/ssl/sub.class2.server.ca.pem
+ # SSLCACertificateFile /etc/ssl/ca.pem
+
+ SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
+</VirtualHost>
diff --git a/config/httpd.conf-example b/config/httpd.conf-example
index 8d549d363..9736cafff 100644
--- a/config/httpd.conf-example
+++ b/config/httpd.conf-example
@@ -1,81 +1,145 @@
-# Apache configuration for FOI site.
-#
-# For development ignore this, you can just run ./scripts/server as for any
-# Ruby on Rails application.
-#
-# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: hello@mysociety.org; WWW: http://www.mysociety.org
-
-# This is needed for the PHP spell checker
-<Location /fcgi>
- Options +ExecCGI
- SetHandler fastcgi-script
-</Location>
-
-RewriteEngine On
-#RewriteLog /var/log/apache2/rewrite.log
-#RewriteLogLevel 9
-
-# TODO: do we need this now we use Passenger?
-# Pass through the HTTP basic authentication to mongrel. See also
-# admin_http_auth_user in app/controllers/application.rb
-# Note: Apache 2 only. Doesn't work in Apache 1.3, you'll need to live without
-# it.
-RewriteCond %{LA-U:REMOTE_USER} (.+)
-RewriteRule . - [E=RU:%1]
-RequestHeader add X-Forwarded-User %{RU}e
-
-# Old /files URL to new subdomain (as can't use Alias with passenger,
-# so we do it on its own domain). This is for custom admin upload
-# files for archiving.
-RewriteRule /files/(.+) http://files.whatdotheyknow.com/$1
-
-# Serve attachments directly from the cache, if possible.
-#
-# The file names are URL-encoded on disk, and sharded by the first
-# three digits of the request id, which is why this is as complicated
-# as it is. The RewriteMap directive makes the URL-escaping function
-# available to use in the other directives.
-#
-# The condition means that the rule will fire only if the cached
-# file exists.
-RewriteMap escape int:escape
-RewriteCond %{DOCUMENT_ROOT}/views_cache/request/$2/$1/${escape:$3} -f
-RewriteRule ^/request/((\d{1,3})\d*)/(response/\d+/attach/(html/)?\d+/.+) /views_cache/request/$2/$1/${escape:$3} [L]
-
-
-<IfModule mod_passenger.c>
- # Set this to something like 100 if you have memory leak issues
- PassengerMaxRequests 500
- PassengerResolveSymlinksInDocumentRoot on
- # Recommend setting this to 3 or less on servers with 512MB RAM
- PassengerMaxPoolSize 6
- # The RackEnv variable applies to Rails 3 applications, while
- # the RailsEnv variable applies to applications for earlier
- # versions of Rails. There doesn't seem to be any harm in
- # setting both, however.
- RailsEnv production
- RackEnv production
-</IfModule>
-
-# Gzip font resources
-<IfModule mod_deflate.c>
- <IfModule mod_mime.c>
- Addtype font/opentype .otf
- Addtype font/opentype .woff
- Addtype font/eot .eot
- Addtype font/truetype .ttf
+# Redirect other domains to canonical domain
+<VirtualHost *:80>
+ ServerName example.com
+ ServerAlias example.org
+ ServerAlias www.example.org
+ RedirectPermanent / http://www.example.com/
+</VirtualHost>
+
+# Canonical domain vHost
+<VirtualHost *:80>
+ ServerName www.example.com
+ ServerAdmin webmaster@example.com
+ DocumentRoot /var/www/alaveteli/public
+
+ # TODO: Remove this and use PassengerUser when supported
+ # This is the user that runs the rails application processes
+ SuExecUserGroup alaveteli alaveteli
+ RewriteEngine On
+
+ ErrorLog /var/log/apache2/alaveteli_error.log
+ CustomLog /var/log/apache2/alaveteli_access.log combined
+
+ # App server configuration
+ <IfModule mod_passenger.c>
+ PassengerAppRoot /var/www/alaveteli
+ PassengerResolveSymlinksInDocumentRoot on
+
+ # See http://blog.phusion.nl/2013/03/12/tuning-phusion-passengers-concurrency-settings/
+ # and http://blog.scoutapp.com/articles/2009/12/08/production-rails-tuning-with-passenger-passengermaxprocesses
+ # for more information on tuning Passenger
+
+ # Set this to something like 100 if you have memory leak issues
+ PassengerMaxRequests 2000
+ # Passenger's default MaxPoolSize is 6. At the time of writing
+ # normal instances of Alaveteli seem to take 150-200MB per
+ # process, so we've set this conservatively at 3. Read the guides
+ # above to tune this for your system
+ PassengerMaxPoolSize 3
+
+ # The RAILS_ENV that the app is running in. This can be any of
+ # the environments listed in APP_ROOT/config/environments.
+ RailsEnv production
+ RackEnv production
</IfModule>
- AddOutputFilterByType DEFLATE font/opentype font/truetype font/eot
- AddOutputFilterByType DEFLATE image/svg+xml
-</IFModule>
-
-# Set the Sendfile header and switch sendfile on - Apache will
-# now handle send_file calls from Alaveteli
-<Location />
- <IfModule mod_xsendfile.c>
- RequestHeader Set X-Sendfile-Type X-Sendfile
- XSendFile On
- XSendFileAllowAbove On
+
+ # This is your Rails app's public directory
+ <Directory "/var/www/alaveteli/public">
+ Options +ExecCGI -MultiViews
+ AllowOverride All
+ </Directory>
+
+ # Maintenance Page
+ # Make a file down.html in the DocumentRoot to bring down the whole
+ # site and display itself.
+ RewriteEngine on
+ ErrorDocument 503 /down.html
+ Redirect 503 /down
+
+ # If down.html exists, and that's what's been asked for,
+ # just hand it over
+ RewriteCond %{DOCUMENT_ROOT}/down.html -s
+ RewriteRule /down.html /down.html [L]
+
+ RewriteCond %{DOCUMENT_ROOT}/down.html -s
+ RewriteRule /(.+).cgi /down [PT]
+ RewriteCond %{DOCUMENT_ROOT}/down.html -s
+ RewriteRule /(.+).php /down [PT]
+ # Mainly for Rails/Django type sites - anything without a . can go down
+ # TODO: could we just check that it is an HTML content-type?
+ RewriteCond %{DOCUMENT_ROOT}/down.html -s
+ RewriteRule /([^.]*)$ /down [PT]
+ # END Maintenance Page
+
+ # Set the Sendfile header and switch sendfile on - Apache will
+ # now handle send_file calls from Alaveteli
+ <Location />
+ <IfModule mod_xsendfile.c>
+ RequestHeader Set X-Sendfile-Type X-Sendfile
+ XSendFile On
+ XSendFilePath /var/www/alaveteli/public
+ </IfModule>
+ </Location>
+
+ # Commonlib is typically found in alaveteli/commonlib
+ Alias /jslib/ "/var/www/alaveteli/commonlib/jslib"
+ <Directory "/var/www/alaveteli/commonlib/jslib">
+ Options +ExecCGI
+ AddHandler fastcgi-script .cgi
+ </Directory>
+
+ # Serve attachments directly from the cache, if possible.
+ #
+ # The file names are URL-encoded on disk, and sharded by the first
+ # three digits of the request id, which is why this is as complicated
+ # as it is. The RewriteMap directive makes the URL-escaping function
+ # available to use in the other directives.
+ #
+ # The condition means that the rule will fire only if the cached
+ # file exists.
+ RewriteMap escape int:escape
+ RewriteCond %{DOCUMENT_ROOT}/views_cache/request/$2/$1/${escape:$3} -f
+ RewriteRule ^/request/((\d{1,3})\d*)/(response/\d+/attach/(html/)?\d+/.+) /views_cache/request/$2/$1/${escape:$3} [L]
+ RewriteCond %{DOCUMENT_ROOT}/views_cache/cy/request/$2/$1/${escape:$3} -f
+ RewriteRule ^/cy/request/((\d{1,3})\d*)/(response/\d+/attach/(html/)?\d+/.+) /views_cache/cy/request/$2/$1/${escape:$3} [L]
+
+ # Compress assets
+ <Location />
+ <IfModule mod_deflate.c>
+ AddOutputFilterByType DEFLATE text/css application/javascript text/plain
+ </IfModule>
+ </Location>
+
+ # Cache assets
+ ExpiresActive On
+ <LocationMatch "^/(assets).*\.(ico|gif|jpe?g|png|js|css|svg|ttf|otf|eot|woff)$">
+ ExpiresDefault "access plus 1 day"
+ </LocationMatch>
+
+ # Compress font resources
+ <IfModule mod_deflate.c>
+ <IfModule mod_mime.c>
+ Addtype font/opentype .otf
+ Addtype font/opentype .woff
+ Addtype font/eot .eot
+ Addtype font/truetype .ttf
+ </IfModule>
+ AddOutputFilterByType DEFLATE font/opentype font/truetype font/eot
+ AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>
-</Location>
+
+ # Include optional configuration
+ Include vhost.d/alaveteli
+
+</VirtualHost>
+
+# Large / static files for WhatDoTheyKnow. Used for manual sysadmin uploads.
+# Is on its own files.example.com subdomain (instead of old /files URL)
+# as mod_alias doesn't work with Passenger.
+# <VirtualHost *:80>
+# ServerName files.example.com
+# DocumentRoot /var/www/alaveteli/files
+# <Directory "/var/www/alaveteli/files">
+# Options +Indexes
+# </Directory>
+# </VirtualHost>
diff --git a/config/packages b/config/packages
index fda09cbc1..e11fa1d52 100644
--- a/config/packages
+++ b/config/packages
@@ -1,42 +1,43 @@
# please note that this package list currently forms part of the
# mysociety deployment infrastructure -- please discuss on the
# alavateli mailing list if you want to change it
-ruby1.8
-ruby
-rdoc | rdoc1.8
-irb | irb1.8
-wv
-poppler-utils
-pdftk (>> 1.41+dfsg-1) | pdftk (<< 1.41+dfsg-1) # that version has a non-functionining uncompress option
-ghostscript
+build-essential
+bundler
catdoc
-links
elinks
-unrtf
-xlhtml
-xapian-tools
-gnuplot-nox
-php5-cli
-sharutils
-unzip
-mutt
-tnef (>= 1.4.5)
gettext
-python-yaml
-wkhtmltopdf-static
+ghostscript
+gnuplot-nox
+irb | irb1.8
+libapache2-mod-passenger
+libicu-dev
libmagic-dev
libmagickwand-dev
libpq-dev
+libsqlite3-dev
libxml2-dev
libxslt-dev
-uuid-dev
+links
+memcached
+mutt
+pdftk (>> 1.41+dfsg-1) | pdftk (<< 1.41+dfsg-1) # that version has a non-functionining uncompress option
+php5-cli
+poppler-utils
+python-yaml
+rake (>= 0.9.2.2)
+rdoc | rdoc1.8
+ruby
+ruby1.8
ruby1.8-dev
rubygems (>= 1.8.15)
-rake (>= 0.9.2.2)
-build-essential
-bundler
+sharutils
sqlite3
-libsqlite3-dev
-libicu-dev
-memcached
+tnef (>= 1.4.5)
ttf-bitstream-vera
+unrtf
+unzip
+uuid-dev
+wkhtmltopdf-static
+wv
+xapian-tools
+xlhtml
diff --git a/config/packages.debian-squeeze b/config/packages.debian-squeeze
index d82d66324..52bdbc376 100644
--- a/config/packages.debian-squeeze
+++ b/config/packages.debian-squeeze
@@ -1,40 +1,41 @@
-ruby1.8
-ruby
-libruby1.8
-rdoc1.8
-irb1.8
-wv
-poppler-utils
-pdftk
-ghostscript
+build-essential
+bundler
catdoc
-links
elinks
-unrtf
-xlhtml
-xapian-tools
-gnuplot-nox
-php5-cli
-sharutils
-unzip
-mutt
-tnef
gettext
-python-yaml
-wkhtmltopdf-static
+ghostscript
+gnuplot-nox
+irb1.8
+libicu-dev
libmagic-dev
libmagickwand-dev
libpq-dev
+libruby1.8
+libsqlite3-dev
libxml2-dev
libxslt-dev
-uuid-dev
+links
+mutt
+pdftk
+php5-cli
+poppler-utils
+postgresql
+postgresql-client
+python-yaml
+rake
+rdoc1.8
+ruby
+ruby1.8
ruby1.8-dev
rubygems/squeeze-backports
-rake
-build-essential
+sharutils
sqlite3
-libsqlite3-dev
-libicu-dev
-postgresql
-postgresql-client
+tnef
ttf-bitstream-vera
+unrtf
+unzip
+uuid-dev
+wkhtmltopdf-static
+wv
+xapian-tools
+xlhtml
diff --git a/config/packages.debian-wheezy b/config/packages.debian-wheezy
index 509cde56e..381e25daa 100644
--- a/config/packages.debian-wheezy
+++ b/config/packages.debian-wheezy
@@ -1,36 +1,36 @@
-ruby1.9.3
-wv
-poppler-utils
-pdftk
-ghostscript
+build-essential
+bundler
catdoc
-links
elinks
-unrtf
-xlhtml
-xapian-tools
-gnuplot-nox
-php5-cli
-sharutils
-unzip
-mutt
-tnef
gettext
-python-yaml
-wkhtmltopdf-static
+ghostscript
+gnuplot-nox
+libicu-dev
libmagic-dev
libmagickwand-dev
libpq-dev
+libsqlite3-dev
libxml2-dev
libxslt-dev
-uuid-dev
+links
+mutt
+pdftk
+php5-cli
+poppler-utils
+postgresql
+postgresql-client
+python-yaml
+rake
ruby-dev
+ruby1.9.3
rubygems
-rake
-build-essential
-bundler
+sharutils
sqlite3
-libsqlite3-dev
-libicu-dev
-postgresql
-postgresql-client
+tnef
+unrtf
+unzip
+uuid-dev
+wkhtmltopdf-static
+wv
+xapian-tools
+xlhtml
diff --git a/config/packages.ubuntu-precise b/config/packages.ubuntu-precise
index 68911359a..87b9591bf 100644
--- a/config/packages.ubuntu-precise
+++ b/config/packages.ubuntu-precise
@@ -1,36 +1,36 @@
-ruby1.9.1
-wv
-poppler-utils
-pdftk
-ghostscript
+build-essential
catdoc
-links
elinks
-unrtf
-xlhtml
-xapian-tools
-gnuplot-nox
-sharutils
-unzip
-mutt
-tnef
gettext
-python-yaml
-wkhtmltopdf-static
+ghostscript
+gnuplot-nox
+libicu-dev
libmagic-dev
libmagickwand-dev
libpq-dev
+libsqlite3-dev
libxml2-dev
libxslt1-dev
-uuid-dev
-ruby1.9.1-dev
-rubygems
+links
+mutt
+pdftk
+poppler-utils
+postgresql
+postgresql-client
+python-yaml
rake
-build-essential
ruby-bundler
+ruby1.9.1
+ruby1.9.1-dev
+rubygems
+sharutils
sqlite3
-libsqlite3-dev
-libicu-dev
-postgresql
-postgresql-client
+tnef
ttf-bitstream-vera
+unrtf
+unzip
+uuid-dev
+wkhtmltopdf-static
+wv
+xapian-tools
+xlhtml
diff --git a/config/purge-varnish-debian.ugly b/config/purge-varnish-debian.ugly
index ebd4d9e5c..dc3f74ff6 100644..100755
--- a/config/purge-varnish-debian.ugly
+++ b/config/purge-varnish-debian.ugly
@@ -13,10 +13,12 @@
# !!(*= $daemon_name *)!! Start the Alaveteli email purge-varnish daemon
NAME=!!(*= $daemon_name *)!!
-DAEMON=!!(*= $vhost_dir *)!!/alaveteli/script/runner
+DAEMON=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/runner
DAEMON_ARGS="--daemon PurgeRequest.purge_all_loop"
-PIDFILE=!!(*= $vhost_dir *)!!/purge-varnish.pid
-LOGFILE=!!(*= $vhost_dir *)!!/alaveteli/log/purge-varnish.log
+PIDDIR=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/tmp/pids
+PIDFILE=$PIDDIR/!!(*= $daemon_name *)!!.pid
+LOGDIR=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/log
+LOGFILE=$LOGDIR/!!(*= $daemon_name *)!!.log
DUSER=!!(*= $user *)!!
# Set RAILS_ENV - not needed if using config/rails_env.rb
# RAILS_ENV=your_rails_env
@@ -29,10 +31,14 @@ trap "" 1
export PIDFILE LOGFILE
quietly_start_daemon() {
+ mkdir -p {$LOGDIR,$PIDDIR}
+ chown $DUSER:$DUSER {$LOGDIR,$PIDDIR}
/sbin/start-stop-daemon --quiet --start --pidfile "$PIDFILE" --chuid "$DUSER" --startas "$DAEMON" -- $DAEMON_ARGS
}
start_daemon() {
+ mkdir -p {$LOGDIR,$PIDDIR}
+ chown $DUSER:$DUSER {$LOGDIR,$PIDDIR}
/sbin/start-stop-daemon --start --pidfile "$PIDFILE" --chuid "$DUSER" --startas "$DAEMON" -- $DAEMON_ARGS
}
diff --git a/config/routes.rb b/config/routes.rb
index 7cc85c974..9f426fabf 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -261,6 +261,7 @@ Alaveteli::Application.routes.draw do
match '/api/v2/request/:id.json' => 'api#show_request', :as => :api_show_request, :via => :get
match '/api/v2/request/:id.json' => 'api#add_correspondence', :as => :api_add_correspondence, :via => :post
+ match '/api/v2/request/:id/update.json' => 'api#update_state', :as => :api_update_state, :via => :post
match '/api/v2/body/:id/request_events.:feed_type' => 'api#body_request_events', :as => :api_body_request_events, :feed_type => '^(json|atom)$'
####
diff --git a/config/sysvinit-passenger.ugly b/config/sysvinit-passenger.ugly
new file mode 100755
index 000000000..0940a4d63
--- /dev/null
+++ b/config/sysvinit-passenger.ugly
@@ -0,0 +1,59 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: application-passenger-!!(*= $site *)!!
+# Required-Start: $local_fs $network
+# Required-Stop: $local_fs $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Starts the Passenger app server for the "!!(*= $site *)!!" site
+# Description: The Passenger app server for the "!!(*= $site *)!!" site
+### END INIT INFO
+
+# This example sysvinit script is based on the helpful example here:
+# http://richard.wallman.org.uk/2010/02/howto-deploy-a-catalyst-application-using-fastcgi-and-nginx/
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+NAME=!!(*= $site *)!!
+SITE_HOME=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!
+DESC="Alaveteli app server"
+USER=!!(*= $user *)!!
+
+set -e
+
+start_daemon() {
+ echo -n "Starting $DESC: "
+ rm -f "$SITE_HOME/public/down.html"
+ echo "$NAME."
+}
+
+stop_daemon() {
+ echo -n "Stopping $DESC: "
+ cp "$SITE_HOME/public/down.default.html" "$SITE_HOME/public/down.html"
+ echo "$NAME."
+}
+
+restart_daemon() {
+ echo -n "Restarting $DESC: "
+ rm -f "$SITE_HOME/public/down.html"
+ touch "$SITE_HOME/tmp/restart.txt"
+ echo "$NAME."
+}
+
+case "$1" in
+ start)
+ start_daemon
+ ;;
+ stop)
+ stop_daemon
+ ;;
+ reload|restart|force-reload)
+ restart_daemon
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ echo "Usage: $N {start|stop|reload|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/config/sysvinit-thin.ugly b/config/sysvinit-thin.ugly
new file mode 100755
index 000000000..cc604d994
--- /dev/null
+++ b/config/sysvinit-thin.ugly
@@ -0,0 +1,68 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: application-thin-!!(*= $site *)!!
+# Required-Start: $local_fs $network
+# Required-Stop: $local_fs $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Starts the Thin app server for the "!!(*= $site *)!!" site
+# Description: The Thin app server for the "!!(*= $site *)!!" site
+### END INIT INFO
+
+# This example sysvinit script is based on the helpful example here:
+# http://richard.wallman.org.uk/2010/02/howto-deploy-a-catalyst-application-using-fastcgi-and-nginx/
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+NAME=!!(*= $site *)!!
+SITE_HOME=!!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!
+DESC="Alaveteli app server"
+USER=!!(*= $user *)!!
+
+set -e
+
+# Check that the Daemon can be run
+su -l -c "cd $SITE_HOME && bundle exec thin --version &> /dev/null || exit 0" $USER
+
+start_daemon() {
+ echo -n "Starting $DESC: "
+ cd "$SITE_HOME" && bundle exec thin \
+ --environment=production \
+ --user="$USER" \
+ --group="$USER" \
+ --address=127.0.0.1 \
+ --daemonize \
+ --quiet \
+ start || true
+ echo "$NAME."
+}
+
+stop_daemon() {
+ echo -n "Stopping $DESC: "
+ cd "$SITE_HOME" && bundle exec thin --quiet stop || true
+ echo "$NAME."
+}
+
+restart_daemon() {
+ echo -n "Restarting $DESC: "
+ cd "$SITE_HOME" && bundle exec thin --onebyone --quiet restart || true
+ echo "$NAME."
+}
+
+case "$1" in
+ start)
+ start_daemon
+ ;;
+ stop)
+ stop_daemon
+ ;;
+ reload|restart|force-reload)
+ restart_daemon
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ echo "Usage: $N {start|stop|reload|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/config/sysvinit.example b/config/sysvinit.example
deleted file mode 100755
index 443e7c3fb..000000000
--- a/config/sysvinit.example
+++ /dev/null
@@ -1,53 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: application-thin-alaveteli
-# Required-Start: $local_fs $network
-# Required-Stop: $local_fs $network
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Starts the Thin web server for the "Alaveteli" site
-# Description: The Thin web server for the "Alaveteli" site
-### END INIT INFO
-
-# This example sysvinit script is based on the helpful example here:
-# http://richard.wallman.org.uk/2010/02/howto-deploy-a-catalyst-application-using-fastcgi-and-nginx/
-
-PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-SITE_HOME=/var/www/alaveteli
-NAME=alaveteli
-DESC="Alaveteli app server"
-USER=fms
-
-echo $DAEMON
-test -f $DAEMON || exit 0
-
-set -e
-
-start_daemon() {
- su -l -c "cd $SITE_HOME/alaveteli && bundle exec thin -d -p 3300 -e development start" $USER
-}
-
-stop_daemon() {
- pkill -f thin -u $USER || true
-}
-
-case "$1" in
- start)
- start_daemon
- ;;
- stop)
- stop_daemon
- ;;
- reload|restart|force-reload)
- stop_daemon
- sleep 5
- start_daemon
- ;;
- *)
- N=/etc/init.d/$NAME
- echo "Usage: $N {start|stop|reload|restart|force-reload}" >&2
- exit 1
- ;;
-esac
-
-exit 0
diff --git a/db/migrate/20140801132719_add_index_to_info_request_events.rb b/db/migrate/20140801132719_add_index_to_info_request_events.rb
new file mode 100644
index 000000000..5f0a77eac
--- /dev/null
+++ b/db/migrate/20140801132719_add_index_to_info_request_events.rb
@@ -0,0 +1,5 @@
+class AddIndexToInfoRequestEvents < ActiveRecord::Migration
+ def change
+ add_index :info_request_events, :event_type
+ end
+end
diff --git a/doc/CHANGES.md b/doc/CHANGES.md
index 0032706ef..61f55211c 100644
--- a/doc/CHANGES.md
+++ b/doc/CHANGES.md
@@ -4,6 +4,11 @@
## Upgrade Notes
+* The `SHARED_DIRECTORIES` setting now includes `tmp/pids`. The notes below for
+ updating the log directory should cover the update steps for `tmp/pids`.
+* Capistrano now creates `SHARED_PATH/tmp/pids` and links `APP_ROOT/tmp/pids`
+ here, as the alert tracks daemon writes its pids to the generally expected
+ location of `APP_ROOT/tmp/pids`.
* rails-post-deploy no longer handles linking `APP_ROOT/log` to a log directory
outside the app. Capistrano users will find that `:symlink_configuration` now
links `APP_ROOT/log` to `SHARED_PATH/log`. Users who aleady use the
diff --git a/lib/tasks/config_files.rake b/lib/tasks/config_files.rake
index 60814cb27..5dda64a04 100644
--- a/lib/tasks/config_files.rake
+++ b/lib/tasks/config_files.rake
@@ -23,26 +23,34 @@ namespace :config_files do
desc 'Convert Debian .ugly init script in config to a form suitable for installing in /etc/init.d'
task :convert_init_script => :environment do
- example = 'rake config_files:convert_init_script DEPLOY_USER=deploy VHOST_DIR=/dir/above/alaveteli SCRIPT_FILE=config/alert-tracks-debian.ugly '
- check_for_env_vars(['DEPLOY_USER', 'VHOST_DIR', 'SCRIPT_FILE'], example)
+ example = 'rake config_files:convert_init_script DEPLOY_USER=deploy VHOST_DIR=/dir/above/alaveteli VCSPATH=alaveteli SITE=alaveteli SCRIPT_FILE=config/alert-tracks-debian.ugly'
+ check_for_env_vars(['DEPLOY_USER',
+ 'VHOST_DIR',
+ 'SCRIPT_FILE'], example)
+
+ replacements = {
+ :user => ENV['DEPLOY_USER'],
+ :vhost_dir => ENV['VHOST_DIR'],
+ :vcspath => ENV.fetch('VCSPATH') { 'alaveteli' },
+ :site => ENV.fetch('SITE') { 'foi' }
+ }
- deploy_user = ENV['DEPLOY_USER']
- vhost_dir = ENV['VHOST_DIR']
- script_file = ENV['SCRIPT_FILE']
+ # Use the filename for the $daemon_name ugly variable
+ daemon_name = File.basename(ENV['SCRIPT_FILE'], '-debian.ugly')
+ replacements.update(:daemon_name => "#{ replacements[:site] }-#{ daemon_name }")
- replacements = { :user => deploy_user,
- :vhost_dir => vhost_dir }
+ # Generate the template for potential further processing
+ converted = convert_ugly(ENV['SCRIPT_FILE'], replacements)
- daemon_name = File.basename(script_file, '-debian.ugly')
- replacements.update(:daemon_name => "foi-#{daemon_name}")
- converted = convert_ugly(script_file, replacements)
- rails_env_file = File.expand_path(File.join(Rails.root, 'config', 'rails_env.rb'))
- if !File.exists?(rails_env_file)
+ # gsub the RAILS_ENV in to the generated template if its not set by the
+ # hard coded config file
+ unless File.exists?("#{ Rails.root }/config/rails_env.rb")
converted.each do |line|
line.gsub!(/^#\s*RAILS_ENV=your_rails_env/, "RAILS_ENV=#{Rails.env}")
line.gsub!(/^#\s*export RAILS_ENV/, "export RAILS_ENV")
end
end
+
converted.each do |line|
puts line
end
diff --git a/lib/tasks/stats.rake b/lib/tasks/stats.rake
index f09594529..46a645b4d 100644
--- a/lib/tasks/stats.rake
+++ b/lib/tasks/stats.rake
@@ -119,7 +119,7 @@ DESC
count ? count : 0
end
- row = [body.name] + stats
+ row = [%Q("#{ body.name }")] + stats
puts row.join(",")
end
end
@@ -147,7 +147,7 @@ DESC
count ? count : 0
end
- row = [body.name] + stats
+ row = [%Q("#{ body.name }")] + stats
puts row.join(",")
end
end
diff --git a/locale/ca/app.po b/locale/ca/app.po
index ae7cbc6d8..e33acf5cd 100644
--- a/locale/ca/app.po
+++ b/locale/ca/app.po
@@ -13,8 +13,8 @@ msgstr ""
"Project-Id-Version: alaveteli\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-05-15 12:46+0100\n"
-"PO-Revision-Date: 2014-05-15 11:56+0000\n"
-"Last-Translator: louisecrow <louise@mysociety.org>\n"
+"PO-Revision-Date: 2014-07-23 14:23+0000\n"
+"Last-Translator: David Cabo <david.cabo@gmail.com>\n"
"Language-Team: Catalan (http://www.transifex.com/projects/p/alaveteli/language/ca/)\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
@@ -48,7 +48,7 @@ msgstr ""
msgid " <strong>Note:</strong>\\n We will send you an email. Follow the instructions in it to change\\n your password."
msgstr ""
-" <strong>Nota::</strong>\n"
+" <strong>Nota:</strong>\n"
" T'enviarem un correu electrònic. Segueix les instruccions per canviar la teva contrasenya."
msgid " <strong>Privacy note:</strong> Your email address will be given to"
@@ -108,7 +108,7 @@ msgid " when you send this message."
msgstr " quan enviares aquest missatge."
msgid "'Crime statistics by ward level for Wales'"
-msgstr "'Estadístiques de crims per regió a Espanya'"
+msgstr "'Estadístiques de crims per comarca a Catalunya'"
msgid "'Pollution levels over time for the River Tyne'"
msgstr "'Nivells històrics de contaminació en el riu Ebre'"
@@ -126,13 +126,13 @@ msgid "(hide)"
msgstr ""
msgid "(or <a href=\"{{url}}\">sign in</a>)"
-msgstr ""
+msgstr "(o <a href=\"{{url}}\">inicia sessió</a>)"
msgid "(show)"
msgstr ""
msgid "*unknown*"
-msgstr ""
+msgstr "*desconegut*"
msgid ",\\n\\n\\n\\nYours,\\n\\n{{user_name}}"
msgstr ""
@@ -426,7 +426,7 @@ msgid "All the options below can use <strong>variety</strong> or <strong>latest_
msgstr "All the options below can use <strong>variety</strong> or <strong>latest_variety</strong> before the colon. For example, <strong>variety:sent</strong> will match requests which have <em>ever</em> been sent; <strong>latest_variety:sent</strong> will match only requests that are <em>currently</em> marked as sent."
msgid "Also called {{other_name}}."
-msgstr "También conocido como {{other_name}}."
+msgstr "També conegut com a {{other_name}}."
msgid "Also send me alerts by email"
msgstr ""
@@ -455,33 +455,33 @@ msgid "Annotation added to request"
msgstr "Comentario añadido a la solicitud"
msgid "Annotations"
-msgstr "Comentarios"
+msgstr "Comentaris"
msgid "Annotations are so anyone, including you, can help the requester with their request. For example:"
-msgstr "Los comentarios sirven para que cualquiera, incluído tú, pueda ayudar al creador de la solicitud. Por ejemplo:"
+msgstr "Els comentaris serveixen per tal que qualsevol, inclòs tu, pugui ajudar al creador de la sol·licitud. Per exemple:"
msgid "Annotations will be posted publicly here, and are\\n <strong>not</strong> sent to {{public_body_name}}."
msgstr ""
-"Los comentarios se muestran públicamente aquí, y \n"
-" <strong>no</strong> se envían a {{public_body_name}}."
+"Els comentaris es mostren públicament aquí, i\n"
+" <strong>no</strong> s'envien a {{public_body_name}}."
msgid "Anonymous user"
msgstr ""
msgid "Anyone:"
-msgstr "Cualquiera:"
+msgstr "Qualsevol:"
msgid "Applies to"
msgstr ""
msgid "Are we missing a public authority?"
-msgstr ""
+msgstr "Hi falta algun organisme?"
msgid "Are you the owner of any commercial copyright on this page?"
msgstr "Posseeix el copyright d'alguna informació d'aquesta pàgina?"
msgid "Ask for <strong>specific</strong> documents or information, this site is not suitable for general enquiries."
-msgstr "Pide documentos o información <strong>específica</strong>, esta web no está pensada para resolver dudas generales."
+msgstr "Demana documents o informació <strong>específica</strong>, aquesta web no està pensada per resoldre dubtes generals."
msgid "Ask us to add an authority"
msgstr ""
@@ -510,19 +510,19 @@ msgid "Authority:"
msgstr ""
msgid "Awaiting classification."
-msgstr "Esperando clasificación."
+msgstr "Esperant classificació."
msgid "Awaiting internal review."
msgstr "Esperando revisión interna."
msgid "Awaiting response."
-msgstr "Esperando respuesta."
+msgstr "Esperant resposta."
msgid "Batch created by {{info_request_user}} on {{date}}."
msgstr ""
msgid "Beginning with"
-msgstr "Comenzando por"
+msgstr "Començant per"
msgid "Browse <a href='{{url}}'>other requests</a> for examples of how to word your request."
msgstr "Consulta <a href='{{url}}'>otras solicitudes</a> para ver cómo puede redactar tu solicitud."
@@ -591,13 +591,13 @@ msgid "Change your email address used on {{site_name}}"
msgstr "Cambia tu dirección de correo en {{site_name}}"
msgid "Change your password"
-msgstr "Cambia tu contraseña"
+msgstr "Canvia la teva contrassenya"
msgid "Change your password on {{site_name}}"
-msgstr "Cambia tu contraseña en {{site_name}}"
+msgstr "Canvia la teva contrassenya a {{site_name}}"
msgid "Change your password {{site_name}}"
-msgstr "Cambia tu contraseña en {{site_name}}"
+msgstr "Canvia la teva contrassenya a {{site_name}}"
msgid "Charity registration"
msgstr "Registro de la ONG"
@@ -606,7 +606,7 @@ msgid "Check for mistakes if you typed or copied the address."
msgstr "Busque erratas si ha copiado la dirección."
msgid "Check you haven't included any <strong>personal information</strong>."
-msgstr "Compruebe que no ha incluído <strong>ninguna información personal</strong>."
+msgstr "Comprova que no has inclòs <strong>cap informació personal</strong>."
msgid "Choose a reason"
msgstr ""
@@ -727,22 +727,22 @@ msgstr ""
" los factores medioambientales mencionados anteriormente)"
msgid "Currently <strong>waiting for a response</strong> from {{public_body_link}}, they must respond promptly and"
-msgstr "Actualmente <strong>esperando la respuesta</strong> de {{public_body_link}}, que debe responder pronto y"
+msgstr "Actualment <strong>esperant la resposta</strong> de {{public_body_link}}, que ha de respondre aviat i"
msgid "Date:"
msgstr "Fecha:"
msgid "Dear [Authority name],"
-msgstr ""
+msgstr "Benvolgut [Authority name],"
msgid "Dear {{name}},"
-msgstr ""
+msgstr "Benvolgut {{name}},"
msgid "Dear {{public_body_name}},"
-msgstr "Estimado {{public_body_name}},"
+msgstr "Benvolgut {{public_body_name}},"
msgid "Dear {{user_name}},"
-msgstr ""
+msgstr "Benvolgut {{user_name}},"
msgid "Default locale"
msgstr ""
@@ -754,10 +754,10 @@ msgid "Delayed response to your FOI request - "
msgstr "Respuesta retrasada a tu solicitud de acceso a información - "
msgid "Delayed."
-msgstr "Retrasado."
+msgstr "Endarrerit."
msgid "Delivery error"
-msgstr "Error en la entrega"
+msgstr "Error en el lliurament"
msgid "Destroy {{name}}"
msgstr ""
@@ -790,7 +790,7 @@ msgid "Done &gt;&gt;"
msgstr ""
msgid "Download a zip file of all correspondence"
-msgstr "Descargar un fichero ZIP con toda la correspondencia"
+msgstr "Descarregar un fitxer ZIP amb tota la correspondència"
msgid "Download original attachment"
msgstr "Descargar ficheros adjuntos"
@@ -807,7 +807,7 @@ msgstr ""
" explicando por qué no estás satisfecho con su respuesta."
msgid "Edit text about you"
-msgstr "Edite el texto sobre tí"
+msgstr "Edita el text sobre tu"
msgid "Edit this request"
msgstr "Editar esta solicitud"
@@ -822,7 +822,7 @@ msgid "Email doesn't look like a valid address"
msgstr "La dirección de correo no parece válida"
msgid "Email me future updates to this request"
-msgstr "Quiero recibir emails con las actulizaciones de esta solicitud"
+msgstr "Vull rebre emails amb les actualitzacions d'aquesta sol·licitud"
msgid "Email:"
msgstr ""
@@ -853,30 +853,30 @@ msgstr ""
msgid "Everything that you enter on this page, including <strong>your name</strong>,\\n will be <strong>displayed publicly</strong> on\\n this website forever (<a href=\"{{url}}\">why?</a>)."
msgstr ""
-"Todo lo que escribas en esta página, incluyendo <strong>tu nombre</strong>, \n"
-" estará <strong>disponible públicamente</strong> en\n"
-" está web para siempre (<a href=\"{{url}}\">¿por qué?</a>)."
+"Tot el que escriguis en aquesta pàgina, incloent <strong>el teu nom</strong>, \n"
+" estarà <strong>disponible públicament</strong> en\n"
+" aquesta web per sempre (<a href=\"{{url}}\">per què?</a>)."
msgid "Everything that you enter on this page\\n will be <strong>displayed publicly</strong> on\\n this website forever (<a href=\"{{url}}\">why?</a>)."
msgstr ""
-"Todo lo que escriba en esta página \n"
-" estará <strong>disponible públicamente</strong> en\n"
-" está web para siempre (<a href=\"{{url}}\">¿por qué?</a>)."
+"Tot el que escriguis en aquesta pàgina, incloent <strong>el teu nom</strong>, \n"
+" estarà <strong>disponible públicament</strong> en\n"
+" aquesta web per sempre (<a href=\"{{url}}\">per què?</a>)."
msgid "FOI"
msgstr "FOI"
msgid "FOI email address for {{public_body}}"
-msgstr "Dirección de correo para {{public_body}}"
+msgstr "Adreça de correu de {{public_body}}"
msgid "FOI request – {{title}}"
msgstr ""
msgid "FOI requests"
-msgstr "Solicitudes de información"
+msgstr "Sol·licituds d'informació"
msgid "FOI requests by '{{user_name}}'"
-msgstr "Solicitudes de información por '{{user_name}}'"
+msgstr "Sol·licituds d'informació de '{{user_name}}'"
msgid "FOI requests {{start_count}} to {{end_count}} of {{total_count}}"
msgstr "Solicitudes {{start_count}} a {{end_count}} de {{total_count}}"
@@ -924,7 +924,7 @@ msgid "FoiAttachment|Within rfc822 subject"
msgstr "FoiAttachment|Within rfc822 subject"
msgid "Follow"
-msgstr ""
+msgstr "Segueix"
msgid "Follow all new requests"
msgstr ""
@@ -936,13 +936,13 @@ msgid "Follow requests to {{public_body_name}}"
msgstr ""
msgid "Follow these requests"
-msgstr "Seguir estas solicitudes"
+msgstr "Segueix aquestes sol·licituds"
msgid "Follow things matching this search"
msgstr ""
msgid "Follow this authority"
-msgstr "Seguir a este organismo"
+msgstr "Seguir aquest organisme"
msgid "Follow this link to see the request:"
msgstr "Siga este enlace para ver la solicitud:"
@@ -954,7 +954,7 @@ msgid "Follow this person"
msgstr ""
msgid "Follow this request"
-msgstr "Seguir esta solicitud"
+msgstr "Segueix aquesta sol·licitud"
#. "Follow up" in this context means a further
#. message sent by the requester to the authority after
@@ -990,15 +990,15 @@ msgid "For an unknown reason, it is not possible to make a request to this autho
msgstr "No es posible hacer una solicitud a este organismo, por motivos desconocidos."
msgid "Forgotten your password?"
-msgstr "¿Has olvidado tu contraseña?"
+msgstr "Has oblidat la teva contrassenya?"
msgid "Found {{count}} public authority {{description}}"
msgid_plural "Found {{count}} public authorities {{description}}"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Trobat {{count}} organismo {{description}}"
+msgstr[1] "Trobats {{count}} organismes {{description}}"
msgid "Freedom of Information"
-msgstr "Acceso a la Información"
+msgstr "accés a la informació"
msgid "Freedom of Information Act"
msgstr "Ley de Acceso a la Información"
@@ -1025,7 +1025,7 @@ msgid "Freedom of Information requests made using this site"
msgstr "Solicitudes de acceso a información realizadas por esta web"
msgid "Freedom of information requests to"
-msgstr "Solicitudes de información a"
+msgstr "Sol·licituds d'informació a"
msgid "From"
msgstr ""
@@ -1104,10 +1104,10 @@ msgid "Home"
msgstr "Inicio"
msgid "Home page"
-msgstr ""
+msgstr "Lloc web"
msgid "Home page of authority"
-msgstr "Sitio web del organismo"
+msgstr "Lloc web de l'organisme"
msgid "However, you have the right to request environmental\\n information under a different law"
msgstr ""
@@ -1168,7 +1168,7 @@ msgid "Id"
msgstr ""
msgid "If the address is wrong, or you know a better address, please <a href=\"{{url}}\">contact us</a>."
-msgstr "Si la dirección es incorrecta, o conoce una más actualizada, por favor <a href=\"{{url}}\">contáctenos</a>."
+msgstr "Si l'adreça és incorrecta, o en coneix una de més actualitzada, sisplau <a href=\"{{url}}\">contacta'ns</a>."
msgid "If the error was a delivery failure, and you can find an up to date FOI email address for the authority, please tell us using the form below."
msgstr ""
@@ -1196,8 +1196,8 @@ msgstr "Si la solicitud es tuya, puedes <a href=\"{{url}}\">abrir una sesión</a
msgid "If you are thinking of using a pseudonym,\\n please <a href=\"{{url}}\">read this first</a>."
msgstr ""
-"Si está pensando en utilizar un pseudónimo,\n"
-" por favor <a href=\"{{url}}\">lea esto primero</a>."
+"Si estàs pensant en utilitzar un pseudònim,\n"
+" sisplau <a href=\"{{url}}\">llegeix això abans</a>."
msgid "If you are {{user_link}}, please"
msgstr "Si es {{user_link}}, por favor"
@@ -1231,9 +1231,7 @@ msgid "If you reply to this message it will go directly to {{user_name}}, who wi
msgstr ""
msgid "If you use web-based email or have \"junk mail\" filters, also check your\\nbulk/spam mail folders. Sometimes, our messages are marked that way."
-msgstr ""
-"Si usas correo web o tiene filtros \"anti spam\", por favor comprueba\n"
-"tus carpetas de spam. A veces, nuestros mensajes se marcan así por error."
+msgstr "Si utilitzes correu web o tens filtres \"anti spam\", si us plau comprova les teves carpetes d'spam. A vegades, els nostres missatges es marquen així per error."
msgid "If you would like us to lift this ban, then you may politely\\n<a href=\"/help/contact\">contact us</a> giving reasons.\\n"
msgstr ""
@@ -1366,7 +1364,7 @@ msgid "InfoRequest|Url title"
msgstr "InfoRequest|Url title"
msgid "Information not held."
-msgstr "Información no disponible."
+msgstr "Informació no disponible."
msgid "Information on emissions and discharges (e.g. noise, energy,\\n radiation, waste materials)"
msgstr ""
@@ -1395,19 +1393,19 @@ msgid "Items sent in last month"
msgstr ""
msgid "Joined in"
-msgstr "Registrado el"
+msgstr "Registrat el"
msgid "Joined {{site_name}} in"
-msgstr "Registrado en {{site_name}} el"
+msgstr "Registrat a {{site_name}} el"
msgid "Just one more thing"
msgstr ""
msgid "Keep it <strong>focused</strong>, you'll be more likely to get what you want (<a href=\"{{url}}\">why?</a>)."
-msgstr "Sea <strong>específico</strong>, tendrá más probabilidades de conseguir lo que quiere (<a href=\"{{url}}\">¿por qué?</a>)."
+msgstr "Sigues <strong>específic</strong>, tindràs més probabilitats d'aconseguir el que vols (<a href=\"{{url}}\">per què?</a>)."
msgid "Keywords"
-msgstr "Términos"
+msgstr "Paraules"
msgid "Last authority viewed: "
msgstr "Ultimo organismo visitado: "
@@ -1425,7 +1423,7 @@ msgid "Link to this"
msgstr "Enlace"
msgid "List of all authorities (CSV)"
-msgstr "Lista de todos los organismos (CSV)"
+msgstr "Llista de tots els organismes (CSV)"
msgid "Listing FOI requests"
msgstr ""
@@ -1449,10 +1447,10 @@ msgid "Log into the admin interface"
msgstr ""
msgid "Long overdue."
-msgstr "Muy retrasada."
+msgstr "Molt endarrerida."
msgid "Made between"
-msgstr "Realizadas entre"
+msgstr "Realitzades entre"
msgid "Mail server log"
msgstr ""
@@ -1479,7 +1477,7 @@ msgid "Make a new EIR request"
msgstr ""
msgid "Make a new FOI request"
-msgstr ""
+msgstr "Fes una nova sol·licitud"
msgid "Make a new<br/>\\n <strong>Freedom <span>of</span><br/>\\n Information<br/>\\n request</strong>"
msgstr ""
@@ -1494,7 +1492,7 @@ msgid "Make a request to these authorities"
msgstr ""
msgid "Make a request to this authority"
-msgstr ""
+msgstr "Fes una sol·licitud a aquest organisme"
msgid "Make an {{law_used_short}} request"
msgstr ""
@@ -1506,7 +1504,7 @@ msgid "Make and browse Freedom of Information (FOI) requests"
msgstr "Realiza una solicitud de información o mira las ya realizadas"
msgid "Make your own request"
-msgstr "Hacer mi propia solicitud"
+msgstr "Fer la meva pròpia sol·licitud"
msgid "Many requests"
msgstr ""
@@ -1524,25 +1522,25 @@ msgid "Missing contact details for '"
msgstr "Faltan datos de contacto para '"
msgid "More about this authority"
-msgstr "Más información sobre este organismo"
+msgstr "Més informació d'aquest organisme"
msgid "More requests..."
msgstr ""
msgid "More similar requests"
-msgstr "Más solicitudes similares"
+msgstr "Més sol·licituds similars"
msgid "More successful requests..."
msgstr "Más solicitudes realizadas con éxito..."
msgid "My profile"
-msgstr "Mi perfil"
+msgstr "El meu perfil"
msgid "My request has been <strong>refused</strong>"
msgstr "Mi solicitud ha sido <strong>rechazada</strong>"
msgid "My requests"
-msgstr "Mis solicitudes."
+msgstr "Les meves sol·licituds"
msgid "My wall"
msgstr ""
@@ -1587,7 +1585,7 @@ msgid "New updates for the request '{{request_title}}'"
msgstr "Actualizaciones para la solicitud '{{request_title}}'"
msgid "Newest results first"
-msgstr "Resultados recientes primero"
+msgstr "Resultats recents primer"
msgid "Next"
msgstr "Siguiente"
@@ -1614,7 +1612,7 @@ msgid "None found."
msgstr "No se han encontrado resultados."
msgid "None made."
-msgstr "Ninguno/a."
+msgstr "Cap."
msgid "Not a valid FOI request"
msgstr ""
@@ -1629,10 +1627,10 @@ msgid "Notes:"
msgstr ""
msgid "Now check your email!"
-msgstr "¡Ahora comprueba tu correo!"
+msgstr "Ara comprova el teu correu!"
msgid "Now preview your annotation"
-msgstr "Ahora revisa tu comentario"
+msgstr "Ara revisa el teu comentari"
msgid "Now preview your follow up"
msgstr "Ahora revisa tu mensaje"
@@ -1662,7 +1660,7 @@ msgid "Old email doesn't look like a valid address"
msgstr "La dirección de correo antigua no parece válida"
msgid "On this page"
-msgstr "En esta página"
+msgstr "En aquesta pàgina"
msgid "One FOI request found"
msgstr "Una solicitud encontrada"
@@ -1677,7 +1675,7 @@ msgid "Only put in abbreviations which are really used, otherwise leave blank. S
msgstr ""
msgid "Only requests made using {{site_name}} are shown."
-msgstr "Sólo se muestran las solicitudes realizadas con {{site_name}}."
+msgstr "Només es mostren las sol·licituds realitzades emprant {{site_name}}."
msgid "Only the authority can reply to this request, and I don't recognise the address this reply was sent from"
msgstr "Sólo el organismo puede responder a esta solicitud, y no reconozco la dirección desde la que se mandó esta respuesta"
@@ -1725,19 +1723,19 @@ msgid "OutgoingMessage|What doing"
msgstr "OutgoingMessage|What doing"
msgid "Partially successful."
-msgstr "Éxito parcial."
+msgstr "Èxit parcial."
msgid "Password is not correct"
msgstr "La contraseña no es correcta"
msgid "Password:"
-msgstr "Contraseña:"
+msgstr "Contrassenya:"
msgid "Password: (again)"
-msgstr "Contraseña: (de nuevo)"
+msgstr "Contrassenya: (de nou)"
msgid "Paste this link into emails, tweets, and anywhere else:"
-msgstr "Pegue este enlace en correos, tweets, o cualquier otro sitio:"
+msgstr "Enganxa aquest enllaç a correus, piulades, o qualsevol altre lloc:"
msgid "People"
msgstr ""
@@ -1898,10 +1896,10 @@ msgid "Please sign at the bottom with your name, or alter the \"{{signoff}}\" si
msgstr "Por favor, firma con tu nombre en la parte inferior, o cambia la firma \"{{signoff}}\""
msgid "Please sign in as "
-msgstr "Por favor abre una sesión como "
+msgstr "Sisplau inicia sessió como"
msgid "Please sign in or make a new account."
-msgstr ""
+msgstr "Sisplau inicia sessió o dóna d'alta un nou compte."
msgid "Please tell us more:"
msgstr ""
@@ -1934,7 +1932,7 @@ msgid "Possibly related requests:"
msgstr "Posibles solicitudes relacionadas:"
msgid "Post annotation"
-msgstr "Enviar comentario"
+msgstr "Envia comentari"
msgid "Post redirect"
msgstr ""
@@ -1982,13 +1980,13 @@ msgid "Preview new {{law_used_short}} request to '{{public_body_name}}"
msgstr ""
msgid "Preview your annotation"
-msgstr "Revisa tu comentario"
+msgstr "Revisa el teu comentari"
msgid "Preview your message"
msgstr "Revisa tu mensaje"
msgid "Preview your public request"
-msgstr "Revisa tu solicitud pública"
+msgstr "Revisa la teva sol·licitud pública"
msgid "Profile photo"
msgstr ""
@@ -2006,16 +2004,16 @@ msgid "Public Body Statistics"
msgstr ""
msgid "Public authorities"
-msgstr "Organismos públicos"
+msgstr "Organismes públics"
msgid "Public authorities - {{description}}"
-msgstr "Organismos públicos - {{description}}"
+msgstr "Organismes públics - {{description}}"
msgid "Public authorities {{start_count}} to {{end_count}} of {{total_count}}"
-msgstr "Organismos públicos {{start_count}} a {{end_count}} de {{total_count}}"
+msgstr "Organismes públics {{start_count}} a {{end_count}} de {{total_count}}"
msgid "Public authority – {{name}}"
-msgstr ""
+msgstr "Organismo público - {{name}}"
msgid "Public bodies that most frequently replied with \"Not Held\""
msgstr ""
@@ -2141,10 +2139,10 @@ msgid "RSS feed"
msgstr "RSS"
msgid "RSS feed of updates"
-msgstr "Actualizaciones RSS"
+msgstr "Actualitzacions RSS"
msgid "Re-edit this annotation"
-msgstr "Editar este comentario"
+msgstr "Edita aquest comentari"
msgid "Re-edit this message"
msgstr "Editar este mensaje"
@@ -2165,9 +2163,7 @@ msgid "Refused."
msgstr "Rechazada."
msgid "Remember me</label> (keeps you signed in longer;\\n do not use on a public computer) "
-msgstr ""
-"Recuérdame</label> (mantiene la sesión abierta;\n"
-" no lo use en un ordenador público) "
+msgstr "Recorda'm</label> (manté la sessió oberta;\\n no ho faci servir en un ordinador públic)"
msgid "Report abuse"
msgstr "Denuncie abuso"
@@ -2203,7 +2199,7 @@ msgid "Request has been removed"
msgstr "La solicitud ha sido eliminada"
msgid "Request sent to {{public_body_name}} by {{info_request_user}} on {{date}}."
-msgstr "Solicitud enviada a {{public_body_name}} por {{info_request_user}} el {{date}}."
+msgstr "Sol·licitud enviada a {{public_body_name}} per {{info_request_user}} el {{date}}."
msgid "Request to {{public_body_name}} by {{info_request_user}}. Annotated by {{event_comment_user}} on {{date}}."
msgstr "Solicitud a {{public_body_name}} por {{info_request_user}}. Comentada por {{event_comment_user}} el {{date}}."
@@ -2260,10 +2256,10 @@ msgid "Response to '{{title}}'"
msgstr ""
msgid "Response to this request is <strong>delayed</strong>."
-msgstr "La respuesta a esta solicitud está <strong>retrasada</strong>."
+msgstr "La resposta a aquesta sol·licitud està <strong>endarrerida</strong>."
msgid "Response to this request is <strong>long overdue</strong>."
-msgstr "La respuesta a esta solicitud está <strong>muy retrasada</strong>."
+msgstr "La resposta a aquesta sol·licitud està <strong>molt endarrerida</strong>."
msgid "Response to your request"
msgstr "Respuesta a tu solicitud"
@@ -2281,13 +2277,13 @@ msgid "Save"
msgstr "Guardar"
msgid "Search"
-msgstr "Buscar"
+msgstr "Cerca"
msgid "Search Freedom of Information requests, public authorities and users"
msgstr "Buscar solicitudes de información, organismos públicos y usuarios"
msgid "Search contributions by this person"
-msgstr "Buscar aportaciones de esta persona"
+msgstr "Cerca aportacions d'aquesta persona"
msgid "Search for the authorities you'd like information from:"
msgstr ""
@@ -2308,7 +2304,7 @@ msgid "Search queries"
msgstr ""
msgid "Search results"
-msgstr "Resultados de la búsqueda"
+msgstr "Resultats de la cerca"
msgid "Search the site to find what you were looking for."
msgstr "Buscar en esta web para encontrar lo que busca."
@@ -2334,10 +2330,10 @@ msgid "Select the authority to write to"
msgstr "Elija el organismo al que escribir"
msgid "Send a followup"
-msgstr "Mandar una respuesta"
+msgstr "Enviar una resposta"
msgid "Send a message to "
-msgstr "Enviar un mensaje a "
+msgstr "Envia un missatge a "
msgid "Send a public follow up message to {{person_or_body}}"
msgstr "Responder públicamente a {{person_or_body}}"
@@ -2349,10 +2345,10 @@ msgid "Send follow up to '{{title}}'"
msgstr ""
msgid "Send message"
-msgstr "Enviar un mensaje"
+msgstr "Envia el missatge"
msgid "Send message to "
-msgstr "Enviar un mensaje a "
+msgstr "Envia un missatge a "
msgid "Send request"
msgstr "Enviar solicitud"
@@ -2372,34 +2368,34 @@ msgid "Short name is already taken"
msgstr "Nombre de usuario ya en uso"
msgid "Show most relevant results first"
-msgstr "Muestra resultados más relevantes primero"
+msgstr "Mostra resultats més rellevants primer"
msgid "Show only..."
-msgstr "Mostrar sólo..."
+msgstr "Mostrar només..."
msgid "Showing"
-msgstr "Mostrando"
+msgstr "Mostrant"
msgid "Sign in"
-msgstr "Abrir sesión"
+msgstr "Inicia sessió"
msgid "Sign in as the emergency user"
msgstr ""
msgid "Sign in or make a new account"
-msgstr "Abrir sesión o crear nueva cuenta"
+msgstr "Inicia sessió o crea un nou compte"
msgid "Sign in or sign up"
msgstr "Inicia sessió / registra't"
msgid "Sign out"
-msgstr "Cerrar sesión"
+msgstr "Tancar sessió"
msgid "Sign up"
-msgstr "Registrarse"
+msgstr "Registra't"
msgid "Similar requests"
-msgstr "Solicitudes similares"
+msgstr "Sol·licituds similars"
msgid "Simple search"
msgstr "Búsqueda básica"
@@ -2498,7 +2494,7 @@ msgid "Suggest how the requester can find the <strong>rest of the information</s
msgstr "Sugerir al creador de la solicitud cómo puede encontrar el <strong>resto de la información</strong>."
msgid "Summary:"
-msgstr "Resumen:"
+msgstr "Resum:"
msgid "Table of statuses"
msgstr "Tabla de estados"
@@ -2634,13 +2630,13 @@ msgid "The request is <strong>waiting for clarification</strong>."
msgstr "La solicitud está <strong>esperando aclaración</strong>."
msgid "The request was <strong>partially successful</strong>."
-msgstr "La solicitud fue <strong>parcialmente exitosa</strong>."
+msgstr "La sol·licitud ha tingut un resultat <strong>parcialment exitós</strong>."
msgid "The request was <strong>refused</strong> by"
msgstr "La solicitud fue <strong>rechazada</strong> por"
msgid "The request was <strong>successful</strong>."
-msgstr "La solicitud fue <strong>exitosa</strong>."
+msgstr "La sol·licitud ha estat <strong>exitosa</strong>."
msgid "The request was refused by the public authority"
msgstr "La solicitud ha sido rechazada por el organismo"
@@ -2662,9 +2658,8 @@ msgstr ""
msgid "The response to your request is <strong>long overdue</strong>. You can say that, by\\n law, under all circumstances, the authority should have responded\\n by now"
msgstr ""
-"La respuesta a tu solicitud ha sido <strong>muy retrasada</strong>.\n"
-" Por ley, bajo cualquier circunstancia, el organismo ya debería\n"
-" haber respondido"
+"La resposta a aquesta sol·licitud està <strong>molt endarrerida</strong>.\n"
+" Per llei, sota qualsevol circumstància, el organismo ja hauria d'haver respòs"
msgid "The search index is currently offline, so we can't show the Freedom of Information requests that have been made to this authority."
msgstr "El motor de búsqueda no está accesible en estos momentos: no podemos mostrar las solicitudes de información realizadas a este organismo."
@@ -2768,7 +2763,7 @@ msgstr[0] "Hay {{count}} persona siguiendo esta solicitud."
msgstr[1] "Hay {{count}} personas siguiendo esta solicitud."
msgid "There was a <strong>delivery error</strong> or similar, which needs fixing by the {{site_name}} team."
-msgstr "Se ha producido un <strong>error en la entrega</strong> o similar, y necesita ser arreglado por el equipo de {{site_name}}."
+msgstr "S'ha produït un <strong>error en el lliurament</strong> o quelcom similar, i necessita ser arreglat per l'equip de {{site_name}}."
msgid "There was an error with the words you entered, please try again."
msgstr "Ha habido un error con las palabras introducidas, por favor pruebe otra vez."
@@ -2803,7 +2798,7 @@ msgstr ""
" como requiere la ley"
msgid "Things to do with this request"
-msgstr "Cosas que hacer con esta solicitud"
+msgstr "Coses per fer amb aquesta sol·licitud"
msgid "Things you're following"
msgstr ""
@@ -2867,17 +2862,17 @@ msgid "This person has made no Freedom of Information requests using this site."
msgstr "Esta persona no ha realizado solicitudes de información usando esta web."
msgid "This person's annotations"
-msgstr "Tus comentarios"
+msgstr "Comentaris"
msgid "This person's {{count}} Freedom of Information request"
msgid_plural "This person's {{count}} Freedom of Information requests"
-msgstr[0] "Tu {{count}} solicitud de información"
-msgstr[1] "Tus {{count}} solicitudes de información"
+msgstr[0] "{{count}} sol·licitud d'informació"
+msgstr[1] "{{count}} sol·licituds d'informació"
msgid "This person's {{count}} annotation"
msgid_plural "This person's {{count}} annotations"
-msgstr[0] "Tu {{count}} comentario"
-msgstr[1] "Tus {{count}} comentarios"
+msgstr[0] "{{count}} comentari"
+msgstr[1] "{{count}} comentaris"
msgid "This request <strong>requires administrator attention</strong>"
msgstr "Esta solicitud <strong>requiere la intervención de un administrador</strong>"
@@ -2886,7 +2881,7 @@ msgid "This request has already been reported for administrator attention"
msgstr ""
msgid "This request has an <strong>unknown status</strong>."
-msgstr "Esta solicitud tiene un <strong>estado desconocido</strong>."
+msgstr "Aquesta sol·licitud té un <strong>estat desconegut</strong>."
msgid "This request has been <strong>hidden</strong> from the site, because an administrator considers it not to be an FOI request"
msgstr ""
@@ -2981,7 +2976,7 @@ msgid "To follow new requests"
msgstr ""
msgid "To follow requests and responses matching your search"
-msgstr "Para seguir solicitudes y respuestas que encajen con tu búsqueda"
+msgstr "Per seguir sol·licituds i respostes que encaixin amb la teva cerca"
msgid "To follow requests by '{{user_name}}'"
msgstr ""
@@ -3010,7 +3005,7 @@ msgid "To play the request categorisation game"
msgstr "Jugar al juego de recategorización de solicitudes"
msgid "To post your annotation"
-msgstr "Añadir tu comentario"
+msgstr "Envia comentari"
msgid "To reply to "
msgstr "Contestar a "
@@ -3037,16 +3032,16 @@ msgid "To use the advanced search, combine phrases and labels as described in th
msgstr "Para usar la búsqueda avanzada, combine frases y etiquetas como se describe en las instrucciones a continuación."
msgid "To view the email address that we use to send FOI requests to {{public_body_name}}, please enter these words."
-msgstr "Para ver la dirección de correo que usamos para mandar solicitudes a {{public_body_name}}, por favor introduzca estas palabras."
+msgstr "Per veure l'adreça de correu que utilitzem per enviar sol·licituds a {{public_body_name}}, sisplau introdueix aquestes paraules."
msgid "To view the response, click on the link below."
msgstr "Para ver la respuesta, use el siguiente enlace."
msgid "To {{public_body_link_absolute}}"
-msgstr "Para {{public_body_link_absolute}}"
+msgstr "Per a {{public_body_link_absolute}}"
msgid "To:"
-msgstr "Para:"
+msgstr "Per a:"
msgid "Today"
msgstr "Hoy"
@@ -3061,10 +3056,10 @@ msgid "Track thing"
msgstr ""
msgid "Track this person"
-msgstr "Seguir a esta persona"
+msgstr "Segueix aquesta persona"
msgid "Track this search"
-msgstr "Seguir esta búsqueda"
+msgstr "Segueix aquesta cerca"
msgid "TrackThing|Track medium"
msgstr "TrackThing|Track medium"
@@ -3079,7 +3074,7 @@ msgid "Turn off email alerts"
msgstr ""
msgid "Tweet this request"
-msgstr "Tuitear esta solicitud"
+msgstr "Piular aquesta sol·licitud"
msgid "Type <strong><code>01/01/2008..14/01/2008</code></strong> to only show things that happened in the first two weeks of January."
msgstr "Introduce <code><strong>01/01/2008..14/01/2008</strong></code> para mostrar sólo las cosas que sucedieron en las dos primeras semanas de enero."
@@ -3115,7 +3110,7 @@ msgid "Unfortunately, we do not have a working {{info_request_law_used_full}}\\n
msgstr "Desgraciadamente, no tenemos una dirección de correo válida para"
msgid "Unknown"
-msgstr "Desconocido"
+msgstr "Desconegut"
msgid "Unsubscribe"
msgstr ""
@@ -3130,10 +3125,10 @@ msgid "Update the address:"
msgstr ""
msgid "Update the status of this request"
-msgstr "Actualizar el estado de esta solicitud"
+msgstr "Actualitzar l'estat d'aquesta sol·licitud"
msgid "Update the status of your request to "
-msgstr "Actualizar el estado de la solicitud a "
+msgstr "Actualitzar l'estat d'aquesta sol·licitud a "
msgid "Upload FOI response"
msgstr ""
@@ -3220,13 +3215,13 @@ msgid "Vexatious"
msgstr ""
msgid "View FOI email address"
-msgstr "Ver dirección de correo"
+msgstr "Veure l'adreça de correu"
msgid "View FOI email address for '{{public_body_name}}'"
-msgstr "Ver dirección de correo para '{{public_body_name}}'"
+msgstr "Veure l'adreça de correu de '{{public_body_name}}'"
msgid "View FOI email address for {{public_body_name}}"
-msgstr "Ver dirección de correo para '{{public_body_name}}'"
+msgstr "Veure l'adreça de correu de '{{public_body_name}}'"
msgid "View Freedom of Information requests made by {{user_name}}:"
msgstr "Ver solicitudes de acceso a información hechas por {{user_name}}:"
@@ -3238,7 +3233,7 @@ msgid "View authorities"
msgstr "Ver organismos públicos"
msgid "View email"
-msgstr "Ver correo"
+msgstr "Veure el correu"
msgid "View requests"
msgstr "Ver solicitudes"
@@ -3272,15 +3267,11 @@ msgstr "No tenemos una dirección de correo válida para este {{public_body_name
msgid "We don't know whether the most recent response to this request contains\\n information or not\\n &ndash;\\n\tif you are {{user_link}} please <a href=\"{{url}}\">sign in</a> and let everyone know."
msgstr ""
-"No sabemos si la última respuesta a esta solicitud contiene\n"
-" información o no\n"
-" &ndash;\n"
-"\tsi es {{user_link}} por favor <a href=\"{{url}}\">abra una sesión</a> y háganoslo saber."
+"No sabem si l'última resposta a aquesta sol·licitud conté informació o no &ndash;\n"
+"\tsi ets {{user_link}} sisplau <a href=\"{{url}}\">inicia la sessió</a> i fes-nos-ho saber."
msgid "We will not reveal your email address to anybody unless you or\\n the law tell us to (<a href=\"{{url}}\">details</a>). "
-msgstr ""
-"No revelaremos tu dirección de correo a nadie salvo que tú nos lo digas\n"
-" o la ley nos obligue (<a href=\"{{url}}\">más información</a>). "
+msgstr "No compartirem la teva adreça de correu amb ningú, excepte que ens ho diguis\\n o la llei ens hi obligui (<a href=\"{{url}}\">més informació</a>). "
msgid "We will not reveal your email address to anybody unless you\\nor the law tell us to."
msgstr ""
@@ -3309,7 +3300,7 @@ msgstr ""
"de continuar."
msgid "We've sent you an email, click the link in it, then you can change your password."
-msgstr "Te hemos enviado un correo, sigue el enlace incluído en él, y podrás cambiar tu contraseña."
+msgstr "Te hem enviat un correu, segueix l'enllaç inclòs en ell, i podràs canviar la teva contrassenya."
msgid "What are you doing?"
msgstr "¿Qué está haciendo?"
@@ -3364,7 +3355,7 @@ msgid "Write your FOI follow up message to "
msgstr "Escribe tu respuesta a "
msgid "Write your request in <strong>simple, precise language</strong>."
-msgstr "Escribe tu solicitud en un <strong>lenguaje sencillo y claro</strong>."
+msgstr "Escriu la teva sol·licitud en un <strong>llenguatge senzill i clar</strong>."
msgid "You"
msgstr "Tú"
@@ -3571,7 +3562,7 @@ msgid "You're in. <a href=\"#\" id=\"send-request\">Continue sending your reques
msgstr ""
msgid "You're long overdue a response to your FOI request - "
-msgstr "La respuesta a tu solicitud de información está muy retrasada - "
+msgstr "La resposta a la teva sol·licitud està <strong>molt endarrerida</strong> - "
msgid "You're not following anything."
msgstr ""
@@ -3581,11 +3572,11 @@ msgstr "Has borrado la foto de tu perfil"
msgid "Your <strong>name will appear publicly</strong>\\n (<a href=\"{{why_url}}\">why?</a>)\\n on this website and in search engines. If you\\n are thinking of using a pseudonym, please\\n <a href=\"{{help_url}}\">read this first</a>."
msgstr ""
-"<strong>Tu nombre aparecerá públicamente</strong> \n"
-" (<a href=\"{{why_url}}\">¿por qué?</a>)\n"
-" en esta web y en motores de búsqueda. Si estás\n"
-" pensando en utilizar un seudónimo, por favor \n"
-" <a href=\"{{help_url}}\">lee esto primero</a>."
+"<strong>El teu nom apareixerà públicament</strong> \n"
+" (<a href=\"{{why_url}}\">¿per què?</a>)\n"
+" en aquesta web i en motors de cerca. Si estàs\n"
+" pensant en utilitzar un pseudònim, sisplau \n"
+" <a href=\"{{help_url}}\">llegeix això abans</a>."
msgid "Your annotations"
msgstr "Tus comentarios"
@@ -3597,7 +3588,7 @@ msgid "Your details, including your email address, have not been given to anyone
msgstr ""
msgid "Your e-mail:"
-msgstr "Tu correo:"
+msgstr "Correu:"
msgid "Your email doesn't look like a valid address"
msgstr ""
@@ -3624,15 +3615,15 @@ msgid "Your message will appear in <strong>search engines</strong>"
msgstr "Tu mensaje aparecerá en <strong>los motores de búsqueda</strong>"
msgid "Your name and annotation will appear in <strong>search engines</strong>."
-msgstr "Tu nombre y su comentario aparecerán en los <strong>motores de búsqueda</strong>."
+msgstr "El teu nom i els teus comentaris apareixeran en els <strong>motors de cerca</strong>."
msgid "Your name, request and any responses will appear in <strong>search engines</strong>\\n (<a href=\"{{url}}\">details</a>)."
msgstr ""
-"Tu nombre, tu solicitud y cualquier respuesta aparecerán en los <strong>motoros de búsqueda</strong>\n"
-" (<a href=\"{{url}}\">detalles</a>)."
+"El teu nom, la teva sol·liitud i qualsevol resposta apareixeran en els <strong>motors de cerca</strong>\n"
+" (<a href=\"{{url}}\">detalls</a>)."
msgid "Your name:"
-msgstr "Tu nombre:"
+msgstr "El teu nom:"
msgid "Your original message is attached."
msgstr "Tu mensaje original está adjunto."
@@ -3668,7 +3659,7 @@ msgid "Your request was called {{info_request}}. Letting everyone know whether y
msgstr "Tu solicitud se llamaba {{info_request}}. Haznos saber si has recibido la información para ayudarnos a controlar a"
msgid "Your request:"
-msgstr "Tu solicitud:"
+msgstr "La teva sol·licitud:"
msgid "Your response to an FOI request was not delivered"
msgstr ""
@@ -3684,13 +3675,13 @@ msgstr "Opine sobre lo que los <strong>administradores</strong> de {{site_name}}
msgid "Your {{count}} Freedom of Information request"
msgid_plural "Your {{count}} Freedom of Information requests"
-msgstr[0] "Tu {{count}} solicitud de información"
-msgstr[1] "Tus {{count}} solicitudes de información"
+msgstr[0] "{{count}} sol·licitud d'informació"
+msgstr[1] "{{count}} sol·licituds d'informació"
msgid "Your {{count}} annotation"
msgid_plural "Your {{count}} annotations"
msgstr[0] "Tu {{count}} comentario"
-msgstr[1] "Tus {{count}} comentarios"
+msgstr[1] "Els teus {{count}} comentaris"
msgid "Your {{count}} batch requests"
msgid_plural "Your {{count}} batch requests"
@@ -3701,13 +3692,13 @@ msgid "Your {{site_name}} email alert"
msgstr "Tu alerta en {{site_name}}"
msgid "Yours faithfully,"
-msgstr "Un saludo,"
+msgstr "Salutacions,"
msgid "Yours sincerely,"
-msgstr "Un saludo,"
+msgstr "Salutacions,"
msgid "Yours,"
-msgstr ""
+msgstr "Salutacions,"
msgid "[Authority URL will be inserted here]"
msgstr ""
@@ -3725,9 +3716,7 @@ msgid "\\n\\n[ {{site_name}} note: The above text was badly encoded, and has had
msgstr "\\n\\n[ {{site_name}} Nota: El text anterior estava mal codificat, i s'han eliminat alguns caràcters estranys. ]"
msgid "a one line summary of the information you are requesting, \\n\t\t\te.g."
-msgstr ""
-"un resumen de una línea de la información que solicitas, \n"
-"\t\t\tpor ejemplo"
+msgstr "un resum d'una línia de la informació que sol·licites, \\n\t\t\tper exemple"
msgid "admin"
msgstr "admin"
@@ -3736,7 +3725,7 @@ msgid "alaveteli_foi:The software that runs {{site_name}}"
msgstr ""
msgid "all requests"
-msgstr "todas las solicitudes"
+msgstr "totes les sol·licituds"
msgid "all requests or comments"
msgstr ""
@@ -3745,13 +3734,13 @@ msgid "all requests or comments matching text '{{query}}'"
msgstr ""
msgid "also called {{public_body_short_name}}"
-msgstr "también conocido como {{public_body_short_name}}"
+msgstr "també conegut com a {{public_body_short_name}}"
msgid "an anonymous user"
msgstr ""
msgid "and"
-msgstr "y"
+msgstr "i"
msgid "and update the status accordingly. Perhaps <strong>you</strong> might like to help out by doing that?"
msgstr "y actualice su estado. ¿Tal vez <strong>tú</strong> quieres ayudarnos a hacerlo?"
@@ -3772,16 +3761,16 @@ msgid "at"
msgstr ""
msgid "authorities"
-msgstr "organismos"
+msgstr "organismes"
msgid "beginning with ‘{{first_letter}}’"
-msgstr "comenzando con ‘{{first_letter}}’"
+msgstr "començant per ‘{{first_letter}}’"
msgid "but followupable"
msgstr ""
msgid "by"
-msgstr "por"
+msgstr "per"
msgid "by <strong>{{date}}</strong>"
msgstr "antes de <strong>{{date}}</strong>"
@@ -3813,7 +3802,7 @@ msgid "even during holidays"
msgstr "incluso durante las vacaciones"
msgid "everything"
-msgstr "todo"
+msgstr "tot"
msgid "external"
msgstr ""
@@ -3846,7 +3835,7 @@ msgid "just to see how it works"
msgstr "sólo para ver cómo funciona"
msgid "left an annotation"
-msgstr "dejó un comentario"
+msgstr "ha deixat un comentari"
msgid "made."
msgstr "hecho."
@@ -3867,7 +3856,7 @@ msgid "new requests"
msgstr ""
msgid "no later than"
-msgstr "no más tarde de"
+msgstr "no més tard de"
msgid "no longer exists. If you are trying to make\\n From the request page, try replying to a particular message, rather than sending\\n a general followup. If you need to make a general followup, and know\\n an email which will go to the right place, please <a href=\"{{url}}\">send it to us</a>."
msgstr ""
@@ -3918,7 +3907,7 @@ msgid "simple_date_format"
msgstr ""
msgid "successful requests"
-msgstr "solicitudes exitosas"
+msgstr "sol·licituds exitoses"
msgid "that you made to"
msgstr "que hizo a"
@@ -3953,10 +3942,10 @@ msgid "unknown reason "
msgstr "motivo desconocido "
msgid "unknown status "
-msgstr "estado desconocido "
+msgstr "estat desconegut"
msgid "unresolved requests"
-msgstr "solicitudes no resueltas"
+msgstr "sol·licituds no resoltes"
msgid "unsubscribe"
msgstr "cancelar suscripción"
@@ -3965,19 +3954,19 @@ msgid "unsubscribe all"
msgstr "cancelar todas las suscripciones"
msgid "unsuccessful requests"
-msgstr "solicitudes fallidas"
+msgstr "sol·licituds fallides"
msgid "useful information."
msgstr "información útil."
msgid "users"
-msgstr "usuarios"
+msgstr "usuaris"
msgid "what's that?"
msgstr "Què és això?"
msgid "{{count}} FOI requests found"
-msgstr "{{count}} solicitudes de información encontradas"
+msgstr "{{count}} sol·licituds d'informació trobades"
msgid "{{count}} Freedom of Information request to {{public_body_name}}"
msgid_plural "{{count}} Freedom of Information requests to {{public_body_name}}"
@@ -3986,8 +3975,8 @@ msgstr[1] "{{count}} sol·licituds d'informació a {{public_body_name}}"
msgid "{{count}} person is following this authority"
msgid_plural "{{count}} people are following this authority"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "{{count}} persona segueix aquest organisme"
+msgstr[1] "{{count}} persones segueixen aquest organisme"
msgid "{{count}} request"
msgid_plural "{{count}} requests"
@@ -4009,7 +3998,7 @@ msgid "{{foi_law}} requests to '{{public_body_name}}'"
msgstr ""
msgid "{{info_request_user_name}} only:"
-msgstr "Sólo {{info_request_user_name}}:"
+msgstr "Només {{info_request_user_name}}:"
msgid "{{law_used_full}} request - {{title}}"
msgstr "solicitud {{law_used_full}} - {{title}}"
@@ -4030,7 +4019,7 @@ msgid "{{public_body_link}} was sent a request about"
msgstr ""
msgid "{{public_body_name}} only:"
-msgstr "Sólo {{public_body_name}}:"
+msgstr "Només {{public_body_name}}:"
msgid "{{public_body}} has asked you to explain part of your {{law_used}} request."
msgstr ""
@@ -4039,7 +4028,7 @@ msgid "{{public_body}} sent a response to {{user_name}}"
msgstr "{{public_body}} respondió a {{user_name}}"
msgid "{{reason}}, please sign in or make a new account."
-msgstr ""
+msgstr "{{reason}}, sisplau inicia sessió o dóna d'alta un nou compte."
msgid "{{search_results}} matching '{{query}}'"
msgstr "{{search_results}} encontrados por '{{query}}'"
@@ -4051,7 +4040,7 @@ msgid "{{site_name}} covers requests to {{number_of_authorities}} authorities, i
msgstr "{{site_name}} incluye solicitudes a {{number_of_authorities}} organismos públicos, incluyendo:"
msgid "{{site_name}} sends new requests to <strong>{{request_email}}</strong> for this authority."
-msgstr "{{site_name}} envía nuevas solicitudes a <strong>{{request_email}}</strong> para este organismo."
+msgstr "{{site_name}} envia noves sol·licituds a <strong>{{request_email}}</strong> per aquest organisme."
msgid "{{site_name}} users have made {{number_of_requests}} requests, including:"
msgstr "Los usuarios de {{site_name}} han hecho {{number_of_requests}} solicitudes, incluyendo:"
@@ -4098,10 +4087,10 @@ msgid "{{user_name}} would like the email address for {{public_body_name}} to be
msgstr ""
msgid "{{username}} left an annotation:"
-msgstr "{{username}} dejó un comentario:"
+msgstr "{{username}} ha deixat un comentari:"
msgid "{{user}} ({{user_admin_link}}) made this {{law_used_full}} request (<a href=\"{{request_admin_url}}\">admin</a>) to {{public_body_link}} (<a href=\"{{public_body_admin_url}}\">admin</a>)"
-msgstr "{{user}} ({{user_admin_link}}) hizo esta solicitud {{law_used_full}} (<a href=\"{{request_admin_url}}\">admin</a>) a {{public_body_link}} (<a href=\"{{public_body_admin_url}}\">admin</a>)"
+msgstr "{{user}} ({{user_admin_link}}) va fer aquesta sol·licitud de {{law_used_full}} (<a href=\"{{request_admin_url}}\">admin</a>) a {{public_body_link}} (<a href=\"{{public_body_admin_url}}\">admin</a>)"
msgid "{{user}} made this {{law_used_full}} request"
-msgstr "{{user}} hizo esta solicitud {{law_used_full}}"
+msgstr "{{user}} va fer aquesta sol·licitud de {{law_used_full}}"
diff --git a/locale/cy/app.po b/locale/cy/app.po
index 4bdf663de..95163f107 100644
--- a/locale/cy/app.po
+++ b/locale/cy/app.po
@@ -21,7 +21,7 @@ msgstr ""
"Project-Id-Version: alaveteli\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-05-15 12:46+0100\n"
-"PO-Revision-Date: 2014-06-03 13:06+0000\n"
+"PO-Revision-Date: 2014-08-12 11:36+0000\n"
"Last-Translator: louisecrow <louise@mysociety.org>\n"
"Language-Team: Welsh (http://www.transifex.com/projects/p/alaveteli/language/cy/)\n"
"Language: cy\n"
@@ -2657,7 +2657,7 @@ msgid "They have not replied to your {{law_used_short}} request {{title}} prompt
msgstr "Nid ydynt wedi ymateb i'ch cais {{title}} {{law_used_short}} yn brydlon, fel sy'n ofynnol fel arfer yn ôl y gyfraith"
msgid "They have not replied to your {{law_used_short}} request {{title}}, \\nas required by law"
-msgstr "Nid ydynt wedi ateb i'ch cais {{teitl}} {{law_used_short}}, fel sy'n ofynnol yn ôl y gyfraith"
+msgstr "Nid ydynt wedi ateb i'ch cais {{title}} {{law_used_short}}, fel sy'n ofynnol yn ôl y gyfraith"
msgid "Things to do with this request"
msgstr "Pethau i'w gwneud gyda'r cais hwn"
@@ -2836,7 +2836,7 @@ msgid "To follow the request '{{request_title}}'"
msgstr "I ddilyn y cais '{{request_title}}'"
msgid "To help us keep the site tidy, someone else has updated the status of the \\n{{law_used_full}} request {{title}} that you made to {{public_body}}, to \"{{display_status}}\" If you disagree with their categorisation, please update the status again yourself to what you believe to be more accurate."
-msgstr "I'n helpu ni i gadw'r wefan yn daclus, mae rhywun arall wedi diweddaru statws y cais {{law_used_full}} {{teitl}} a wnaethoch i {{public_body}} , i \"{{display_status}}\" Os ydych yn anghytuno â'u categoreiddio, diweddarwch y statws unwaith eto eich hun i'r hyn y credwch i fod yn fwy cywir."
+msgstr "I'n helpu ni i gadw'r wefan yn daclus, mae rhywun arall wedi diweddaru statws y cais {{law_used_full}} {{title}} a wnaethoch i {{public_body}} , i \"{{display_status}}\" Os ydych yn anghytuno â'u categoreiddio, diweddarwch y statws unwaith eto eich hun i'r hyn y credwch i fod yn fwy cywir."
msgid "To let everyone know, follow this link and then select the appropriate box."
msgstr "I adael i bawb wybod, dilynwch y ddolen hon ac yna dewiswch y blwch priodol."
diff --git a/public/down.default.html b/public/down.default.html
index 0440f91f9..d6291a74a 100644
--- a/public/down.default.html
+++ b/public/down.default.html
@@ -3,12 +3,12 @@
<head>
<meta charset="utf-8">
<title>
- WhatDoTheyKnow - make and browse Freedom of Information (FOI) requests
+ Alaveteli - make and browse Freedom of Information (FOI) requests
</title>
- <link href="/assets/main.css" media="screen" rel="stylesheet" title="Main" type="text/css">
+ <link href="/assets/application.css" media="screen" rel="stylesheet" title="Main" type="text/css">
<!--[if LT IE 7]>
- <style type="text/css">@import url("/stylesheets/ie6.css");</style>
+ <style type="text/css">@import url("/assets/ie6.css");</style>
<![endif]-->
</head>
@@ -17,15 +17,12 @@
<div id="banner">
</div>
<div id="header">
- <h1>
- <a href="/">WhatDoTheyKnow?</a>
- </h1>
<div id="tagline">
Make and explore Freedom of Information requests
</div>
</div>
<div id="mysoclogo">
- <a href="http://www.mysociety.org">a site by mysociety.org</a>
+ <a href="http://www.alaveteli.org">powered by Alaveteli</a>
</div>
<div id="topnav">
<ul id="navigation"></ul>
@@ -35,7 +32,7 @@
<div id="content">
<div id="general_frontpage">
<div id="frontpage_search">
- <h1>Sorry. WhatDoTheyKnow is down for maintenance. Please come back in a few minutes.</h1>
+ <h1>Sorry. We&rsquo;re down for maintenance. Please come back in a few minutes.</h1>
</div>
</div>
</div>
diff --git a/script/site-specific-install.sh b/script/site-specific-install.sh
index fce230822..4c8c99aa2 100755
--- a/script/site-specific-install.sh
+++ b/script/site-specific-install.sh
@@ -134,10 +134,6 @@ su -l -c "$BIN_DIRECTORY/install-as-user '$UNIX_USER' '$HOST' '$DIRECTORY'" "$UN
# no longer need the PostgreSQL user to be a superuser:
echo "ALTER USER \"$UNIX_USER\" WITH NOSUPERUSER;" | su -l -c 'psql' postgres
-if [ ! "$DEVELOPMENT_INSTALL" = true ]; then
- install_sysvinit_script
-fi
-
# Set up root's crontab:
cd "$REPOSITORY"
@@ -151,6 +147,13 @@ sed -r \
-i /etc/cron.d/alaveteli
echo $DONE_MSG
+if [ ! "$DEVELOPMENT_INSTALL" = true ]; then
+ echo -n "Creating /etc/init.d/$SITE... "
+ (su -l -c "cd '$REPOSITORY' && bundle exec rake config_files:convert_init_script DEPLOY_USER='$UNIX_USER' VHOST_DIR='$DIRECTORY' VCSPATH='$SITE' SITE='$SITE' SCRIPT_FILE=config/sysvinit-thin.ugly" "$UNIX_USER") > /etc/init.d/"$SITE"
+ chmod a+rx /etc/init.d/"$SITE"
+ echo $DONE_MSG
+fi
+
echo -n "Creating /etc/init.d/foi-alert-tracks... "
(su -l -c "cd '$REPOSITORY' && bundle exec rake config_files:convert_init_script DEPLOY_USER='$UNIX_USER' VHOST_DIR='$DIRECTORY' SCRIPT_FILE=config/alert-tracks-debian.ugly" "$UNIX_USER") > /etc/init.d/foi-alert-tracks
chmod a+rx /etc/init.d/foi-alert-tracks
diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api_controller_spec.rb
index 6b02bd5b4..323ef4cd4 100644
--- a/spec/controllers/api_controller_spec.rb
+++ b/spec/controllers/api_controller_spec.rb
@@ -4,382 +4,538 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ApiController, "when using the API" do
describe 'checking API keys' do
- before do
- @number_of_requests = InfoRequest.count
- @request_data = {
- "title" => "Tell me about your chickens",
- "body" => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
-
- "external_url" => "http://www.example.gov.uk/foi/chickens_23",
- "external_user_name" => "Bob Smith",
- }
- end
-
- it 'should check that an API key is given as a param' do
- expect {
- post :create_request, :request_json => @request_data.to_json
- }.to raise_error ApplicationController::PermissionDenied
- InfoRequest.count.should == @number_of_requests
- end
-
- it "should check the API key" do
- expect {
- post :create_request,
- :k => "This is not really an API key",
- :request_json => @request_data.to_json
- }.to raise_error ApplicationController::PermissionDenied
- InfoRequest.count.should == @number_of_requests
- end
+ before do
+ @number_of_requests = InfoRequest.count
+ @request_data = {
+ 'title' => 'Tell me about your chickens',
+ 'body' => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
+ 'external_url' => 'http://www.example.gov.uk/foi/chickens_23',
+ 'external_user_name' => 'Bob Smith'
+ }
+ end
+
+ it 'should check that an API key is given as a param' do
+ expect {
+ post :create_request, :request_json => @request_data.to_json
+ }.to raise_error ApplicationController::PermissionDenied
+ InfoRequest.count.should == @number_of_requests
+ end
+
+ it 'should check the API key' do
+ expect {
+ post :create_request,
+ :k => 'This is not really an API key',
+ :request_json => @request_data.to_json
+ }.to raise_error ApplicationController::PermissionDenied
+ InfoRequest.count.should == @number_of_requests
+ end
+ end
+
+ def _create_request
+ post :create_request,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :request_json => {
+ 'title' => 'Tell me about your chickens',
+ 'body' => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
+ 'external_url' => 'http://www.example.gov.uk/foi/chickens_23',
+ 'external_user_name' => 'Bob Smith'
+ }.to_json
+ response.content_type.should == 'application/json'
+ ActiveSupport::JSON.decode(response.body)['id']
end
- it "should create a new request from a POST" do
- number_of_requests = InfoRequest.count(
+ # POST /api/v2/request.json
+ describe 'creating a request' do
+ it 'should create a new request from a POST' do
+ number_of_requests = InfoRequest.count(
:conditions => [
- "public_body_id = ?",
- public_bodies(:geraldine_public_body).id
+ "public_body_id = ?",
+ public_bodies(:geraldine_public_body).id
]
- )
-
- request_data = {
- "title" => "Tell me about your chickens",
- "body" => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
+ )
+
+ request_data = {
+ 'title' => 'Tell me about your chickens',
+ 'body' => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
+ 'external_url' => 'http://www.example.gov.uk/foi/chickens_23',
+ 'external_user_name' => 'Bob Smith',
+ }
+
+ post :create_request,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :request_json => request_data.to_json
+ response.should be_success
+
+ response.content_type.should == 'application/json'
+ response_body = ActiveSupport::JSON.decode(response.body)
+ response_body['errors'].should be_nil
+ response_body['url'].should =~ /^http/
+
+ InfoRequest.count(:conditions => [
+ 'public_body_id = ?',
+ public_bodies(:geraldine_public_body).id]
+ ).should == number_of_requests + 1
+
+ new_request = InfoRequest.find(response_body['id'])
+ new_request.user_id.should be_nil
+ new_request.external_user_name.should == request_data['external_user_name']
+ new_request.external_url.should == request_data['external_url']
+
+ new_request.title.should == request_data['title']
+ new_request.last_event_forming_initial_request.outgoing_message.body.should == request_data['body'].strip
+
+ new_request.public_body_id.should == public_bodies(:geraldine_public_body).id
+ new_request.info_request_events.size.should == 1
+ new_request.info_request_events[0].event_type.should == 'sent'
+ new_request.info_request_events[0].calculated_state.should == 'waiting_response'
+ end
+ end
- "external_url" => "http://www.example.gov.uk/foi/chickens_23",
- "external_user_name" => "Bob Smith",
- }
+ # POST /api/v2/request/:id/add_correspondence.json
+ describe 'adding correspondence to a request' do
+ it 'should add a response to a request' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+
+ # Initially it has no incoming messages
+ IncomingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 0
+
+ # Now add one
+ sent_at = '2012-05-28T12:35:39+01:00'
+ response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'response',
+ 'sent_at' => sent_at,
+ 'body' => response_body
+ }.to_json
+
+ # And make sure it worked
+ response.should be_success
+ incoming_messages = IncomingMessage.all(:conditions => ['info_request_id = ?', request_id])
+ incoming_messages.count.should == 1
+ incoming_message = incoming_messages[0]
+
+ incoming_message.sent_at.should == Time.iso8601(sent_at)
+ incoming_message.get_main_body_text_folded.should be_equal_modulo_whitespace_to(response_body)
+ end
- post :create_request, :k => public_bodies(:geraldine_public_body).api_key, :request_json => request_data.to_json
- response.should be_success
+ it 'should add a followup to a request' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+
+ # Initially it has one outgoing message
+ OutgoingMessage.count(:conditions => ['info_request_id = ?', request_id]).should == 1
+
+ # Add another, as a followup
+ sent_at = '2012-05-29T12:35:39+01:00'
+ followup_body = "Pls answer ASAP.\nkthxbye\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'request',
+ 'sent_at' => sent_at,
+ 'body' => followup_body
+ }.to_json
+
+ # Make sure it worked
+ response.should be_success
+ followup_messages = OutgoingMessage.all(
+ :conditions => ["info_request_id = ? and message_type = 'followup'", request_id]
+ )
+ followup_messages.size.should == 1
+ followup_message = followup_messages[0]
+
+ followup_message.last_sent_at.should == Time.iso8601(sent_at)
+ followup_message.body.should == followup_body.strip
+ end
- response.content_type.should == "application/json"
+ it 'should update the status if a valid state is supplied' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+
+ # Initially it has no incoming messages
+ IncomingMessage.count(:conditions => ['info_request_id = ?', request_id]).should == 0
+
+ # Now add one
+ sent_at = '2012-05-28T12:35:39+01:00'
+ response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :state => 'successful',
+ :correspondence_json => {
+ 'direction' => 'response',
+ 'sent_at' => sent_at,
+ 'body' => response_body,
+ }.to_json
+
+ # And make sure it worked
+ response.should be_success
+ incoming_messages = IncomingMessage.all(:conditions => ['info_request_id = ?', request_id])
+ incoming_messages.count.should == 1
+ request = InfoRequest.find_by_id(request_id)
+ request.described_state.should == 'successful'
+ end
- response_body = ActiveSupport::JSON.decode(response.body)
- response_body["errors"].should be_nil
- response_body["url"].should =~ /^http/
+ it 'should raise a JSON 500 error if an invalid state is supplied' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+
+ # Initially it has no incoming messages
+ IncomingMessage.count(:conditions => ['info_request_id = ?', request_id]).should == 0
+
+ # Now add one
+ sent_at = '2012-05-28T12:35:39+01:00'
+ response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :state => 'random_string',
+ :correspondence_json => {
+ 'direction' => 'response',
+ 'sent_at' => sent_at,
+ 'body' => response_body,
+ }.to_json
+
+ # And make sure it worked
+ response.status.should == 500
+ ActiveSupport::JSON.decode(response.body)['errors'].should == [
+ "'random_string' is not a valid request state"]
+
+ incoming_messages = IncomingMessage.all(:conditions => ['info_request_id = ?', request_id])
+ incoming_messages.count.should == 0
+ request = InfoRequest.find_by_id(request_id)
+ request.described_state.should == 'waiting_response'
+ end
- InfoRequest.count(:conditions => [
- "public_body_id = ?",
- public_bodies(:geraldine_public_body).id]
- ).should == number_of_requests + 1
+ it 'should not allow internal requests to be updated' do
+ n_incoming_messages = IncomingMessage.count
+ n_outgoing_messages = OutgoingMessage.count
+
+ request_id = info_requests(:naughty_chicken_request).id
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'request',
+ 'sent_at' => Time.now.iso8601,
+ 'body' => 'xxx'
+ }.to_json
+
+ response.status.should == 403
+ ActiveSupport::JSON.decode(response.body)['errors'].should == [
+ "Request #{request_id} cannot be updated using the API"]
+
+ IncomingMessage.count.should == n_incoming_messages
+ OutgoingMessage.count.should == n_outgoing_messages
+ end
- new_request = InfoRequest.find(response_body["id"])
- new_request.user_id.should be_nil
- new_request.external_user_name.should == request_data["external_user_name"]
- new_request.external_url.should == request_data["external_url"]
+ it 'should not allow other people\'s requests to be updated' do
+ request_id = _create_request
+ n_incoming_messages = IncomingMessage.count
+ n_outgoing_messages = OutgoingMessage.count
+
+ post :add_correspondence,
+ :k => public_bodies(:humpadink_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'request',
+ 'sent_at' => Time.now.iso8601,
+ 'body' => 'xxx'
+ }.to_json
+
+ response.status.should == 403
+ ActiveSupport::JSON.decode(response.body)['errors'].should == [
+ "You do not own request #{request_id}"]
+
+ IncomingMessage.count.should == n_incoming_messages
+ OutgoingMessage.count.should == n_outgoing_messages
+ end
- new_request.title.should == request_data["title"]
- new_request.last_event_forming_initial_request.outgoing_message.body.should == request_data["body"].strip
+ it 'should return a JSON 404 error for non-existent requests' do
+ request_id = '123459876'
+ InfoRequest.stub(:find_by_id).with(request_id).and_return(nil)
+ sent_at = '2012-05-28T12:35:39+01:00'
+ response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'response',
+ 'sent_at' => sent_at,
+ 'body' => response_body
+ }.to_json
+ response.status.should == 404
+ ActiveSupport::JSON.decode(response.body)['errors'].should == ['Could not find request 123459876']
+ end
- new_request.public_body_id.should == public_bodies(:geraldine_public_body).id
- new_request.info_request_events.size.should == 1
- new_request.info_request_events[0].event_type.should == 'sent'
- new_request.info_request_events[0].calculated_state.should == 'waiting_response'
- end
+ it 'should return a JSON 403 error if we try to add correspondence to a request we don\'t own' do
+ request_id = info_requests(:naughty_chicken_request).id
+ sent_at = '2012-05-28T12:35:39+01:00'
+ response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'response',
+ 'sent_at' => sent_at,
+ 'body' => response_body
+ }.to_json
+ response.status.should == 403
+ ActiveSupport::JSON.decode(response.body)['errors'].should == ["Request #{request_id} cannot be updated using the API"]
+ end
- def _create_request
- post :create_request,
- :k => public_bodies(:geraldine_public_body).api_key,
- :request_json => {
- "title" => "Tell me about your chickens",
- "body" => "Dear Sir,\n\nI should like to know about your chickens.\n\nYours in faith,\nBob\n",
-
- "external_url" => "http://www.example.gov.uk/foi/chickens_23",
- "external_user_name" => "Bob Smith",
- }.to_json
- response.content_type.should == "application/json"
- return ActiveSupport::JSON.decode(response.body)["id"]
- end
+ it 'should not allow files to be attached to a followup' do
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => info_requests(:external_request).id,
+ :correspondence_json => {
+ 'direction' => 'request',
+ 'sent_at' => Time.now.iso8601,
+ 'body' => 'Are you joking, or are you serious?'
+ }.to_json,
+ :attachments => [
+ fixture_file_upload('/files/tfl.pdf')
+ ]
+
+ # Make sure it worked
+ response.status.should == 500
+ errors = ActiveSupport::JSON.decode(response.body)['errors']
+ errors.should == ["You cannot attach files to messages in the 'request' direction"]
+ end
- it "should add a response to a request" do
- # First we need an external request
- request_id = info_requests(:external_request).id
-
- # Initially it has no incoming messages
- IncomingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 0
-
- # Now add one
- sent_at = "2012-05-28T12:35:39+01:00"
- response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "response",
- "sent_at" => sent_at,
- "body" => response_body
- }.to_json
-
- # And make sure it worked
- response.should be_success
- incoming_messages = IncomingMessage.all(:conditions => ["info_request_id = ?", request_id])
- incoming_messages.count.should == 1
- incoming_message = incoming_messages[0]
-
- incoming_message.sent_at.should == Time.iso8601(sent_at)
- incoming_message.get_main_body_text_folded.should be_equal_modulo_whitespace_to(response_body)
+ it 'should allow files to be attached to a response' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+
+ # Initially it has no incoming messages
+ IncomingMessage.count(:conditions => ['info_request_id = ?', request_id]).should == 0
+
+ # Now add one
+ sent_at = '2012-05-28T12:35:39+01:00'
+ response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
+ post :add_correspondence,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :correspondence_json => {
+ 'direction' => 'response',
+ 'sent_at' => sent_at,
+ 'body' => response_body
+ }.to_json,
+ :attachments => [
+ fixture_file_upload('/files/tfl.pdf')
+ ]
+
+ # And make sure it worked
+ response.should be_success
+ incoming_messages = IncomingMessage.all(:conditions => ['info_request_id = ?', request_id])
+ incoming_messages.count.should == 1
+ incoming_message = incoming_messages[0]
+
+ incoming_message.sent_at.should == Time.iso8601(sent_at)
+ incoming_message.get_main_body_text_folded.should be_equal_modulo_whitespace_to(response_body)
+
+ # Get the attachment
+ attachments = incoming_message.get_attachments_for_display
+ attachments.size.should == 1
+ attachment = attachments[0]
+ attachment.filename.should == 'tfl.pdf'
+ attachment.body.should == load_file_fixture('tfl.pdf')
+ end
end
- it "should add a followup to a request" do
- # First we need an external request
- request_id = info_requests(:external_request).id
-
- # Initially it has one outgoing message
- OutgoingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 1
-
- # Add another, as a followup
- sent_at = "2012-05-29T12:35:39+01:00"
- followup_body = "Pls answer ASAP.\nkthxbye\n"
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "request",
- "sent_at" => sent_at,
- "body" => followup_body
- }.to_json
-
- # Make sure it worked
- response.should be_success
- followup_messages = OutgoingMessage.all(
- :conditions => ["info_request_id = ? and message_type = 'followup'", request_id]
- )
- followup_messages.size.should == 1
- followup_message = followup_messages[0]
-
- followup_message.last_sent_at.should == Time.iso8601(sent_at)
- followup_message.body.should == followup_body.strip
- end
+ # POST /api/v2/request/:id/update.json
+ describe 'updating a request\'s status' do
+ it 'should update the status' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+ request = InfoRequest.find_by_id(request_id)
+
+ # Its status should be the default for a new request
+ request.described_state.should == 'waiting_response'
+
+ # Now accept an update
+ post :update_state,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :state => 'partially_successful'
+
+ # It should have updated the status
+ request = InfoRequest.find_by_id(request_id)
+ request.described_state.should == 'partially_successful'
+
+ # It should have recorded the status_update event
+ last_event = request.info_request_events.last
+ last_event.event_type.should == 'status_update'
+ last_event.described_state.should == 'partially_successful'
+ last_event.params_yaml.should =~ /script: Geraldine Quango on behalf of requester via API/
+ end
- it "should not allow internal requests to be updated" do
- n_incoming_messages = IncomingMessage.count
- n_outgoing_messages = OutgoingMessage.count
-
- request_id = info_requests(:naughty_chicken_request).id
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "request",
- "sent_at" => Time.now.iso8601,
- "body" => "xxx"
- }.to_json
-
- response.status.should == 500
- ActiveSupport::JSON.decode(response.body)["errors"].should == [
- "Request #{request_id} cannot be updated using the API"]
-
- IncomingMessage.count.should == n_incoming_messages
- OutgoingMessage.count.should == n_outgoing_messages
- end
+ it 'should return a JSON 500 error if an invalid state is sent' do
+ # First we need an external request
+ request_id = info_requests(:external_request).id
+ request = InfoRequest.find_by_id(request_id)
- it "should not allow other people's requests to be updated" do
- request_id = _create_request
- n_incoming_messages = IncomingMessage.count
- n_outgoing_messages = OutgoingMessage.count
-
- post :add_correspondence,
- :k => public_bodies(:humpadink_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "request",
- "sent_at" => Time.now.iso8601,
- "body" => "xxx"
- }.to_json
-
- response.status.should == 500
- ActiveSupport::JSON.decode(response.body)["errors"].should == [
- "You do not own request #{request_id}"]
-
- IncomingMessage.count.should == n_incoming_messages
- OutgoingMessage.count.should == n_outgoing_messages
- end
+ # Its status should be the default for a new request
+ request.described_state.should == 'waiting_response'
- it "should not allow files to be attached to a followup" do
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => info_requests(:external_request).id,
- :correspondence_json => {
- "direction" => "request",
- "sent_at" => Time.now.iso8601,
- "body" => "Are you joking, or are you serious?"
- }.to_json,
- :attachments => [
- fixture_file_upload("/files/tfl.pdf")
- ]
+ # Now post an invalid update
+ post :update_state,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :state => 'random_string'
+ # Check that the error has been raised...
+ response.status.should == 500
+ ActiveSupport::JSON.decode(response.body)['errors'].should == ["'random_string' is not a valid request state"]
- # Make sure it worked
- response.status.should == 500
- errors = ActiveSupport::JSON.decode(response.body)["errors"]
- errors.should == ["You cannot attach files to messages in the 'request' direction"]
- end
+ # ..and that the status hasn't been updated
+ request = InfoRequest.find_by_id(request_id)
+ request.described_state.should == 'waiting_response'
+ end
- it "should allow files to be attached to a response" do
- # First we need an external request
- request_id = info_requests(:external_request).id
-
- # Initially it has no incoming messages
- IncomingMessage.count(:conditions => ["info_request_id = ?", request_id]).should == 0
-
- # Now add one
- sent_at = "2012-05-28T12:35:39+01:00"
- response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "response",
- "sent_at" => sent_at,
- "body" => response_body
- }.to_json,
- :attachments => [
- fixture_file_upload("/files/tfl.pdf")
- ]
+ it 'should return a JSON 404 error for non-existent requests' do
+ request_id = '123459876'
+ InfoRequest.stub(:find_by_id).with(request_id).and_return(nil)
- # And make sure it worked
- response.should be_success
- incoming_messages = IncomingMessage.all(:conditions => ["info_request_id = ?", request_id])
- incoming_messages.count.should == 1
- incoming_message = incoming_messages[0]
-
- incoming_message.sent_at.should == Time.iso8601(sent_at)
- incoming_message.get_main_body_text_folded.should be_equal_modulo_whitespace_to(response_body)
-
- # Get the attachment
- attachments = incoming_message.get_attachments_for_display
- attachments.size.should == 1
- attachment = attachments[0]
- attachment.filename.should == "tfl.pdf"
- attachment.body.should == load_file_fixture("tfl.pdf")
- end
+ post :update_state,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :state => "successful"
- it "should show information about a request" do
- info_request = info_requests(:naughty_chicken_request)
- get :show_request,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => info_request.id
-
- response.should be_success
- assigns[:request].id.should == info_request.id
-
- r = ActiveSupport::JSON.decode(response.body)
- r["title"].should == info_request.title
- # Let’s not test all the fields here, because it would
- # essentially just be a matter of copying the code that
- # assigns them and changing assignment to an equality
- # check, which does not really test anything at all.
- end
+ response.status.should == 404
+ ActiveSupport::JSON.decode(response.body)['errors'].should == ['Could not find request 123459876']
+ end
- it 'should show information about an external request' do
- info_request = info_requests(:external_request)
- get :show_request,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => info_request.id
+ it 'should return a JSON 403 error if we try to add correspondence to a request we don\'t own' do
+ request_id = info_requests(:naughty_chicken_request).id
- response.should be_success
- assigns[:request].id.should == info_request.id
- r = ActiveSupport::JSON.decode(response.body)
- r["title"].should == info_request.title
- end
+ post :update_state,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => request_id,
+ :state => 'successful'
- it "should show an Atom feed of new request events" do
- get :body_request_events,
- :id => public_bodies(:geraldine_public_body).id,
- :k => public_bodies(:geraldine_public_body).api_key,
- :feed_type => "atom"
-
- response.should be_success
- response.should render_template("api/request_events")
- assigns[:events].size.should > 0
- assigns[:events].each do |event|
- event.info_request.public_body.should == public_bodies(:geraldine_public_body)
- event.outgoing_message.should_not be_nil
- event.event_type.should satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)}
+ response.status.should == 403
+ ActiveSupport::JSON.decode(response.body)['errors'].should == ["Request #{request_id} cannot be updated using the API"]
end
end
- it "should show a JSON feed of new request events" do
- get :body_request_events,
- :id => public_bodies(:geraldine_public_body).id,
- :k => public_bodies(:geraldine_public_body).api_key,
- :feed_type => "json"
-
- response.should be_success
- assigns[:events].size.should > 0
- assigns[:events].each do |event|
- event.info_request.public_body.should == public_bodies(:geraldine_public_body)
- event.outgoing_message.should_not be_nil
- event.event_type.should satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)}
+ # GET /api/v2/request/:id.json
+ describe 'showing request info' do
+ it 'should show information about a request' do
+ info_request = info_requests(:naughty_chicken_request)
+
+ get :show_request,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => info_request.id
+
+ response.should be_success
+ assigns[:request].id.should == info_request.id
+
+ r = ActiveSupport::JSON.decode(response.body)
+ r['title'].should == info_request.title
+ # Let’s not test all the fields here, because it would
+ # essentially just be a matter of copying the code that
+ # assigns them and changing assignment to an equality
+ # check, which does not really test anything at all.
end
- assigns[:event_data].size.should == assigns[:events].size
- assigns[:event_data].each do |event_record|
- event_record[:event_type].should satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)}
+ it 'should show information about an external request' do
+ info_request = info_requests(:external_request)
+ get :show_request,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :id => info_request.id
+
+ response.should be_success
+ assigns[:request].id.should == info_request.id
+ r = ActiveSupport::JSON.decode(response.body)
+ r['title'].should == info_request.title
end
end
- it "should honour the since_event_id parameter" do
- get :body_request_events,
- :id => public_bodies(:geraldine_public_body).id,
- :k => public_bodies(:geraldine_public_body).api_key,
- :feed_type => "json"
- response.should be_success
- first_event = assigns[:event_data][0]
- second_event_id = assigns[:event_data][1][:event_id]
-
- get :body_request_events,
- :id => public_bodies(:geraldine_public_body).id,
- :k => public_bodies(:geraldine_public_body).api_key,
- :feed_type => "json",
- :since_event_id => second_event_id
- response.should be_success
- assigns[:event_data].should == [first_event]
- end
+ # GET /api/v2/body/:id/request_events.:feed_type
+ describe 'showing public body info' do
+ it 'should show an Atom feed of new request events' do
+ get :body_request_events,
+ :id => public_bodies(:geraldine_public_body).id,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :feed_type => 'atom'
+
+ response.should be_success
+ response.should render_template('api/request_events')
+ assigns[:events].size.should > 0
+ assigns[:events].each do |event|
+ event.info_request.public_body.should == public_bodies(:geraldine_public_body)
+ event.outgoing_message.should_not be_nil
+ event.event_type.should satisfy { |x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x) }
+ end
+ end
- it "should honour the since_date parameter for the Atom feed" do
- get :body_request_events,
- :id => public_bodies(:humpadink_public_body).id,
- :k => public_bodies(:humpadink_public_body).api_key,
- :since_date => "2010-01-01",
- :feed_type => "atom"
-
- response.should be_success
- response.should render_template("api/request_events")
- assigns[:events].size.should > 0
- assigns[:events].each do |event|
- event.created_at.should >= Date.new(2010, 1, 1)
+ it 'should show a JSON feed of new request events' do
+ get :body_request_events,
+ :id => public_bodies(:geraldine_public_body).id,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :feed_type => 'json'
+
+ response.should be_success
+ assigns[:events].size.should > 0
+ assigns[:events].each do |event|
+ event.info_request.public_body.should == public_bodies(:geraldine_public_body)
+ event.outgoing_message.should_not be_nil
+ event.event_type.should satisfy {|x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x)}
+ end
+
+ assigns[:event_data].size.should == assigns[:events].size
+ assigns[:event_data].each do |event_record|
+ event_record[:event_type].should satisfy { |x| ['sent', 'followup_sent', 'resent', 'followup_resent'].include?(x) }
+ end
end
- end
- it "should return a JSON 404 error for non-existent requests" do
- request_id = 123459876 # Let's hope this doesn't exist!
- sent_at = "2012-05-28T12:35:39+01:00"
- response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "response",
- "sent_at" => sent_at,
- "body" => response_body
- }.to_json
- response.status.should == 404
- ActiveSupport::JSON.decode(response.body)["errors"].should == ["Could not find request 123459876"]
- end
+ it 'should honour the since_event_id parameter' do
+ get :body_request_events,
+ :id => public_bodies(:geraldine_public_body).id,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :feed_type => 'json'
+
+ response.should be_success
+ first_event = assigns[:event_data][0]
+ second_event_id = assigns[:event_data][1][:event_id]
+
+ get :body_request_events,
+ :id => public_bodies(:geraldine_public_body).id,
+ :k => public_bodies(:geraldine_public_body).api_key,
+ :feed_type => 'json',
+ :since_event_id => second_event_id
+ response.should be_success
+ assigns[:event_data].should == [first_event]
+ end
- it "should return a JSON 500 error if we try to add correspondence to a request we don't own" do
- request_id = info_requests(:naughty_chicken_request).id
- sent_at = "2012-05-28T12:35:39+01:00"
- response_body = "Thank you for your request for information, which we are handling in accordance with the Freedom of Information Act 2000. You will receive a response within 20 working days or before the next full moon, whichever is sooner.\n\nYours sincerely,\nJohn Gandermulch,\nExample Council FOI Officer\n"
- post :add_correspondence,
- :k => public_bodies(:geraldine_public_body).api_key,
- :id => request_id,
- :correspondence_json => {
- "direction" => "response",
- "sent_at" => sent_at,
- "body" => response_body
- }.to_json
- response.status.should == 500
- ActiveSupport::JSON.decode(response.body)["errors"].should == ["Request #{request_id} cannot be updated using the API"]
+ it 'should honour the since_date parameter' do
+ get :body_request_events,
+ :id => public_bodies(:humpadink_public_body).id,
+ :k => public_bodies(:humpadink_public_body).api_key,
+ :since_date => '2010-01-01',
+ :feed_type => 'atom'
+
+ response.should be_success
+ response.should render_template('api/request_events')
+ assigns[:events].size.should > 0
+ assigns[:events].each do |event|
+ event.created_at.should >= Date.new(2010, 1, 1)
+ end
+
+ get :body_request_events,
+ :id => public_bodies(:humpadink_public_body).id,
+ :k => public_bodies(:humpadink_public_body).api_key,
+ :since_date => '2010-01-01',
+ :feed_type => 'json'
+ assigns[:events].each do |event|
+ event.created_at.should >= Date.new(2010, 1, 1)
+ end
+ end
end
end