aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/helpers/application_helper.rb3
-rw-r--r--app/helpers/date_time_helper.rb69
-rwxr-xr-xapp/helpers/link_to_helper.rb83
-rw-r--r--app/mailers/request_mailer.rb2
-rw-r--r--app/models/incoming_message.rb15
-rw-r--r--app/views/track_mailer/event_digest.text.erb6
-rw-r--r--app/views/user/_user_listing_single.html.erb2
-rw-r--r--app/views/user/show.html.erb2
-rw-r--r--doc/DEPLOY.md41
-rw-r--r--doc/INSTALL-exim4.md99
-rw-r--r--doc/INSTALL-postfix.md68
-rw-r--r--doc/INSTALL.md651
-rw-r--r--doc/README.md9
-rw-r--r--doc/THEMES.md165
-rw-r--r--doc/TRANSLATE.md106
-rw-r--r--lib/attachment_to_html/adapters/rtf.rb2
-rw-r--r--spec/helpers/date_time_helper_spec.rb71
-rw-r--r--spec/helpers/link_to_helper_spec.rb123
-rw-r--r--spec/lib/attachment_to_html/adapters/rtf_spec.rb11
-rw-r--r--spec/models/incoming_message_spec.rb18
20 files changed, 293 insertions, 1253 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 33525cb3d..45b042354 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -13,6 +13,9 @@ module ApplicationHelper
# all of all.
include LinkToHelper
+ # Some extra date and time formatters
+ include DateTimeHelper
+
# Site-wide access to configuration settings
include ConfigHelper
diff --git a/app/helpers/date_time_helper.rb b/app/helpers/date_time_helper.rb
new file mode 100644
index 000000000..5f129e590
--- /dev/null
+++ b/app/helpers/date_time_helper.rb
@@ -0,0 +1,69 @@
+module DateTimeHelper
+ # Public: Usually-correct format for a DateTime-ish object
+ # To define a new new format define the `simple_date_{FORMAT}` method
+ #
+ # date - a DateTime, Date or Time
+ # opts - a Hash of options (default: { format: :html})
+ # :format - :html returns a HTML <time> tag
+ # :text returns a plain String
+ #
+ # Examples
+ #
+ # simple_date(Time.now)
+ # # => "<time>..."
+ #
+ # simple_date(Time.now, :format => :text)
+ # # => "March 10, 2014"
+ #
+ # Returns a String
+ # Raises ArgumentError if the format is unrecognized
+ def simple_date(date, opts = {})
+ opts = { :format => :html }.merge(opts)
+ date_formatter = "simple_date_#{ opts[:format] }"
+
+ if respond_to?(date_formatter)
+ send(date_formatter, date)
+ else
+ raise ArgumentError, "Unrecognized format :#{ opts[:format] }"
+ end
+ end
+
+ # Usually-correct HTML formatting of a DateTime-ish object
+ # Use LinkToHelper#simple_date with desired formatting options
+ #
+ # date - a DateTime, Date or Time
+ #
+ # Returns a String
+ def simple_date_html(date)
+ date = date.in_time_zone unless date.is_a?(Date)
+ time_tag date, simple_date_text(date), :title => date.to_s
+ end
+
+ # Usually-correct plain text formatting of a DateTime-ish object
+ # Use LinkToHelper#simple_date with desired formatting options
+ #
+ # date - a DateTime, Date or Time
+ #
+ # Returns a String
+ def simple_date_text(date)
+ date = date.in_time_zone.to_date unless date.is_a? Date
+
+ date_format = _('simple_date_format')
+ date_format = :long if date_format == 'simple_date_format'
+ I18n.l(date, :format => date_format)
+ end
+
+ # Strips the date from a DateTime
+ #
+ # date - a DateTime, Date or Time
+ #
+ # Examples
+ #
+ # simple_time(Time.now)
+ # # => "10:46:54"
+ #
+ # Returns a String
+ def simple_time(date)
+ date.strftime("%H:%M:%S").strip
+ end
+end
diff --git a/app/helpers/link_to_helper.rb b/app/helpers/link_to_helper.rb
index dd6ffa805..3709469cf 100755
--- a/app/helpers/link_to_helper.rb
+++ b/app/helpers/link_to_helper.rb
@@ -28,19 +28,19 @@ module LinkToHelper
# Incoming / outgoing messages
def incoming_message_url(incoming_message, options = {})
- return request_url(incoming_message.info_request, options.merge(:anchor => "incoming-#{incoming_message.id}"))
+ message_url(incoming_message, options)
end
def incoming_message_path(incoming_message)
- incoming_message_url(incoming_message, :only_path => true)
+ message_path(incoming_message)
end
def outgoing_message_url(outgoing_message, options = {})
- request_url(outgoing_message.info_request, options.merge(:anchor => "outgoing-#{outgoing_message.id}"))
+ message_url(outgoing_message, options)
end
def outgoing_message_path(outgoing_message)
- outgoing_message_url(outgoing_message, :only_path => true)
+ message_path(outgoing_message)
end
def comment_url(comment, options = {})
@@ -279,73 +279,30 @@ module LinkToHelper
end
end
- # Public: Usually-correct format for a DateTime-ish object
- # To define a new new format define the `simple_date_{FORMAT}` method
- #
- # date - a DateTime, Date or Time
- # opts - a Hash of options (default: { format: :html})
- # :format - :html returns a HTML <time> tag
- # :text returns a plain String
- #
- # Examples
- #
- # simple_date(Time.now)
- # # => "<time>..."
- #
- # simple_date(Time.now, :format => :text)
- # # => "March 10, 2014"
- #
- # Returns a String
- # Raises ArgumentError if the format is unrecognized
- def simple_date(date, opts = {})
- opts = { :format => :html }.merge(opts)
- date_formatter = "simple_date_#{ opts[:format] }"
-
- if respond_to?(date_formatter)
- send(date_formatter, date)
- else
- raise ArgumentError, "Unrecognised format :#{ opts[:format] }"
- end
- end
+ #I18n locale switcher
- # Usually-correct HTML formatting of a DateTime-ish object
- # Use LinkToHelper#simple_date with desired formatting options
- #
- # date - a DateTime, Date or Time
- #
- # Returns a String
- def simple_date_html(date)
- date = date.in_time_zone unless date.is_a? Date
- time_tag date, simple_date_text(date), :title => date.to_s
+ def locale_switcher(locale, params)
+ params['locale'] = locale
+ return url_for(params)
end
- # Usually-correct plain text formatting of a DateTime-ish object
- # Use LinkToHelper#simple_date with desired formatting options
- #
- # date - a DateTime, Date or Time
- #
- # Returns a String
- def simple_date_text(date)
- date = date.in_time_zone.to_date unless date.is_a? Date
+ private
- date_format = _("simple_date_format")
- date_format = :long if date_format == "simple_date_format"
- I18n.l(date, :format => date_format)
- end
+ # Private: Generate a request_url linking to the new correspondence
+ def message_url(message, options = {})
+ message_type = message.class.to_s.gsub('Message', '').downcase
- def simple_time(date)
- return date.strftime("%H:%M:%S").strip
- end
+ default_options = { :anchor => "#{ message_type }-#{ message.id }" }
- def year_from_date(date)
- return date.strftime("%Y").strip
- end
+ if options.delete(:cachebust)
+ default_options.merge!(:nocache => "#{ message_type }-#{ message.id }")
+ end
- #I18n locale switcher
+ request_url(message.info_request, options.merge(default_options))
+ end
- def locale_switcher(locale, params)
- params['locale'] = locale
- return url_for(params)
+ def message_path(message)
+ message_url(message, :only_path => true)
end
end
diff --git a/app/mailers/request_mailer.rb b/app/mailers/request_mailer.rb
index 360549f0c..768257ba8 100644
--- a/app/mailers/request_mailer.rb
+++ b/app/mailers/request_mailer.rb
@@ -71,7 +71,7 @@ class RequestMailer < ApplicationMailer
def new_response(info_request, incoming_message)
# Don't use login link here, just send actual URL. This is
# because people tend to forward these emails amongst themselves.
- @url = incoming_message_url(incoming_message)
+ @url = incoming_message_url(incoming_message, :cachebust => true)
@incoming_message, @info_request = incoming_message, info_request
headers('Return-Path' => blackhole_email,
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index 39a5c996e..135a6bdaf 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -834,14 +834,15 @@ class IncomingMessage < ActiveRecord::Base
def fully_destroy
ActiveRecord::Base.transaction do
- for o in self.outgoing_message_followups
- o.incoming_message_followup = nil
- o.save!
+ outgoing_message_followups.each do |outgoing_message_followup|
+ outgoing_message_followup.incoming_message_followup = nil
+ outgoing_message_followup.save!
+ end
+ info_request_events.each do |info_request_event|
+ info_request_event.track_things_sent_emails.each { |a| a.destroy }
+ info_request_event.user_info_request_sent_alerts.each { |a| a.destroy }
+ info_request_event.destroy
end
- info_request_event = InfoRequestEvent.find_by_incoming_message_id(self.id)
- info_request_event.track_things_sent_emails.each { |a| a.destroy }
- info_request_event.user_info_request_sent_alerts.each { |a| a.destroy }
- info_request_event.destroy
self.raw_email.destroy_file_representation!
self.destroy
end
diff --git a/app/views/track_mailer/event_digest.text.erb b/app/views/track_mailer/event_digest.text.erb
index b83c184f0..a154f430f 100644
--- a/app/views/track_mailer/event_digest.text.erb
+++ b/app/views/track_mailer/event_digest.text.erb
@@ -17,14 +17,14 @@
# e.g. Julian Burgess sent a request to Royal Mail Group (15 May 2008)
if event.event_type == 'response'
- url = incoming_message_url(event.incoming_message)
+ url = incoming_message_url(event.incoming_message, :cachebust => true)
main_text += _("{{public_body}} sent a response to {{user_name}}", :public_body => event.info_request.public_body.name, :user_name => event.info_request.user_name)
elsif event.event_type == 'followup_sent'
- url = outgoing_message_url(event.outgoing_message)
+ url = outgoing_message_url(event.outgoing_message, :cachebust => true)
main_text += _("{{user_name}} sent a follow up message to {{public_body}}", :user_name => event.info_request.user_name, :public_body => event.info_request.public_body.name)
elsif event.event_type == 'sent'
# this is unlikely to happen in real life, but happens in the test code
- url = outgoing_message_url(event.outgoing_message)
+ url = outgoing_message_url(event.outgoing_message, :cachebust => true)
main_text += _("{{user_name}} sent a request to {{public_body}}", :user_name => event.info_request.user_name, :public_body => event.info_request.public_body.name)
elsif event.event_type == 'comment'
url = comment_url(event.comment)
diff --git a/app/views/user/_user_listing_single.html.erb b/app/views/user/_user_listing_single.html.erb
index ed1b95718..3cb0d283f 100644
--- a/app/views/user/_user_listing_single.html.erb
+++ b/app/views/user/_user_listing_single.html.erb
@@ -18,7 +18,7 @@ end %>
<span class="bottomline">
<%= pluralize(display_user.info_requests.size, "request") %> <%= _('made.')%>
<%= pluralize(display_user.visible_comments.size, "annotation") %> <%= _('made.')%>
- <%= _('Joined in')%> <%= year_from_date(display_user.created_at) %>.
+ <%= _('Joined in')%> <%= display_user.created_at.year %>.
</span>
</div>
diff --git a/app/views/user/show.html.erb b/app/views/user/show.html.erb
index ce328b46f..7ae577565 100644
--- a/app/views/user/show.html.erb
+++ b/app/views/user/show.html.erb
@@ -64,7 +64,7 @@
<h1> <%= h(@display_user.name) + (@is_you ? _(" (you)") : "") %></h1>
<p class="subtitle">
- <%= _('Joined {{site_name}} in', :site_name=>site_name) %> <%= year_from_date(@display_user.created_at) %>
+ <%= _('Joined {{site_name}} in', :site_name=>site_name) %> <%= @display_user.created_at.year %>
<% if !@user.nil? && @user.admin_page_links? %>
(<%= link_to "admin", admin_user_show_path(@display_user) %>)
<% end %>
diff --git a/doc/DEPLOY.md b/doc/DEPLOY.md
deleted file mode 100644
index f2e643ec5..000000000
--- a/doc/DEPLOY.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Deployment
-
-mySociety uses a custom deployment and buildout system however Capistrano is included as part of Alaveteli as a standard deployment system.
-
-## Capistrano
-
-### Set up
-
-First you need to customise your deployment settings, e.g. the name of the server you're deploying to. This is done by copying the example file `config/deploy.yml.example` to `config/deploy.yml` and editing the settings to suit you.
-
-TODO: The following instructions could be greatly improved
-
-These are the general steps required to get your staging server up and running:
-
-* Install packages from `config/packages`
-* Install Postgres and configure a user
-* Create a directory to deploy to and make sure your deployment user can write to it
-* Run `cap deploy:setup` to create directories, etc.
-* Run `cap deploy:update_code` so that we've got a copy of the example config on the server. This process will take a long time installing gems, etc. it will also fail on `rake:themes:install` but that's OK
-* SSH to the server, change to the `deploy_to` directory
-* `cp releases/[SOME_DATE]/config/general.yml-example shared/general.yml`
-* `cp releases/[SOME_DATE]/config/database.yml-example shared/database.yml`
-* Edit those files to match your required settings
-* Back on your machine run `cap deploy` and it should successfully deploy
-* Run the DB migrations `cap deploy:migrate`
-* Build the Xapian DB `cap xapian:rebuild_index`
-* Configure Apache/Passenger with a DocumentRoot of `your_deploy_to/current/public`
-* Phew. Time to admire your work by browsing to the server!
-
-### Usage
-
-Ensure you've got a `config/deploy.yml` file with the correct settings for your site. You'll need to share this with everyone in your team that deploys so it might be a good idea to keep the latest version in a [Gist](http://gist.github.com/).
-
-To deploy to staging just run `cap deploy` but if you want to deploy to production you need to run `cap -S stage=production deploy`.
-
-For additional usage instructions, see the [Capistrano wiki](https://github.com/capistrano/capistrano/wiki/).
-
-### TODO
-
-* Get `cap deploy:setup` to do most of the work described above in the *Set up* section
-* Use [Whenever](https://github.com/javan/whenever) to set up cronjobs
diff --git a/doc/INSTALL-exim4.md b/doc/INSTALL-exim4.md
deleted file mode 100644
index 796fb295c..000000000
--- a/doc/INSTALL-exim4.md
+++ /dev/null
@@ -1,99 +0,0 @@
-As an example of how to set up your MTA, in exim on Ubuntu, you might
-add the following to its configuration.
-
-In `/etc/exim4/conf.d/main/04_alaveteli_options`:
-
- ALAVETELI_HOME=/path/to/alaveteli/software
- ALAVETELI_USER=www-data
- log_file_path=/var/log/exim4/exim-%slog-%D
- MAIN_LOG_SELECTOR==+all -retry_defer
- extract_addresses_remove_arguments=false
-
-(The user ALAVETELI_USER should have write permissions on ALAVETELI_HOME).
-
-Note that the name and location of the log files created by Exim must match
-what the `load-mail-server-logs` script expects, hence the need for the extra
-`log_file_path` setting. And the `check-recent-requests-sent` scripts expects
-the logs to contain the `from=<...>` envelope information, so we make the
-logs more verbose with `log_selector`. The ALAVETELI_USER may need to also
-need to be added to the `trusted_users` list in your Exim config in order to
-set the return path on outgoing mail, depending on your setup.
-
-In `/etc/exim4/conf.d/router/04_alaveteli`:
-
- alaveteli_request:
- debug_print = "R: alaveteli for $local_part@$domain"
- driver = redirect
- data = ${lookup{$local_part}wildlsearch{ALAVETELI_HOME/config/aliases}}
- pipe_transport = alaveteli_mailin_transport
-
-In `/etc/exim4/conf.d/transport/04_alaveteli`:
-
- alaveteli_mailin_transport:
- driver = pipe
- command = $address_pipe ${lc:$local_part}
- current_directory = ALAVETELI_HOME
- home_directory = ALAVETELI_HOME
- user = ALAVETELI_USER
- group = ALAVETELI_USER
-
-And, assuming you set `INCOMING_EMAIL_PREFIX` in your config at
-`config/general` to "foi+", create `config/aliases` with the following
-content:
-
- ^foi\\+.*: |/path/to/alaveteli/software/script/mailin
-
-You should also configure exim to discard any messages sent to the
-`BLACKHOLE_PREFIX` address, whose default value is
-'do-not-reply-to-this-address'. For example, add the following to
-config/aliases:
-
- # We use this for envelope from for some messages where we don't care about delivery
- do-not-reply-to-this-address: :blackhole:
-
-If you want to make use of the automatic bounce-message handling, then
-set the `TRACK_SENDER_EMAIL` address to be filtered through
-`script/handle-mail-replies`. Messages that are not bounces or
-out-of-office autoreplies will be forwarded to
-`FORWARD_NONBOUNCE_RESPONSES_TO`. For example, in WhatDoTheyKnow the
-configuration looks like this:
-
- raw_team: [a list of people on the team]
- team: |/path/to/alaveteli/software/script/handle-mail-replies
-
-with `FORWARD_NONBOUNCE_RESPONSES_TO: 'raw_team@whatdotheyknow.com'`
-
-Finally, make sure you have `dc_use_split_config='true'` in
-`/etc/exim4/update-exim4.conf.conf`, and execute the command
-`update-exim4.conf`.
-
-NB: if the file `/etc/exim4/exim4.conf` exists then `update-exim4.conf`
-will silently do nothing. Some distributions include this file. If
-yours does, you will need to rename it before running `update-exim4.conf`.
-
-(You may also want to set `dc_eximconfig_configtype='internet'`,
-`dc_local_interfaces='0.0.0.0 ; ::1'`, and
-`dc_other_hostnames='<your-host-name>'`)
-
-# Troubleshooting
-
-To test mail delivery, run:
-
- exim -bt foi+request-1234@localhost
-
-This should tell you which routers are being processed. You should
-see something like:
-
- $ exim -bt foi+request-1234@localhost
- R: alaveteli pipe for snafflerequest-234@localhost
- snafflerequest-234@localhost -> |/home/alaveteli/alaveteli/script/mailin
- transport = alaveteli_mailin_transport
-
-This tells you that the routing part (making emails to
-`foi\+.*@localhost` be forwarded to Alaveteli's `mailin` script) is
-working.
-
-There is a great
-[Exim Cheatsheet](http://bradthemad.org/tech/notes/exim_cheatsheet.php)
-online that you may find useful.
-
diff --git a/doc/INSTALL-postfix.md b/doc/INSTALL-postfix.md
deleted file mode 100644
index a73d67ce1..000000000
--- a/doc/INSTALL-postfix.md
+++ /dev/null
@@ -1,68 +0,0 @@
-As an example of how to set up your MTA, in postfix on Ubuntu, you might
-add the following to its configuration.
-
-In /etc/postfix/master.cf:
-
- alaveteli unix - n n - 50 pipe
- flags=R user=ALAVETELI_USER argv=ALAVETELI_HOME/script/mailin
-
-In /etc/postfix/main.cf
-
- virtual_alias_maps = regexp:/etc/postfix/regexp
-
-For example
-
-ALAVETELI_HOME=/path/to/alaveteli/software
-ALAVETELI_USER=www-data
-
-The user ALAVETELI_USER should have write permissions on ALAVETELI_HOME.
-
-And, assuming you set `OPTION_INCOMING_EMAIL_PREFIX` in your config at
-`config/general` to "foi+", create `/etc/postfix/regexp` with the following
-content:
-
- /^foi.*/ alaveteli
-
-
-You should also configure postfix to discard any messages sent to the `BLACKHOLE_PREFIX`
-address, whose default value is 'do-not-reply-to-this-address'. For example, add the
-following to /etc/aliases:
-
- # We use this for envelope from for some messages where we don't care about delivery
- do-not-reply-to-this-address: :blackhole:
-
-# Logging
-
-For the postfix logs to be read by the script 'load-mail-server-logs' succesfully they need to be log rotated with a date in the filename. Since that will create a lot of rotated log files (one for each day), it's good to have them in their own directory. For example (on Ubuntu) /etc/rsyslog.d/50-default.conf
-
- mail.* -/var/log/mail/mail.log
-
-And also edit /etc/logrotate.d/rsyslog:
-
- /var/log/mail/mail.log
- {
- rotate 30
- daily
- dateext
- missingok
- notifempty
- compress
- delaycompress
- sharedscripts
- postrotate
- reload rsyslog >/dev/null 2>&1 || true
- endscript
- }
-
-You'll also need to tell Alaveteli where the log files are stored and that they're in postfix format. Update config/general.yml with:
-
- MTA_LOG_PATH: '/var/log/mail/mail.log-*'
- MTA_LOG_TYPE: "postfix"
-
-# Troubleshooting
-
-To test mail delivery, run:
-
- $ /usr/sbin/sendmail -bv foi+requrest-1234@localhost
-
-This tells you if sending the emails to 'foi\+.*localhost' is working.
diff --git a/doc/INSTALL.md b/doc/INSTALL.md
deleted file mode 100644
index f6563be99..000000000
--- a/doc/INSTALL.md
+++ /dev/null
@@ -1,651 +0,0 @@
-# Installation Script and AMI
-
-The easiest options for installating Alaveteli for evaluation
-are to use our install script or to use the AMI (Amazon Machine
-Image) to create an instance on Amazon EC2. These options are
-described below. If you would prefer to install the site
-manually, please go to the Manual Installation section below.
-
-## Installing from an AMI (Amazon Machine Image)
-
-To help people try out Alaveteli, we have created an AMI (Amazon
-Machine Image) with a basic installation of Alaveteli, which you
-can use to create a running server on an Amazon EC2 instance.
-This creates an instance that runs in development mode, so we
-wouldn't recommend you use it for a production system without
-changing the configuration.
-
-Unfortunately, Alaveteli will not run properly on a free Micro
-instance due to the low amount of memory available on those
-instances; you will need to use at least a Small instance, which
-Amazon will charge for.
-
-The AMI can be found in the EU West (Ireland) region, with the
-ID ami-8603f4f1 and name “Basic Alaveteli installation
-2014-01-29”. You can launch an instance based on that AMI with
-[this link](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchAmi=ami-8603f4f1).
-
-When you create an EC2 instance based on that AMI, make sure
-that you choose Security Groups that allows at least inbound
-HTTP, HTTPS, SSH and, if you want to test incoming mail as well,
-SMTP.
-
-When your EC2 instance is launched, you will be able to log in
-as the `ubuntu` user. This user can `sudo` freely to run
-commands as root. However, the code is actually owned by (and
-runs as) the `alaveteli` user. After creating the instance, you
-may want to edit a configuration file to customize the site's
-configuration. That configuration file is
-`/var/www/alaveteli/alaveteli/config/general.yml`, which can be
-edited with:
-
- ubuntu@ip-10-58-191-98:~$ sudo su - alaveteli
- alaveteli@ip-10-58-191-98:~$ cd alaveteli
- alaveteli@ip-10-58-191-98:~/alaveteli$ nano config/general.yml
-
-Then you should restart the Thin webserver with:
-
- alaveteli@ip-10-58-191-98:~/alaveteli$ logout
- ubuntu@ip-10-58-191-98:~$ sudo /etc/init.d/alaveteli restart
-
-If you find the hostname of your EC2 instance from the AWS
-console, you should then be able to see the site at
-`http://your-ec2-hostname.eu-west-1.compute.amazonaws.com`
-
-If you have any problems or questions, please ask on the
-[Alaveteli Google Group](https://groups.google.com/forum/#!forum/alaveteli-dev)
-or [report an issue](https://github.com/mysociety/alaveteli/issues?state=open).
-
-## Installing with the Installation Script
-
-If you have a clean installation of Debian squeeze or Ubuntu
-precise, you can use an install script in our commonlib
-repository to set up a working instance of Alaveteli. This is
-not suitable for production (it runs in development mode, for
-example) but should set up a functional installation of the
-site.
-
-**Warning: only use this script on a newly installed server – it
-will make significant changes to your server’s setup, including
-modifying your nginx setup, creating a user account, creating a
-database, installing new packages etc.**
-
-To download the script, run the following command:
-
- curl -O https://raw.github.com/mysociety/commonlib/master/bin/install-site.sh
-
-If you run this script with `sh install-site.sh`, you'll see its
-usage message:
-
- Usage: ./install-site.sh [--default] <SITE-NAME> <UNIX-USER> [HOST]
- HOST is only optional if you are running this on an EC2 instance.
- --default means to install as the default site for this server,
- rather than a virtualhost for HOST.
-
-In this case `<SITE-NAME>` should be `alaveteli`. `<UNIX-USER>`
-is the name of the Unix user that you want to own and run the
-code. (This user will be created by the script.)
-
-The `HOST` parameter is a hostname for the server that will be
-usable externally – a virtualhost for this name will be created
-by the script, unless you specified the `--default` option. This
-parameter is optional if you are on an EC2 instance, in which
-case the hostname of that instance will be used.
-
-For example, if you wish to use a new user called `alaveteli`
-and the hostname `alaveteli.127.0.0.1.xip.io`, creating a
-virtualhost just for that hostname, you could download and run
-the script with:
-
- sudo sh install-site.sh alaveteli alaveteli alaveteli.127.0.0.1.xip.io
-
-([xip.io](http://xip.io/) is a helpful domain for development.)
-
-Or, if you want to set this up as the default site on an EC2
-instance, you could download the script, make it executable and
-then invoke it with:
-
- sudo ./install-site.sh --default alaveteli alaveteli
-
-When the script has finished, you should have a working copy of
-the website, accessible via the hostname you supplied to the
-script.
-
-If you have any problems or questions, please ask on the
-[Alaveteli Google Group](https://groups.google.com/forum/#!forum/alaveteli-dev)
-or [report an issue](https://github.com/mysociety/alaveteli/issues?state=open).
-
-# Manual Installation
-
-These instructions assume Debian Squeeze (64-bit) or Ubuntu 12.04 LTS (precise).
-[Install instructions for OS X](https://github.com/mysociety/alaveteli/wiki/OS-X-Quickstart)
-are under development. Debian Squeeze is the best supported
-deployment platform.
-
-Commands are intended to be run via the terminal or over ssh.
-
-As an aid to evaluation, there is an
-[Amazon AMI](https://github.com/mysociety/alaveteli/wiki/Alaveteli-ec2-ami)
-with all these steps configured. It is *not* production-ready.
-
-## Get Alaveteli
-
-To start with, you may need to install git, e.g. with `sudo apt-get
-install git-core`
-
-Next, get hold of the Alaveteli source code from github:
-
- git clone https://github.com/mysociety/alaveteli.git
- cd alaveteli
-
-This will get the development branch, which has the latest (possibly
-buggy) code. If you don't want to add or try new features, swap to the
-master branch (which always contains the latest stable release):
-
- git checkout master
-
-## Package pinning
-
-You need to configure [apt-pinning](http://wiki.debian.org/AptPreferences#Pinning-1) preferences in order to prevent packages being pulled from the debian wheezy distribution in preference to the stable distribution once you have added the wheezy repository as described below.
-
-In order to configure apt-pinning and to keep most packages coming from the Debian stable repository while installing the ones required from wheezy and the mySociety repository you need to run the following commands:
-
- echo "Package: *" >> /tmp/preferences
- echo "Pin: release a=squeeze-backports">> /tmp/preferences
- echo "Pin-Priority: 200" >> /tmp/preferences
- echo "" >> /tmp/preferences
- echo "Package: *" >> /tmp/preferences
- echo "Pin: release a=wheezy">> /tmp/preferences
- echo "Pin-Priority: 50" >> /tmp/preferences
- sudo cp /tmp/preferences /etc/apt/
- rm /tmp/preferences
-
-## Install system dependencies
-
-These are packages that the software depends on: third-party software
-used to parse documents, host the site, etc. There are also packages
-that contain headers necessary to compile some of the gem dependencies
-in the next step.
-
-If you are running Debian, add the following repositories to
-`/etc/apt/sources.list` and run `apt-get update`:
-
- deb http://debian.mysociety.org squeeze main
- deb http://ftp.debian.org/debian/ wheezy main non-free contrib
- deb http://backports.debian.org/debian-backports squeeze-backports main contrib non-free
-
-The repositories above allow us to install the packages
-`wkhtmltopdf-static` and `bundler` using `apt`; so if you're running
-Ubuntu, you won't be able to use the above repositories, and you will
-need to comment out those two lines in `config/packages` before
-following the next step (and install bundler manually).
-
-Now install the packages that are listed in config/packages using apt-get
-e.g.:
-
- sudo apt-get install `cut -d " " -f 1 config/packages | grep -v "^#"`
-
-Some of the files also have a version number listed in config/packages
-- check that you have appropriate versions installed. Some also list
-"|" and offer a choice of packages.
-
-## Install Ruby dependencies
-
-To install Alaveteli's Ruby dependencies, we need to install
-bundler. In Debian, this is provided as a package (installed as part
-of the package install process above). You could also install it as a
-gem:
-
- sudo gem1.8 install bundler
-
-## Install mySociety libraries
-
-You will also want to install mySociety's common ruby libraries and the Rails
-code. Run:
-
- git submodule update --init
-
-to fetch the contents of the submodules.
-
-### Packages customised by mySociety
-
-Debian users should add the mySociety debian archive to their
-`/etc/apt/sources.list` as described above. Doing this and following
-the above instructions should install a couple of custom
-dependencies. Users of other platforms can optionally install these
-dependencies manually, as follows:
-
-1. If you would like users to be able to download pretty PDFs as part of
-the downloadable zipfile of their request history, you should install
-[wkhtmltopdf](http://code.google.com/p/wkhtmltopdf/downloads/list).
-We recommend downloading the latest, statically compiled version from
-the project website, as this allows running headless (i.e. without a
-graphical interface running) on Linux. If you do install
-`wkhtmltopdf`, you need to edit a setting in the config file to point
-to it (see below). If you don't install it, everything will still
-work, but users will get ugly, plain text versions of their requests
-when they download them.
-
-2. Version 1.44 of `pdftk` contains a bug which makes it to loop forever
-in certain edge conditions. Until it's incorporated into an official
-release, you can either hope you don't encounter the bug (it ties up a
-rails process until you kill it) you'll need to patch it yourself or
-use the Debian package compiled by mySociety (see link in
-[issue 305](https://github.com/mysociety/alaveteli/issues/305))
-
-
-## Configure Database
-
-There has been a little work done in trying to make the code work with
-other databases (e.g. SQLite), but the currently supported database is
-PostgreSQL.
-
-If you don't have it installed:
-
- apt-get install postgresql postgresql-client
-
-Now we need to set up the database config file to contain the name,
-username and password of your postgres database.
-
-* copy `database.yml-example` to `database.yml` in `alaveteli/config`
-* edit it to point to your local postgresql database in the development
- and test sections and create the databases:
-
-Make sure that the user specified in database.yml exists, and has full
-permissions on these databases. As they need the ability to turn off
-constraints whilst running the tests they also need to be a superuser.
-If you don't want your database user to be a superuser, you can add a line
-`constraint_disabling: false` to the test config in database.yml, as seen in database.yml-example
-
-You can create a `foi` user from the command line, thus:
-
- # su - postgres
- $ createuser -s -P foi
-
-And you can create a database thus:
-
- $ createdb -T template0 -E SQL_ASCII -O foi foi_production
- $ createdb -T template0 -E SQL_ASCII -O foi foi_test
- $ createdb -T template0 -E SQL_ASCII -O foi foi_development
-
-We create using the ``SQL_ASCII`` encoding, because in postgres this
-is means "no encoding"; and because we handle and store all kinds of
-data that may not be valid UTF (for example, data originating from
-various broken email clients that's not 8-bit clean), it's safer to be
-able to store *anything*, than reject data at runtime.
-
-## Configure email
-
-You will need to set up an email server (MTA) to send and receive
-emails. Full configuration for an MTA is beyond the scope of this
-document, though we describe an example configuration for Exim in
-`INSTALL-exim4.md`.
-
-Note that in development mode, mail is handled by default by mailcatcher
-so that you can see the mails in a browser - see http://mailcatcher.me/
-for more details. Start mailcatcher by running `bundle exec mailcatcher`
-in your application directory.
-
-### Minimal
-
-If you just want to get the tests to pass, you will at a minimum need
-to allow sending emails via a `sendmail` command (a requirement met,
-for example, with `sudo apt-get install exim4`).
-
-### Detailed
-
-When an authority receives an email, the email's `reply-to` field is a
-magic address which is parsed and consumed by the Rails app.
-
-To receive such email in a production setup, you will need to
-configure your MTA to pipe incoming emails to the Alaveteli script
-`script/mailin`. Therefore, you will need to configure your MTA to
-accept emails to magic addresses, and to pipe such emails to this
-script.
-
-Magic email addresses are of the form:
-
- <foi+request-3-691c8388@example.com>
-
-The respective parts of this address are controlled with options in
-config/general.yml, thus:
-
- INCOMING_EMAIL_PREFIX = 'foi+'
- INCOMING_EMAIL_DOMAIN = 'example.com'
-
-When you set up your MTA, note that if there is some error inside
-Rails, the email is returned with an exit code 75, which for Exim at
-least means the MTA will try again later. Additionally, a stacktrace
-is emailed to `CONTACT_EMAIL`.
-
-`INSTALL-exim4.md` describes one possible configuration for Exim (>=
-1.9).
-
-A well-configured installation of this code will separately have had
-Exim make a backup copy of the email in a separate mailbox, just in
-case.
-
-## Set up configs
-
-Copy `config/general.yml-example` to `config/general.yml` and edit to
-your taste.
-
-Note that the default settings for frontpage examples are designed to
-work with the dummy data shipped with Alaveteli; once you have real
-data, you should certainly edit these.
-
-The default theme is the "Alaveteli" theme. When you run
-`rails-post-deploy` (see below), that theme gets installed
-automatically.
-
-Finally, copy `config/newrelic.yml-example` to `config/newrelic.yml`.
-This file contains configuration information for the New Relic
-performance management system. By default, monitoring is switched off
-by the `agent_enabled: false` setting. See https://github.com/newrelic/rpm
-for instructions on switching on local and remote performance analysis.
-
-## Deployment
-
-In the 'alaveteli' directory, run:
-
- script/rails-post-deploy
-
-(This will need execute privs so `chmod 755` if necessary.) This sets
-up directory structures, creates logs, installs/updates themes, runs
-database migrations, etc. You should run it after each new software
-update.
-
-One of the things the script does is install dependencies (using
-`bundle install`). Note that the first time you run it, part of the
-`bundle install` that compiles `xapian-full` takes a *long* time!
-
-If you want some dummy data to play with, you can try loading the
-fixtures that the test suite uses into your development database. You
-can do this with:
-
- script/load-sample-data
-
-Next we need to create the index for the search engine (Xapian):
-
- script/rebuild-xapian-index
-
-If this fails, the site should still mostly run, but it's a core
-component so you should really try to get this working.
-
-## Run the Tests
-
-Make sure everything looks OK:
-
- bundle exec rake spec
-
-If there are failures here, something has gone wrong with the
-preceding steps (see the next section for a common problem and
-workaround). You might be able to move on to the next step, depending
-on how serious they are, but ideally you should try to find out what's
-gone wrong.
-
-### glibc bug workaround
-
-There's a
-[bug in glibc](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=637239)
-which causes Xapian to segfault when running the tests. Although the
-bug report linked to claims it's fixed in the current Debian stable,
-it's not as of version `2.11.3-2`.
-
-Until it's fixed (e.g. `libc6 2.13-26` does work), you can get the
-tests to pass by setting `export LD_PRELOAD=/lib/libuuid.so.1`.
-
-## Run the Server
-
-Run the following to get the server running:
-
- bundle exec rails server --environment=development
-
-By default the server listens on all interfaces. You can restrict it to the
-localhost interface by adding ` --binding=127.0.0.1`
-
-The server should have told you the URL to access in your browser to see
-the site in action.
-
-## Administrator privileges
-
-The administrative interface is at the URL `/admin`.
-
-Only users with the `super` admin level can access the admin
-interface. Users create their own accounts in the usual way, and then
-administrators can give them `super` privileges.
-
-There is an emergency user account which can be accessed via
-`/admin?emergency=1`, using the credentials `ADMIN_USERNAME` and
-`ADMIN_PASSWORD`, which are set in `general.yml`. To bootstrap the
-first `super` level accounts, you will need to log in as the emergency
-user. You can disable the emergency user account by setting `DISABLE_EMERGENCY_USER` to `true` in `general.yml`.
-
-Users with the superuser role also have extra privileges in the
-website frontend, such as being able to categorise any request, being
-able to view items that have been hidden from the search, and being
-presented with "admin" links next to individual requests and comments
-in the front end.
-
-It is possible completely to override the administrator authentication
-by setting `SKIP_ADMIN_AUTH` to `true` in `general.yml`.
-
-## Cron jobs and init scripts
-
-`config/crontab-example` contains the cronjobs run on WhatDoTheyKnow.
-It's in a strange templating format they use in mySociety. mySociety
-render the example file to reference absolute paths, and then drop it
-in `/etc/cron.d/` on the server.
-
-The `ugly` format uses simple variable substitution. A variable looks
-like `!!(*= $this *)!!`. The variables are:
-
-* `vhost`: part of the path to the directory where the software is
- served from. In the mySociety files, it usually comes as
- `/data/vhost/!!(*= $vhost *)!!` -- you should replace that whole
- port with a path to the directory where your Alaveteli software
- installation lives, e.g. `/var/www/`
-* `vhost_dir`: the entire path to the directory where the software is
- served from. -- you should replace this with a path to the
- directory where your Alaveteli software installation lives,
- e.g. `/var/www/`
-* `vcspath`: the name of the alaveteli checkout, e.g. `alaveteli`.
- Thus, `/data/vhost/!!(*= $vhost *)!!/!!(*= $vcspath *)!!` might be
- replaced with `/var/www/alaveteli` in your cron tab
-* `user`: the user that the software runs as
-* `site`: a string to identify your alaveteli instance
-
-There is a rake task that will help to rewrite this file into
-one that is useful to you, which can be invoked with:
-
- bundle exec rake config_files:convert_crontab \
- DEPLOY_USER=deploy \
- VHOST_DIR=/dir/above/alaveteli \
- VCSPATH=alaveteli \
- SITE=alaveteli \
- CRONTAB=config/crontab-example > crontab
-
-You should change the `DEPLOY_USER`, `VHOST_DIR`, `VCSPATH` and
-`SITE` environment variables to match your server and
-installation. You should also edit the resulting `crontab` file
-to customize the `MAILTO` variable.
-
-One of the cron jobs refers to a script at
-`/etc/init.d/foi-alert-tracks`. This is an init script, a copy of
-which lives in `config/alert-tracks-debian.ugly`. As with the cron
-jobs above, replace the variables (and/or bits near the variables)
-with paths to your software. You can use the rake task `rake
-config_files:convert_init_script` to do this.
-`config/purge-varnish-debian.ugly` is a
-similar init script, which is optional and not required if you choose
-not to run your site behind Varnish (see below). Either tweak the file
-permissions to make the scripts executable by your deploy user, or add the
-following line to your sudoers file to allow these to be run by your deploy
-user (named `deploy` in this case):
-
- deploy ALL = NOPASSWD: /etc/init.d/foi-alert-tracks, /etc/init.d/foi-purge-varnish
-
-The cron jobs refer to a program `run-with-lockfile`. See
-[this issue](https://github.com/mysociety/alaveteli/issues/112) for a
-discussion of where to find this program, and how you might replace
-it. This [one line script](https://gist.github.com/3741194) can install
-this program system-wide.
-
-## Set up production web server
-
-It is not recommended to run the website using the default Rails web
-server. There are various recommendations here:
-http://rubyonrails.org/deploy
-
-We usually use Passenger / mod_rails. The file at `conf/httpd.conf-example`
-gives you an example config file for WhatDoTheyKnow. At a minimum, you should
-include the following in an Apache configuration file:
-
- PassengerResolveSymlinksInDocumentRoot on
- PassengerMaxPoolSize 6 # Recommend setting this to 3 or less on servers with 512MB RAM
-
-Under all but light loads, it is strongly recommended to run the
-server behind an http accelerator like Varnish. A sample varnish VCL
-is supplied in `../conf/varnish-alaveteli.vcl`.
-
-It's strongly recommended that you run the site over SSL. (Set FORCE_SSL to true in
-config/general.yml). For this you will need an SSL certificate for your domain and you will
-need to configure an SSL terminator to sit in front of Varnish. If you're already using Apache
-as a web server you could simply use Apache as the SSL terminator. A minimal configuration
-would look something like this:
-
-<VirtualHost *:443>
- ServerName www.yourdomain
-
- 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/apache2/ssl/ssl.crt
- SSLCertificateKeyFile /etc/apache2/ssl/ssl.key
- SSLCertificateChainFile /etc/apache2/ssl/sub.class2.server.ca.pem
- SSLCACertificateFile /etc/apache2/ssl/ca.pem
- SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
-</VirtualHost>
-
-Notice the line "RequestHeader" that sets the X-Forwarded-Proto header. This is important. This ultimately tells Rails that it's serving a page over https and so it knows to include that in any absolute urls it serves.
-
-Some
-[production server best practice notes](https://github.com/mysociety/alaveteli/wiki/Production-Server-Best-Practices)
-are evolving on the wiki.
-
-## Upgrading Alaveteli
-
-The developer team policy is that the master branch in git should
-always contain the latest stable release. Therefore, in production,
-you should usually have your software deployed from the master branch,
-and an upgrade can be simply `git pull`.
-
-Patch version increases (e.g. 1.2.3 -> 1.2.4) should not require any
-further action on your part.
-
-Minor version increases (e.g. 1.2.4 -> 1.3.0) will usually require
-further action. You should read the `CHANGES.md` document to see
-what's changed since your last deployment, paying special attention to
-anything in the "Updgrading" sections.
-
-Any upgrade may include new translations strings, i.e. new or altered
-messages to the user that need translating to your locale. You should
-visit Transifex and try to get your translation up to 100% on each new
-release. Failure to do so means that any new words added to the
-Alaveteli source code will appear in your website in English by
-default. If your translations didn't make it to the latest release,
-you will need to download the updated `app.po` for your locale from
-Transifex and save it in the `locale/` folder.
-
-You should always run the script `scripts/rails-post-deploy` after
-each deployment. This runs any database migrations for you, plus
-various other things that can be automated for deployment.
-
-## Troubleshooting
-
-* **Incoming emails aren't appearing in my Alaveteli install**
-
- First, you need to check that your MTA is delivering relevant
- incoming emails to the `script/mailin` command. There are various
- ways of setting your MTA up to do this; we have documented one way
- of doing it in Exim at `doc/INSTALL-exim4.conf`, including a
- command you can use to check that the email routing is set up
- correctly.
-
- Second, you need to test that the mailin script itself is working
- correctly, by running it from the command line, First, find a
- valid "To" address for a request in your system. You can do this
- through your site's admin interface, or from the command line,
- like so:
-
- $ ./script/console
- Loading development environment (Rails 2.3.14)
- >> InfoRequest.find_by_url_title("why_do_you_have_such_a_fancy_dog").incoming_email
- => "request-101-50929748@localhost"
-
- Now take the source of a valid email (there are some sample emails in
- `spec/fixtures/files/`); edit the `To:` header to match this address;
- and then pipe it through the mailin script. A non-zero exit code
- means there was a problem. For example:
-
- $ cp spec/fixtures/files/incoming-request-plain.email /tmp/
- $ perl -pi -e 's/^To:.*/To: <request-101-50929748@localhost>/' /tmp/incoming-request-plain.email
- $ ./script/mailin < /tmp/incoming-request-plain.email
- $ echo $?
- 75
-
- The `mailin` script emails the details of any errors to
- `CONTACT_EMAIL` (from your `general.yml` file). A common problem is
- for the user that the MTA runs as not to have write access to
- `files/raw_emails/`.
-
-* **Various tests fail with "*Your PostgreSQL connection does not support
- unescape_bytea. Try upgrading to pg 0.9.0 or later.*"**
-
- You have an old version of `pg`, the ruby postgres driver. In
- Ubuntu, for example, this is provided by the package `libdbd-pg-ruby`.
-
- Try upgrading your system's `pg` installation, or installing the pg
- gem with `gem install pg`
-
-* **Some of the tests relating to mail are failing, with messages like
- "*when using TMail should load an email with funny MIME settings'
- FAILED*"**
-
- This sounds like the tests are running using the `production`
- environment, rather than the `test` environment, for some reason.
-
-* **Non-ASCII characters are being displayed as asterisks in my incoming messages**
-
- We rely on `elinks` to convert HTML email to plain text.
- Normally, the encoding should just work, but under some
- circumstances it appears that `elinks` ignores the parameters
- passed to it from Alaveteli.
-
- To force `elinks` always to treat input as UTF8, add the following
- to `/etc/elinks/elinks.conf`:
-
- set document.codepage.assume = "utf-8"
- set document.codepage.force_assumed = 1
-
- You should also check that your locale is set up correctly. See
- [https://github.com/mysociety/alaveteli/issues/128#issuecomment-1814845](this issue followup)
- for further discussion.
-
-* **I'm seeing `rake: command not found` when running the post install script
-
- The script uses `rake`.
-
- It may be that the binaries installed by bundler are not put in the
- system `PATH`; therefore, in order to run `rake` (needed for
- deployments), you may need to do something like:
-
- ln -s /usr/lib/ruby/gems/1.8/bin/rake /usr/local/bin/
-
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 000000000..d8e9b409c
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,9 @@
+The main Alaveteli documentation now lives on the [Alaveteli documentation site](http://code.alaveteli.org/docs/)
+
+Specifically:
+
+[Installation](http://code.alaveteli.org/docs/installing/)
+[Themes](http://code.alaveteli.org/docs/customising/themes/)
+[Translation](http://code.alaveteli.org/docs/customising/translation/)
+[Email](http://code.alaveteli.org/docs/installing/email/)
+[Deployment](http://code.alaveteli.org/docs/installing/deploy/)
diff --git a/doc/THEMES.md b/doc/THEMES.md
deleted file mode 100644
index 8a4828a99..000000000
--- a/doc/THEMES.md
+++ /dev/null
@@ -1,165 +0,0 @@
-When installing an Alaveteli site, there are a few things that you
-might want to do to customise it, beyond the available settings in the
-`config/general` file.
-
-The most common requirement is to brand the site: at a minimum,
-inserting your own logo and colour scheme. You may also want to tweak
-the different states that a request can go through. You'll also want
-to edit the categories that public bodies can appear in (i.e. the
-groupings on the left hand side of the
-"[View authorities](https://www.whatdotheyknow.com/body/list/all)" page
-on WhatDoTheyKnow.
-
-There may also be other things you want to customise; drop a line on
-the developer's mailing list to discuss, if so. We're still working
-out the best way of doing these kinds of customisations!
-
-In any case, the important principle to bear in mind is that the less
-you override and customise the code, the easier your site will be to
-maintain in the long term. Any customisation is possible, but for
-each customisation beyond the simple cases documented here, ask
-yourself or your client, "can we possibly live without this?" If the
-answer is "no", then consider starting a discussion about a pluggable
-way of achieving your goals, rather than overriding any of the core
-code.
-
-# General principles
-
-We try to encapsulate all site-specific functionality in one of these
-places:
-
-* Site configuration (e.g. the name of your site, the available
- languages etc -- all in `config/general`)
-* Data (e.g. the public bodies to whom requests should be addressed)
-* A rails "plugin", installed in `vendor/plugins/`. We call these
- "themes".
-
-This document is about what you can do in a theme.
-
-By default, the sample theme ("alavetelitheme") has already been
-installed. See the setting `THEME_URLS` in `general.yml` for an
-explanation.
-
-You can also install the sample theme by hand, by running:
-
- bundle exec rails plugin install git://github.com/mysociety/alavetelitheme.git
-
-The sample theme contains examples for nearly everything you might
-want to customise. You should probably make a copy, rename it, and
-use that as the basis for your own theme.
-
-# Make sure your theme is as lightweight as possible
-
-The more you put in your theme, the harder it will be to upgrade to
-future versions of Alaveteli. Everything you place in your theme
-overrides things in the core theme, so if you make a new "main
-template", then new widgets that appear in the core theme won't appear
-on your website.
-
-Therefore, you should consider how you can brand your website without
-changing much in the core theme. The ideal would be if you are able
-to rebrand the site by only changing the CSS. You will also need to
-add custom help pages, as described below.
-
-# Branding the site
-
-The core templates that comprise the layout and user interface of an
-Alaveteli site live in `app/views/`. They use Rails' ERB syntax.
-For example, the template for the home page lives at
-`app/views/general/frontpage.html.erb`, and the template for the "about
-us" page is at `app/views/help/about.html.erb`.
-
-Obviously, you *could* edit those core files directly, but this would
-be a Bad Idea, because you would find it increasingly hard to do
-upgrades. Having said that, sometimes you may want to change the core
-templates in a way that would benefit everyone, in which case, discuss
-the changes on the mailing list, make them in a fork of Alaveteli, and
-then issue a pull request.
-
-Normally, however, you should override these pages **in your own
-theme**, by placing them at a corresponding location within your
-theme's `lib/` directory. These means that a file at
-`vendor/plugins/alavetelitheme/lib/help/about.rhml` will appear
-instead of the core "about us" file.
-
-Rails expects all its stylesheets to live at `<railshome>/public`,
-which presents a problem for plugins. Here's how we solve it: the
-stylesheet and associated resources for your theme live (by
-convention) in `alavetelitheme/public/`. This is symlinked from
-the main Rails app -- see `alavetelitheme/install.rb` to see how this
-happens.
-
-The partial at
-`alavetelitheme/lib/views/general/_before_head_end.html.erb` includes the
-custom CSS in your theme's stylesheet folder (by convention, in
-`alavetelitheme/public/stylesheets/`), with:
-
- <%= stylesheet_link_tag "/alavetelitheme/stylesheets/custom" %>
-
-...which will, usually, need changing for your theme.
-
-# Adding your own categories for public bodies
-
-Categories are implemented in Alaveteli using tags. Specific tags can
-be designated to group authorities together as a category.
-
-There's a file in the sample theme,
-`alavetelitheme/lib/public_body_categories_en.rb`, which contains a
-nested structure that defines categories. It contains a comment
-describing its structure. You should make a copy of this file for each
-locale you support.
-
-# Customising the request states
-
-As mentioned above, if you can possibly live with the
-[default Alaveteli request statuses](https://github.com/mysociety/alaveteli/wiki/Alaveteli's-request-statuses),
-it would be good to do so. Note that you can set how many days counts
-as "overdue" in the main site config file.
-
-If you can't live with the states as they are, there's a very basic
-way to add to them (which will get improved over time). There's not
-currently a way to remove any easily. There is an example of how to
-do this in the `alavetelitheme`.
-
-To do add states, create two modules in your theme,
-`InfoRequestCustomStates` and `RequestControllerCustomStates`. The
-former must have these methods:
-
-* `theme_calculate_status`: return a tag to identify the current state of the request
-* `theme_extra_states`: return a list of tags which identify the extra states you'd like to support
-* `theme_display_status`: return human-readable strings corresponding with these tags
-
-The latter must have one method:
-
-* `theme_describe_state`: Return a notice for the user suitable for
- displaying after they've categorised a request; and redirect them to
- a suitable next page
-
-When you've added your extra states, you also need to create the following files in your theme:
-
-* `lib/views/general/_custom_state_descriptions.html.erb`: Descriptions
- of your new states, suitable for displaying to end users
-* `lib/views/general/_custom_state_transitions_complete.html.erb`:
- Descriptions for any new states that you might characterise as
- 'completion' states, for displaying on the categorisation form that
- we ask requestors to fill out
-* `lib/views/general/_custom_state_transitions_pending.html.erb`: As
- above, but for new states you might characterise as 'pending'
- states.
-
-You can see examples of these customisations in
-[this commit](https://github.com/sebbacon/informatazyrtare-theme/commit/2b240491237bd72415990399904361ce9bfa431d)
-for the Kosovan version of Alaveteli, Informata Zyrtare (ignore the
-file `lib/views/general/_custom_state_transitions.html.erb`, which is
-unused).
-
-# Adding new pages in the navigation
-
-`alavetelitheme/lib/config/custom-routes.rb` allows you to extend the base routes in
-Alaveteli. The example in `alavetelitheme` adds an extra help page.
-You can also use this to override the behaviour of specific pages if
-necessary.
-
-# Adding or overriding models and controllers
-
-If you need to extend the behaviour of Alaveteli at the controller or model level, see `alavetelitheme/lib/controller_patches.rb` and `alavetelitheme/lib/model_patches.rb` for examples.
diff --git a/doc/TRANSLATE.md b/doc/TRANSLATE.md
deleted file mode 100644
index aef2cfdc9..000000000
--- a/doc/TRANSLATE.md
+++ /dev/null
@@ -1,106 +0,0 @@
-The software translations are implemented using GNU gettext, and the
-resource files are managed in Transifex.
-
-The Transifex project is at
-https://www.transifex.net/projects/p/alaveteli/; you'll probably want
-an account there (ask on the mailing list). It has a fairly easy to
-use interface for contributing translations.
-
-# Translation process: translator's view
-
-When a developer adds a new feature to the user interface in
-Alaveteli, they use some code to mark sentences or words ("strings")
-that they think will need to be translated.
-
-When the Alaveteli release manager is planning a release, they upload
-a template containing all the strings to be translated (called a POT)
-to Transifex. This causes your own translations in Transifex to be
-updated with the latest strings.
-
-When you visit Transifex, it will prompt you to fill out values for
-all new strings, and all strings that have been modified. In the case
-where a string has only been slightly modified, such as with
-punctuation ("Hello" has become "Hello!"), Transifex will suggest a
-suitable translation for you (look for the "suggestions" tab under the
-source string).
-
-In order for this feature to work properly, the release manager has to
-download your translations, run a program that inserts the
-suggestions, and then upload them again. Therefore, when a release
-candidate is announced, make sure you have uploaded any outstanding
-translations, or you will lose them.
-
-When a release candidate has been annouced, there is a **translation
-freeze**: during this period, developers must not add any new strings
-to the software, so you can be confident that you're translating
-everything that will be in the final release.
-
-The release manager will also give you a **translation deadline**. After
-this date, you can continue to contribute new translations, but they
-won't make it into the release.
-
-## General notes on translation in Transifex
-
-Some bits of text will have comments attached to them from the Alaveteli
-application developers about the context in which the text appears in the
-application - these comments will appear under the 'Details' tab for the
-text in Transifex.
-
-Some texts will have placeholders in them to indicate that another bit of text generated by Alaveteli will be inserted into them when they're displayed. They will look like `some text with a {{placeholder}}`. For these texts, don't translate the placeholder. It needs to stay exactly the same for the text to be inserted properly.
-
-Similarly, some texts will have some code in angle brackets in them to turn bits of the text into links, and other small bits of HTML formatting. e.g. `please <a href=\"{{url}}\">send it to us</a>`. Again, don't edit the bits in angle brackets, preserve them in your translation, just edit the text around them.
-
-Some bits of text are in the form of two bits of text separated by a `|`
-character e.g. `IncomingMessage|Subject`. These represent attribute names, so
-`IncomingMessage|Subject` is the subject attribute of an incoming message on
-the site. You should not prioritise these types of text when translating -
-they do not appear on the site anywhere at the moment, and when they do,
-they will only be used in the admin interface. If you do translate them, only
-translate the text after the `|`.
-
-# Translation process: release manager's view
-
-Before the Alaveteli release manager cuts a new release branch, they
-must:
-
-* pick a date for the release branch to be cut ("release candidate date")
-* make an announcement to the translators (using the "announcements"
- feature in Transifex) that they should ensure they have any pending
- translations saved in Transifex before the release candidate date
-* make an announcement to the developers that all new strings should
- be committed before the release candidate date
-* on the release candidate date:
- * download (`tx pull -a -f`) and commit all the current translations (important:
- there's no revision history in Transifex!)
- * you should also commit these translations to a hotfix for the
- previous version, so they are preserved against the last known
- good msgids
- * regenerate the POT file and individual PO files for each
- language, using `bundle exec rake
- gettext:store_model_attributes`, followed by `bundle exec rake
- gettext:find`
- * careful of including msgids from themes in `lib/themes`;
- you might want to move them out of the way before running
- the above commands
- * this updates the PO template, but also merges it with the
- individual PO files, marking strings that have only changed
- slightly as "fuzzy"
- * reupload (`tx push -s -t`) the POT and PO files to Transifex from the
- current release branch
- * The point of uploading the PO files is that Transifex
- converts the "fuzzy" suggestions from Transifex into
- "suggestions" under each source string
- * Note that Transifex *does not* preserve fuzzy strings in the
- PO files it makes available for download, on the grounds
- that Transifex supports multiple suggestions, whereas
- gettext only allows one fuzzy suggestion per msgid.
- * remove the fuzzy strings from the local PO files (because they
- make Rails very noisy), and then commit the result. You can do
- this by re-pulling from Transifex.
-* on the release date:
- * download and commit all the current translations to the current
- release branch
-
-# Translations: developers' view
-
-See the [I18n guide](https://github.com/mysociety/alaveteli/wiki/I18n-guide) on the wiki.
diff --git a/lib/attachment_to_html/adapters/rtf.rb b/lib/attachment_to_html/adapters/rtf.rb
index 859c0e541..95f499689 100644
--- a/lib/attachment_to_html/adapters/rtf.rb
+++ b/lib/attachment_to_html/adapters/rtf.rb
@@ -73,6 +73,8 @@ module AttachmentToHTML
# Works around http://savannah.gnu.org/bugs/?42015 in unrtf ~> 0.21
def sanitize_converted(html)
+ html.nil? ? html = '' : html
+
invalid = %Q(<!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN>)
valid = %Q(<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN>")
if html.include?(invalid)
diff --git a/spec/helpers/date_time_helper_spec.rb b/spec/helpers/date_time_helper_spec.rb
new file mode 100644
index 000000000..c4fdee1d1
--- /dev/null
+++ b/spec/helpers/date_time_helper_spec.rb
@@ -0,0 +1,71 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe DateTimeHelper do
+
+ include DateTimeHelper
+
+ describe :simple_date do
+
+ it 'formats a date in html by default' do
+ time = Time.utc(2012, 11, 07, 21, 30, 26)
+ self.should_receive(:simple_date_html).with(time)
+ simple_date(time)
+ end
+
+ it 'formats a date in the specified format' do
+ time = Time.utc(2012, 11, 07, 21, 30, 26)
+ self.should_receive(:simple_date_text).with(time)
+ simple_date(time, :format => :text)
+ end
+
+ it 'raises an argument error if given an unrecognized format' do
+ time = Time.utc(2012, 11, 07, 21, 30, 26)
+ expect { simple_date(time, :format => :unknown) }.to raise_error(ArgumentError)
+ end
+
+ end
+
+ describe :simple_date_html do
+
+ it 'formats a date in a time tag' do
+ Time.use_zone('London') do
+ time = Time.utc(2012, 11, 07, 21, 30, 26)
+ expected = %Q(<time datetime="2012-11-07T21:30:26+00:00" title="2012-11-07 21:30:26 +0000">November 07, 2012</time>)
+ simple_date_html(time).should == expected
+ end
+ end
+
+ end
+
+ describe :simple_date_text do
+
+ it 'should respect time zones' do
+ Time.use_zone('Australia/Sydney') do
+ simple_date_text(Time.utc(2012, 11, 07, 21, 30, 26)).should == 'November 08, 2012'
+ end
+ end
+
+ it 'should handle Date objects' do
+ simple_date_text(Date.new(2012, 11, 21)).should == 'November 21, 2012'
+ end
+
+ end
+
+ describe :simple_time do
+
+ it 'returns 00:00:00 for a date' do
+ simple_time(Date.new(2012, 11, 21)).should == '00:00:00'
+ end
+
+ it 'returns the time component of a datetime' do
+ date = DateTime.new(2012, 11, 21, 10, 34, 56)
+ simple_time(date).should == '10:34:56'
+ end
+
+ it 'returns the time component of a time' do
+ time = Time.utc(2000, 'jan', 1, 20, 15, 1)
+ simple_time(time).should == '20:15:01'
+ end
+
+ end
+end
diff --git a/spec/helpers/link_to_helper_spec.rb b/spec/helpers/link_to_helper_spec.rb
index 4a01ec683..b11c35056 100644
--- a/spec/helpers/link_to_helper_spec.rb
+++ b/spec/helpers/link_to_helper_spec.rb
@@ -20,6 +20,82 @@ describe LinkToHelper do
end
+ describe 'when linking to new incoming messages' do
+
+ before do
+ @info_request = mock_model(InfoRequest, :id => 123, :url_title => 'test_title')
+ @incoming_message = mock_model(IncomingMessage, :id => 32, :info_request => @info_request)
+ end
+
+ context 'for external links' do
+
+ it 'generates the url to the info request of the message' do
+ incoming_message_url(@incoming_message).should include('http://test.host/request/test_title')
+ end
+
+ it 'includes an anchor to the new message' do
+ incoming_message_url(@incoming_message).should include('#incoming-32')
+ end
+
+ it 'includes does not cache by default' do
+ incoming_message_url(@incoming_message).should_not include('nocache=incoming-32')
+ end
+
+ it 'includes a cache busting parameter if set' do
+ incoming_message_url(@incoming_message, :cachebust => true).should include('nocache=incoming-32')
+ end
+
+ end
+
+ context 'for internal links' do
+
+ it 'generates the incoming_message_url with the path only' do
+ expected = '/request/test_title#incoming-32'
+ incoming_message_path(@incoming_message).should == expected
+ end
+
+ end
+
+ end
+
+ describe 'when linking to new outgoing messages' do
+
+ before do
+ @info_request = mock_model(InfoRequest, :id => 123, :url_title => 'test_title')
+ @outgoing_message = mock_model(OutgoingMessage, :id => 32, :info_request => @info_request)
+ end
+
+ context 'for external links' do
+
+ it 'generates the url to the info request of the message' do
+ outgoing_message_url(@outgoing_message).should include('http://test.host/request/test_title')
+ end
+
+ it 'includes an anchor to the new message' do
+ outgoing_message_url(@outgoing_message).should include('#outgoing-32')
+ end
+
+ it 'includes does not cache by default' do
+ outgoing_message_url(@outgoing_message).should_not include('nocache=outgoing-32')
+ end
+
+ it 'includes a cache busting parameter if set' do
+ outgoing_message_url(@outgoing_message, :cachebust => true).should include('nocache=outgoing-32')
+ end
+
+ end
+
+ context 'for internal links' do
+
+ it 'generates the outgoing_message_url with the path only' do
+ expected = '/request/test_title#outgoing-32'
+ outgoing_message_path(@outgoing_message).should == expected
+ end
+
+ end
+
+ end
+
describe 'when displaying a user link for a request' do
context "for external requests" do
@@ -69,51 +145,4 @@ describe LinkToHelper do
end
- describe 'simple_date' do
-
- it 'formats a date in html by default' do
- time = Time.utc(2012, 11, 07, 21, 30, 26)
- self.should_receive(:simple_date_html).with(time)
- simple_date(time)
- end
-
- it 'formats a date in the specified format' do
- time = Time.utc(2012, 11, 07, 21, 30, 26)
- self.should_receive(:simple_date_text).with(time)
- simple_date(time, :format => :text)
- end
-
- it 'raises an argument error if given an unrecognized format' do
- time = Time.utc(2012, 11, 07, 21, 30, 26)
- expect { simple_date(time, :format => :unknown) }.to raise_error(ArgumentError)
- end
-
- end
-
- describe 'simple_date_html' do
-
- it 'formats a date in a time tag' do
- Time.use_zone('London') do
- time = Time.utc(2012, 11, 07, 21, 30, 26)
- expected = "<time datetime=\"2012-11-07T21:30:26+00:00\" title=\"2012-11-07 21:30:26 +0000\">November 07, 2012</time>"
- simple_date_html(time).should == expected
- end
- end
-
- end
-
- describe 'simple_date_text' do
-
- it 'should respect time zones' do
- Time.use_zone('Australia/Sydney') do
- simple_date_text(Time.utc(2012, 11, 07, 21, 30, 26)).should == 'November 08, 2012'
- end
- end
-
- it 'should handle Date objects' do
- simple_date_text(Date.new(2012, 11, 21)).should == 'November 21, 2012'
- end
-
- end
-
end
diff --git a/spec/lib/attachment_to_html/adapters/rtf_spec.rb b/spec/lib/attachment_to_html/adapters/rtf_spec.rb
index a3bf0e27e..2c53b5272 100644
--- a/spec/lib/attachment_to_html/adapters/rtf_spec.rb
+++ b/spec/lib/attachment_to_html/adapters/rtf_spec.rb
@@ -60,6 +60,17 @@ describe AttachmentToHTML::Adapters::RTF do
adapter.body.should_not include('//W3C//DTD HTML 4.01 Transitional//EN')
end
+ it 'converts empty files' do
+ attachment = FactoryGirl.build(:rtf_attachment, :body => load_file_fixture('empty.rtf'))
+ adapter = AttachmentToHTML::Adapters::RTF.new(attachment)
+ adapter.body.should == ''
+ end
+
+ it 'doesnt fail if the external command returns nil' do
+ AlaveteliExternalCommand.stub(:run).and_return(nil)
+ adapter.body.should == ''
+ end
+
end
diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb
index f06dcbeeb..3b6887f76 100644
--- a/spec/models/incoming_message_spec.rb
+++ b/spec/models/incoming_message_spec.rb
@@ -112,6 +112,24 @@ describe IncomingMessage, 'when asked if a user can view it' do
end
+describe 'when destroying a message' do
+
+ before do
+ @incoming_message = FactoryGirl.create(:plain_incoming_message)
+ end
+
+ it 'can destroy a message with more than one info request event' do
+ @info_request = @incoming_message.info_request
+ @info_request.log_event('response',
+ :incoming_message_id => @incoming_message.id)
+ @info_request.log_event('edit_incoming',
+ :incoming_message_id => @incoming_message.id)
+ @incoming_message.fully_destroy
+ IncomingMessage.where(:id => @incoming_message.id).should be_empty
+ end
+
+end
+
describe 'when asked if it is indexed by search' do
before do