aboutsummaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/about_me_validator.rb22
-rw-r--r--app/models/application_mailer.rb164
-rw-r--r--app/models/censor_rule.rb12
-rw-r--r--app/models/change_email_validator.rb38
-rw-r--r--app/models/comment.rb2
-rw-r--r--app/models/contact_mailer.rb56
-rw-r--r--app/models/contact_validator.rb34
-rw-r--r--app/models/foi_attachment.rb29
-rw-r--r--app/models/holiday.rb2
-rw-r--r--app/models/incoming_message.rb103
-rw-r--r--app/models/info_request.rb79
-rw-r--r--app/models/info_request_event.rb4
-rw-r--r--app/models/mail_server_log.rb12
-rw-r--r--app/models/mail_server_log_done.rb2
-rw-r--r--app/models/outgoing_mailer.rb98
-rw-r--r--app/models/outgoing_message.rb23
-rw-r--r--app/models/post_redirect.rb28
-rw-r--r--app/models/profile_photo.rb39
-rw-r--r--app/models/public_body.rb12
-rw-r--r--app/models/purge_request.rb2
-rw-r--r--app/models/raw_email.rb6
-rw-r--r--app/models/request_mailer.rb457
-rw-r--r--app/models/track_mailer.rb134
-rw-r--r--app/models/track_thing.rb4
-rw-r--r--app/models/track_things_sent_email.rb2
-rw-r--r--app/models/user.rb41
-rw-r--r--app/models/user_info_request_sent_alert.rb2
-rw-r--r--app/models/user_mailer.rb48
28 files changed, 281 insertions, 1174 deletions
diff --git a/app/models/about_me_validator.rb b/app/models/about_me_validator.rb
index 8ee505ac8..7df70fb61 100644
--- a/app/models/about_me_validator.rb
+++ b/app/models/about_me_validator.rb
@@ -1,25 +1,23 @@
-# == Schema Information
-# Schema version: 114
-#
-# Table name: about_me_validators
-#
-# about_me :text default("I..."), not null
-#
-
# models/about_me_validator.rb:
# Validates editing about me text on user profile pages.
#
# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
-class AboutMeValidator < ActiveRecord::BaseWithoutTable
- strip_attributes!
+class AboutMeValidator
+ include ActiveModel::Validations
- column :about_me, :text, "I...", false
+ attr_accessor :about_me
# TODO: Switch to built in validations
validate :length_of_about_me
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name}=", value)
+ end
+ end
+
private
def length_of_about_me
diff --git a/app/models/application_mailer.rb b/app/models/application_mailer.rb
deleted file mode 100644
index 1a97a4bf9..000000000
--- a/app/models/application_mailer.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-# models/application_mailer.rb:
-# Shared code between different mailers.
-#
-# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-require 'action_mailer/version'
-class ApplicationMailer < ActionMailer::Base
- # Include all the functions views get, as emails call similar things.
- helper :application
- include MailerHelper
-
- # This really should be the default - otherwise you lose any information
- # about the errors, and have to do error checking on return codes.
- self.raise_delivery_errors = true
-
- def blackhole_email
- Configuration::blackhole_prefix+"@"+Configuration::incoming_email_domain
- end
-
- # URL generating functions are needed by all controllers (for redirects),
- # views (for links) and mailers (for use in emails), so include them into
- # all of all.
- include LinkToHelper
-
- # Site-wide access to configuration settings
- include ConfigHelper
-
- # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
- # will be initialized according to the named method. If not, the mailer will
- # remain uninitialized (useful when you only need to invoke the "receive"
- # method, for instance).
- def initialize(method_name=nil, *parameters) #:nodoc:
- create!(method_name, *parameters) if method_name
- end
-
- # For each multipart template (e.g. "the_template_file.text.html.erb") available,
- # add the one from the view path with the highest priority as a part to the mail
- def render_multipart_templates
- added_content_types = {}
- self.view_paths.each do |view_path|
- Dir.glob("#{view_path}/#{mailer_name}/#{@template}.*").each do |path|
- template = view_path["#{mailer_name}/#{File.basename(path)}"]
-
- # Skip unless template has a multipart format
- next unless template && template.multipart?
- next if added_content_types[template.content_type] == true
- @parts << Part.new(
- :content_type => template.content_type,
- :disposition => "inline",
- :charset => charset,
- :body => render_message(template, @body)
- )
- added_content_types[template.content_type] = true
- end
- end
- end
-
- # Look for the current template in each element of view_paths in order,
- # return the first
- def find_template
- self.view_paths.each do |view_path|
- if template = view_path["#{mailer_name}/#{@template}"]
- return template
- end
- end
- return nil
- end
-
- if ActionMailer::VERSION::MAJOR == 2
-
- # This method is a customised version of ActionMailer::Base.create!
- # modified to allow templates to be selected correctly for multipart
- # mails when themes have added to the view_paths. The problem from our
- # point of view with ActionMailer::Base is that it sets template_root to
- # the first element of the view_paths array and then uses only that (directly
- # and via template_path, which is created from it) in the create! method when
- # looking for templates. Our modified version looks for templates in the view_paths
- # in order.
-
- # It also has a line converting the mail subject to a string. This is because we
- # use translated strings in the subject lines, sometimes in conjunction with
- # user input, like request titles. The _() function used for translation
- # returns an instance of SafeBuffer, which doesn't handle gsub calls in the block form
- # with $ variables - https://github.com/rails/rails/issues/1555.
- # Unfortunately ActionMailer uses that form in quoted_printable(), which will be
- # called if any part of the subject requires quoting. So we convert the subject
- # back to a string via to_str() before passing in to create_mail. There is a test
- # for this in spec/models/request_mailer_spec.rb
-
- # Changed lines marked with ***
-
- # Initialize the mailer via the given +method_name+. The body will be
- # rendered and a new TMail::Mail object created.
- def create!(method_name, *parameters) #:nodoc:
- initialize_defaults(method_name)
- __send__(method_name, *parameters)
-
- # If an explicit, textual body has not been set, we check assumptions.
- unless String === @body
- # First, we look to see if there are any likely templates that match,
- # which include the content-type in their file name (i.e.,
- # "the_template_file.text.html.erb", etc.). Only do this if parts
- # have not already been specified manually.
- if @parts.empty?
- # *** render_multipart_templates replaces the following code
- # Dir.glob("#{template_path}/#{@template}.*").each do |path|
- # template = template_root["#{mailer_name}/#{File.basename(path)}"]
- #
- # # Skip unless template has a multipart format
- # next unless template && template.multipart?
- #
- # @parts << Part.new(
- # :content_type => template.content_type,
- # :disposition => "inline",
- # :charset => charset,
- # :body => render_message(template, @body)
- # )
- # end
- render_multipart_templates
-
- unless @parts.empty?
- @content_type = "multipart/alternative" if @content_type !~ /^multipart/
- @parts = sort_parts(@parts, @implicit_parts_order)
- end
- end
-
- # Then, if there were such templates, we check to see if we ought to
- # also render a "normal" template (without the content type). If a
- # normal template exists (or if there were no implicit parts) we render
- # it.
- template_exists = @parts.empty?
-
- # *** find_template replaces template_root call
- # template_exists ||= template_root["#{mailer_name}/#{@template}"]
- template_exists ||= find_template
-
- @body = render_message(@template, @body) if template_exists
-
- # Finally, if there are other message parts and a textual body exists,
- # we shift it onto the front of the parts and set the body to nil (so
- # that create_mail doesn't try to render it in addition to the parts).
- if !@parts.empty? && String === @body
- @parts.unshift ActionMailer::Part.new(:charset => charset, :body => @body)
- @body = nil
- end
- end
-
- # If this is a multipart e-mail add the mime_version if it is not
- # already set.
- @mime_version ||= "1.0" if !@parts.empty?
-
- # *** Convert into a string
- @subject = @subject.to_str if @subject
-
- # build the mail object itself
- @mail = create_mail
- end
- else
- raise "ApplicationMailer.create! is obsolete - find another way to ensure that themes can override mail templates for multipart mails"
- end
-
-end
-
diff --git a/app/models/censor_rule.rb b/app/models/censor_rule.rb
index f40ab6fbb..f0d06e088 100644
--- a/app/models/censor_rule.rb
+++ b/app/models/censor_rule.rb
@@ -20,7 +20,7 @@
# Stores alterations to remove specific data from requests.
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class CensorRule < ActiveRecord::Base
belongs_to :info_request
@@ -33,13 +33,15 @@ class CensorRule < ActiveRecord::Base
validate :require_valid_regexp, :if => proc{ |rule| rule.regexp? == true }
validates_presence_of :text
- named_scope :global, {:conditions => {:info_request_id => nil,
- :user_id => nil,
- :public_body_id => nil}}
+ scope :global, {:conditions => {:info_request_id => nil,
+ :user_id => nil,
+ :public_body_id => nil}}
def require_user_request_or_public_body
if self.info_request.nil? && self.user.nil? && self.public_body.nil?
- errors.add("Censor must apply to an info request a user or a body; ")
+ [:info_request, :user, :public_body].each do |a|
+ errors.add(a, "Rule must apply to an info request, a user or a body")
+ end
end
end
diff --git a/app/models/change_email_validator.rb b/app/models/change_email_validator.rb
index 2ddebb177..5cc13d4c2 100644
--- a/app/models/change_email_validator.rb
+++ b/app/models/change_email_validator.rb
@@ -1,36 +1,27 @@
-# == Schema Information
-# Schema version: 114
-#
-# Table name: change_email_validators
-#
-# old_email :string
-# new_email :string
-# password :string
-# user_circumstance :string
-#
-
# models/changeemail_validator.rb:
# Validates email change form submissions.
#
# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-class ChangeEmailValidator < ActiveRecord::BaseWithoutTable
- strip_attributes!
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
- column :old_email, :string
- column :new_email, :string
- column :password, :string
- column :user_circumstance, :string
+class ChangeEmailValidator
+ include ActiveModel::Validations
- attr_accessor :logged_in_user
+ attr_accessor :old_email, :new_email, :password, :user_circumstance, :logged_in_user
validates_presence_of :old_email, :message => N_("Please enter your old email address")
validates_presence_of :new_email, :message => N_("Please enter your new email address")
validates_presence_of :password, :message => N_("Please enter your password"), :unless => :changing_email
validate :password_and_format_of_email
- def changing_email()
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name}=", value)
+ end
+ end
+
+
+ def changing_email
self.user_circumstance == 'change_email'
end
@@ -41,11 +32,11 @@ class ChangeEmailValidator < ActiveRecord::BaseWithoutTable
errors.add(:old_email, _("Old email doesn't look like a valid address"))
end
- if !errors[:old_email]
+ if errors[:old_email].blank?
if self.old_email.downcase != self.logged_in_user.email.downcase
errors.add(:old_email, _("Old email address isn't the same as the address of the account you are logged in with"))
elsif (!self.changing_email) && (!self.logged_in_user.has_this_password?(self.password))
- if !errors[:password]
+ if errors[:password].blank?
errors.add(:password, _("Password is not correct"))
end
end
@@ -55,5 +46,4 @@ class ChangeEmailValidator < ActiveRecord::BaseWithoutTable
errors.add(:new_email, _("New email doesn't look like a valid address"))
end
end
-
end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 70f3ba00d..9527030a9 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -18,7 +18,7 @@
# A comment by a user upon something.
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class Comment < ActiveRecord::Base
strip_attributes!
diff --git a/app/models/contact_mailer.rb b/app/models/contact_mailer.rb
deleted file mode 100644
index 318f54ea8..000000000
--- a/app/models/contact_mailer.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# models/contact_mailer.rb:
-# Sends contact form mails.
-#
-# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-class ContactMailer < ApplicationMailer
-
- # Send message to administrator
- def to_admin_message(name, email, subject, message, logged_in_user, last_request, last_body)
- @from = "#{name} <#{email}>"
- @recipients = contact_from_name_and_email
- @subject = subject
- @body = { :message => message,
- :logged_in_user => logged_in_user ,
- :last_request => last_request,
- :last_body => last_body
- }
- end
-
- # We always set Reply-To when we set Return-Path to be different from From,
- # since some email clients seem to erroneously use the envelope from when
- # they shouldn't, and this might help. (Have had mysterious cases of a
- # reply coming in duplicate from a public body to both From and envelope
- # from)
-
- # Send message to another user
- def user_message(from_user, recipient_user, from_user_url, subject, message)
- @from = from_user.name_and_email
- # Do not set envelope from address to the from_user, so they can't get
- # someone's email addresses from transitory bounce messages.
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from
- @recipients = recipient_user.name_and_email
- @subject = subject
- @body = {
- :message => message,
- :from_user => from_user,
- :recipient_user => recipient_user,
- :from_user_url => from_user_url
- }
- end
-
- # Send message to a user from the administrator
- def from_admin_message(recipient_user, subject, message)
- @from = contact_from_name_and_email
- @recipients = recipient_user.name_and_email
- @subject = subject
- @body = {
- :message => message,
- :from_user => @from,
- :recipient_user => recipient_user,
- }
- bcc Configuration::contact_email
- end
-
-end
diff --git a/app/models/contact_validator.rb b/app/models/contact_validator.rb
index d277161f9..65e539669 100644
--- a/app/models/contact_validator.rb
+++ b/app/models/contact_validator.rb
@@ -1,35 +1,29 @@
-# == Schema Information
-# Schema version: 114
-#
-# Table name: contact_validators
-#
-# name :string
-# email :string
-# subject :text
-# message :text
-#
-
# models/contact_validator.rb:
# Validates contact form submissions.
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
-class ContactValidator < ActiveRecord::BaseWithoutTable
- strip_attributes!
+class ContactValidator
+ include ActiveModel::Validations
- column :name, :string
- column :email, :string
- column :subject, :text
- column :message, :text
+ attr_accessor :name, :email, :subject, :message
validates_presence_of :name, :message => N_("Please enter your name")
validates_presence_of :email, :message => N_("Please enter your email address")
validates_presence_of :subject, :message => N_("Please enter a subject")
validates_presence_of :message, :message => N_("Please enter the message you want to send")
+ validate :email_format
- def validate
- errors.add(:email, _("Email doesn't look like a valid address")) unless MySociety::Validate.is_valid_email(self.email)
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ send("#{name}=", value)
+ end
end
+ private
+
+ def email_format
+ errors.add(:email, _("Email doesn't look like a valid address")) unless MySociety::Validate.is_valid_email(self.email)
+ end
end
diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb
index bba0b6a8d..0340f2b83 100644
--- a/app/models/foi_attachment.rb
+++ b/app/models/foi_attachment.rb
@@ -20,7 +20,7 @@
# An attachment to an email (IncomingMessage)
#
# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
# This is the type which is used to send data about attachments to the view
require 'digest'
@@ -38,11 +38,7 @@ class FoiAttachment < ActiveRecord::Base
BODY_MAX_DELAY = 5
def directory
- rails_env = Rails.env
- if rails_env.nil? || rails_env.empty?
- raise "$RAILS_ENV is not set"
- end
- base_dir = File.expand_path(File.join(File.dirname(__FILE__), "../../cache", "attachments_#{rails_env}"))
+ base_dir = File.expand_path(File.join(File.dirname(__FILE__), "../../cache", "attachments_#{Rails.env}"))
return File.join(base_dir, self.hexdigest[0..2])
end
@@ -67,28 +63,20 @@ class FoiAttachment < ActiveRecord::Base
file.write d
}
update_display_size!
- encode_cached_body!
@cached_body = d
end
- # If the original mail part had a charset, it's some kind of string, so assume that
- # it should be handled as a string in the stated charset, not a bytearray, and then
- # convert it our default encoding. For ruby 1.8 this is a noop.
- def encode_cached_body!
- if RUBY_VERSION.to_f >= 1.9
- if charset
- @cached_body.force_encoding(charset)
- @cached_body = @cached_body.encode(Encoding.default_internal, charset)
- end
- end
- end
-
def body
if @cached_body.nil?
tries = 0
delay = 1
begin
- @cached_body = File.open(self.filepath, "rb" ).read
+ binary_data = File.open(self.filepath, "rb" ).read
+ if self.content_type =~ /^text/
+ @cached_body = convert_string_to_utf8_or_binary(binary_data, 'UTF-8')
+ else
+ @cached_body = binary_data
+ end
rescue Errno::ENOENT
# we've lost our cached attachments for some reason. Reparse them.
if tries > BODY_MAX_TRIES
@@ -103,7 +91,6 @@ class FoiAttachment < ActiveRecord::Base
self.incoming_message.parse_raw_email!(force)
retry
end
- encode_cached_body!
end
return @cached_body
end
diff --git a/app/models/holiday.rb b/app/models/holiday.rb
index 13258396a..98f73e963 100644
--- a/app/models/holiday.rb
+++ b/app/models/holiday.rb
@@ -19,7 +19,7 @@
# -- Freedom of Information Act 2000 section 10
#
# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class Holiday < ActiveRecord::Base
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index 5c845ead3..f959a8799 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -25,19 +25,16 @@
# response from the public body.
#
# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
# TODO
# Move some of the (e.g. quoting) functions here into rblib, as they feel
# general not specific to IncomingMessage.
-require 'alaveteli_file_types'
require 'htmlentities'
require 'rexml/document'
require 'zip/zip'
-require 'mapi/msg'
-require 'mapi/convert'
-
+require 'iconv' unless RUBY_VERSION >= '1.9'
class IncomingMessage < ActiveRecord::Base
belongs_to :info_request
@@ -132,6 +129,7 @@ class IncomingMessage < ActiveRecord::Base
end
self.valid_to_reply_to = self._calculate_valid_to_reply_to
self.last_parsed = Time.now
+ self.foi_attachments reload=true
self.save!
end
end
@@ -173,15 +171,29 @@ class IncomingMessage < ActiveRecord::Base
super
end
- # And look up by URL part number to get an attachment
+ # And look up by URL part number and display filename to get an attachment
# XXX relies on extract_attachments calling MailHandler.ensure_parts_counted
- def self.get_attachment_by_url_part_number(attachments, found_url_part_number)
- attachments.each do |a|
- if a.url_part_number == found_url_part_number
- return a
+ # The filename here is passed from the URL parameter, so it's the
+ # display_filename rather than the real filename.
+ def self.get_attachment_by_url_part_number_and_filename(attachments, found_url_part_number, display_filename)
+ attachment_by_part_number = attachments.detect { |a| a.url_part_number == found_url_part_number }
+ if attachment_by_part_number && attachment_by_part_number.display_filename == display_filename
+ # Then the filename matches, which is fine:
+ attachment_by_part_number
+ else
+ # Otherwise if the URL part number and filename don't
+ # match - this is probably due to a reparsing of the
+ # email. In that case, try to find a unique matching
+ # filename from any attachment.
+ attachments_by_filename = attachments.select { |a|
+ a.display_filename == display_filename
+ }
+ if attachments_by_filename.length == 1
+ attachments_by_filename[0]
+ else
+ nil
end
end
- return nil
end
# Converts email addresses we know about into textual descriptions of them
@@ -193,7 +205,7 @@ class IncomingMessage < ActiveRecord::Base
text.gsub!(self.info_request.public_body.request_email, _("[{{public_body}} request email]", :public_body => self.info_request.public_body.short_or_long_name))
end
text.gsub!(self.info_request.incoming_email, _('[FOI #{{request}} email]', :request => self.info_request.id.to_s) )
- text.gsub!(Configuration::contact_email, _("[{{site_name}} contact email]", :site_name => Configuration::site_name) )
+ text.gsub!(AlaveteliConfiguration::contact_email, _("[{{site_name}} contact email]", :site_name => AlaveteliConfiguration::site_name) )
end
# Replaces all email addresses in (possibly binary data) with equal length alternative ones.
@@ -219,7 +231,7 @@ class IncomingMessage < ActiveRecord::Base
if censored_uncompressed_text != uncompressed_text
# then use the altered file (recompressed)
recompressed_text = nil
- if Configuration::use_ghostscript_compression == true
+ if AlaveteliConfiguration::use_ghostscript_compression == true
command = ["gs", "-sDEVICE=pdfwrite", "-dCompatibilityLevel=1.4", "-dPDFSETTINGS=/screen", "-dNOPAUSE", "-dQUIET", "-dBATCH", "-sOutputFile=-", "-"]
else
command = ["pdftk", "-", "output", "-", "compress"]
@@ -258,11 +270,21 @@ class IncomingMessage < ActiveRecord::Base
# equivalents to the UCS-2
ascii_chars = text.gsub(/\0/, "")
emails = ascii_chars.scan(MySociety::Validate.email_find_regexp)
+
# Convert back to UCS-2, making a mask at the same time
- emails.map! {|email| [
- Iconv.conv('ucs-2le', 'ascii', email[0]),
- Iconv.conv('ucs-2le', 'ascii', email[0].gsub(/[^@.]/, 'x'))
- ] }
+ if RUBY_VERSION >= '1.9'
+ emails.map! do |email|
+ # We want the ASCII representation of UCS-2
+ [email[0].encode('UTF-16LE').force_encoding('US-ASCII'),
+ email[0].gsub(/[^@.]/, 'x').encode('UTF-16LE').force_encoding('US-ASCII')]
+ end
+ else
+ emails.map! {|email| [
+ Iconv.conv('ucs-2le', 'ascii', email[0]),
+ Iconv.conv('ucs-2le', 'ascii', email[0].gsub(/[^@.]/, 'x'))
+ ] }
+ end
+
# Now search and replace the UCS-2 email with the UCS-2 mask
for email, mask in emails
text.gsub!(email, mask)
@@ -316,7 +338,7 @@ class IncomingMessage < ActiveRecord::Base
text.gsub!(/(Mobile|Mob)([\s\/]*(Fax|Tel))*\s*:?[\s\d]*\d/, "[mobile number]")
# Remove WhatDoTheyKnow signup links
- text.gsub!(/http:\/\/#{Configuration::domain}\/c\/[^\s]+/, "[WDTK login link]")
+ text.gsub!(/http:\/\/#{AlaveteliConfiguration::domain}\/c\/[^\s]+/, "[WDTK login link]")
# Remove things from censor rules
self.info_request.apply_censor_rules_to_text!(text)
@@ -534,7 +556,7 @@ class IncomingMessage < ActiveRecord::Base
source_charset = 'utf-8' if source_charset.nil?
text = Iconv.conv('utf-8//IGNORE', source_charset, text) +
_("\n\n[ {{site_name}} note: The above text was badly encoded, and has had strange characters removed. ]",
- :site_name => Configuration::site_name)
+ :site_name => AlaveteliConfiguration::site_name)
rescue Iconv::InvalidEncoding, Iconv::IllegalSequence, Iconv::InvalidCharacter
if source_charset != "utf-8"
source_charset = "utf-8"
@@ -546,9 +568,11 @@ class IncomingMessage < ActiveRecord::Base
text
end
- # Returns part which contains main body text, or nil if there isn't one
- def get_main_body_text_part
- leaves = self.foi_attachments
+ # Returns part which contains main body text, or nil if there isn't one,
+ # from a set of foi_attachments. If the leaves parameter is empty or not
+ # supplied, uses its own foi_attachments.
+ def get_main_body_text_part(leaves=[])
+ leaves = self.foi_attachments if leaves.empty?
# Find first part which is text/plain or text/html
# (We have to include HTML, as increasingly there are mail clients that
@@ -582,6 +606,7 @@ class IncomingMessage < ActiveRecord::Base
# nil in this case)
return p
end
+
# Returns attachments that are uuencoded in main body part
def _uudecode_and_save_attachments(text)
# Find any uudecoded things buried in it, yeuchly
@@ -605,7 +630,7 @@ class IncomingMessage < ActiveRecord::Base
content_type = 'application/octet-stream'
end
hexdigest = Digest::MD5.hexdigest(content)
- attachment = self.foi_attachments.find_or_create_by_hexdigest(:hexdigest => hexdigest)
+ attachment = self.foi_attachments.find_or_create_by_hexdigest(hexdigest)
attachment.update_attributes(:filename => filename,
:content_type => content_type,
:body => content,
@@ -632,15 +657,19 @@ class IncomingMessage < ActiveRecord::Base
attachment_attributes = MailHandler.get_attachment_attributes(self.mail(force))
attachments = []
attachment_attributes.each do |attrs|
- attachment = self.foi_attachments.find_or_create_by_hexdigest(:hexdigest => attrs[:hexdigest])
- body = attrs.delete(:body)
+ attachment = self.foi_attachments.find_or_create_by_hexdigest(attrs[:hexdigest])
attachment.update_attributes(attrs)
- # Set the body separately as its handling can depend on the value of charset
- attachment.body = body
attachment.save!
- attachments << attachment.id
+ attachments << attachment
end
- main_part = get_main_body_text_part
+
+ # Reload to refresh newly created foi_attachments
+ self.reload
+
+ # get the main body part from the set of attachments we just created,
+ # not from the self.foi_attachments association - some of the total set of
+ # self.foi_attachments may now be obsolete
+ main_part = get_main_body_text_part(attachments)
# we don't use get_main_body_text_internal, as we want to avoid charset
# conversions, since /usr/bin/uudecode needs to deal with those.
# e.g. for https://secure.mysociety.org/admin/foi/request/show_raw_email/24550
@@ -651,12 +680,14 @@ class IncomingMessage < ActiveRecord::Base
c += 1
uudecode_attachment.url_part_number = c
uudecode_attachment.save!
- attachments << uudecode_attachment.id
+ attachments << uudecode_attachment
end
end
+ attachment_ids = attachments.map{ |attachment| attachment.id }
# now get rid of any attachments we no longer have
- FoiAttachment.destroy_all("id NOT IN (#{attachments.join(',')}) AND incoming_message_id = #{self.id}")
+ FoiAttachment.destroy_all(["id NOT IN (?) AND incoming_message_id = ?",
+ attachment_ids, self.id])
end
# Returns body text as HTML with quotes flattened, and emails removed.
@@ -748,9 +779,15 @@ class IncomingMessage < ActiveRecord::Base
attachment.body,
attachment.charset)
end
+
# Remove any bad characters
- text = Iconv.conv('utf-8//IGNORE', 'utf-8', text)
- return text
+ if RUBY_VERSION >= '1.9'
+ text.encode("utf-8", :invalid => :replace,
+ :undef => :replace,
+ :replace => "")
+ else
+ Iconv.conv('utf-8//IGNORE', 'utf-8', text)
+ end
end
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index eaed25a61..cf1af0e87 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -26,8 +26,7 @@
require 'digest/sha1'
class InfoRequest < ActiveRecord::Base
- include ActionView::Helpers::UrlHelper
- include ActionController::UrlWriter
+ include Rails.application.routes.url_helpers
strip_attributes!
@@ -51,7 +50,7 @@ class InfoRequest < ActiveRecord::Base
has_tag_string
- named_scope :visible, :conditions => {:prominence => "normal"}
+ scope :visible, :conditions => {:prominence => "normal"}
# user described state (also update in info_request_event, admin_request/edit.rhtml)
validate :must_be_valid_state
@@ -81,6 +80,11 @@ class InfoRequest < ActiveRecord::Base
'blackhole' # just dump them
]
+ # only check on create, so existing models with mixed case are allowed
+ validate :title_formatting, :on => :create
+
+ after_initialize :set_defaults
+
def self.enumerate_states
states = [
'waiting_response',
@@ -148,7 +152,7 @@ class InfoRequest < ActiveRecord::Base
@@custom_states_loaded = false
begin
- if ENV["RAILS_ENV"] != "test"
+ if !Rails.env.test?
require 'customstates'
include InfoRequestCustomStates
@@custom_states_loaded = true
@@ -456,7 +460,7 @@ public
if !allow
if self.handle_rejected_responses == 'bounce'
- RequestMailer.deliver_stopped_responses(self, email, raw_email_data) if !is_external?
+ RequestMailer.stopped_responses(self, email, raw_email_data).deliver if !is_external?
elsif self.handle_rejected_responses == 'holding_pen'
InfoRequest.holding_pen_request.receive(email, raw_email_data, false, reason)
elsif self.handle_rejected_responses == 'blackhole'
@@ -495,13 +499,13 @@ public
self.awaiting_description = true
params = { :incoming_message_id => incoming_message.id }
if !rejected_reason.empty?
- params[:rejected_reason] = rejected_reason
+ params[:rejected_reason] = rejected_reason.to_str
end
self.log_event("response", params)
self.save!
end
self.info_request_events.each { |event| event.xapian_mark_needs_index } # for the "waiting_classification" index
- RequestMailer.deliver_new_response(self, incoming_message) if !is_external?
+ RequestMailer.new_response(self, incoming_message).deliver if !is_external?
end
@@ -554,6 +558,10 @@ public
# states which require administrator action (hence email administrators
# when they are entered, and offer state change dialog to them)
+ def InfoRequest.requires_admin_states
+ return ['requires_admin', 'error_message', 'attention_requested']
+ end
+
def requires_admin?
['requires_admin', 'error_message', 'attention_requested'].include?(described_state)
end
@@ -575,7 +583,7 @@ public
if self.requires_admin?
# Check there is someone to send the message "from"
if !set_by.nil? || !self.user.nil?
- RequestMailer.deliver_requires_admin(self, set_by, message)
+ RequestMailer.requires_admin(self, set_by, message).deliver
end
end
@@ -590,7 +598,7 @@ public
RequestClassification.create!(:user_id => set_by.id,
:info_request_event_id => event.id)
- RequestMailer.deliver_old_unclassified_updated(self) if !is_external?
+ RequestMailer.old_unclassified_updated(self).deliver if !is_external?
end
end
@@ -705,7 +713,7 @@ public
# last_event_forming_initial_request. There may be more obscure
# things, e.g. fees, not properly covered.
def date_response_required_by
- Holiday.due_date_from(self.date_initial_request_last_sent_at, Configuration::reply_late_after_days, Configuration::working_or_calendar_days)
+ Holiday.due_date_from(self.date_initial_request_last_sent_at, AlaveteliConfiguration::reply_late_after_days, AlaveteliConfiguration::working_or_calendar_days)
end
# This is a long stop - even with UK public interest test extensions, 40
# days is a very long time.
@@ -713,10 +721,10 @@ public
last_sent = last_event_forming_initial_request
if self.public_body.is_school?
# schools have 60 working days maximum (even over a long holiday)
- Holiday.due_date_from(self.date_initial_request_last_sent_at, Configuration::special_reply_very_late_after_days, Configuration::working_or_calendar_days)
+ Holiday.due_date_from(self.date_initial_request_last_sent_at, AlaveteliConfiguration::special_reply_very_late_after_days, AlaveteliConfiguration::working_or_calendar_days)
else
# public interest test ICO guidance gives 40 working maximum
- Holiday.due_date_from(self.date_initial_request_last_sent_at, Configuration::reply_very_late_after_days, Configuration::working_or_calendar_days)
+ Holiday.due_date_from(self.date_initial_request_last_sent_at, AlaveteliConfiguration::reply_very_late_after_days, AlaveteliConfiguration::working_or_calendar_days)
end
end
@@ -802,6 +810,16 @@ public
end
end
+ # Returns last event
+ def get_last_event
+ events = self.info_request_events
+ if events.size == 0
+ return nil
+ else
+ return events[-1]
+ end
+ end
+
# Get previous email sent to
def get_previous_email_sent_to(info_request_event)
last_email = nil
@@ -878,10 +896,10 @@ public
end
def InfoRequest.magic_email_for_id(prefix_part, id)
- magic_email = Configuration::incoming_email_prefix
+ magic_email = AlaveteliConfiguration::incoming_email_prefix
magic_email += prefix_part + id.to_s
magic_email += "-" + InfoRequest.hash_from_id(id)
- magic_email += "@" + Configuration::incoming_email_domain
+ magic_email += "@" + AlaveteliConfiguration::incoming_email_domain
return magic_email
end
@@ -892,7 +910,7 @@ public
end
def InfoRequest.hash_from_id(id)
- return Digest::SHA1.hexdigest(id.to_s + Configuration::incoming_email_secret)[0,8]
+ return Digest::SHA1.hexdigest(id.to_s + AlaveteliConfiguration::incoming_email_secret)[0,8]
end
# Called by find_by_incoming_email - and used to be called by separate
@@ -1115,7 +1133,7 @@ public
before_save :purge_in_cache
def purge_in_cache
- if !Configuration::varnish_host.blank? && !self.id.nil?
+ if !AlaveteliConfiguration::varnish_host.blank? && !self.id.nil?
# we only do this for existing info_requests (new ones have a nil id)
path = url_for(:controller => 'request', :action => 'show', :url_title => self.url_title, :only_path => true, :locale => :none)
req = PurgeRequest.find_by_url(path)
@@ -1133,5 +1151,34 @@ public
yield(column.human_name, self.send(column.name), column.type.to_s, column.name)
end
end
+
+ private
+
+ def set_defaults
+ begin
+ if self.described_state.nil?
+ self.described_state = 'waiting_response'
+ end
+ rescue ActiveModel::MissingAttributeError
+ # this should only happen on Model.exists?() call. It can be safely ignored.
+ # See http://www.tatvartha.com/2011/03/activerecordmissingattributeerror-missing-attribute-a-bug-or-a-features/
+ end
+ # FOI or EIR?
+ if !self.public_body.nil? && self.public_body.eir_only?
+ self.law_used = 'eir'
+ end
+ end
+
+ def title_formatting
+ if !self.title.nil? && !MySociety::Validate.uses_mixed_capitals(self.title, 10)
+ errors.add(:title, _('Please write the summary using a mixture of capital and lower case letters. This makes it easier for others to read.'))
+ end
+ if !self.title.nil? && title.size > 200
+ errors.add(:title, _('Please keep the summary short, like in the subject of an email. You can use a phrase, rather than a full sentence.'))
+ end
+ if !self.title.nil? && self.title =~ /^(FOI|Freedom of Information)\s*requests?$/i
+ errors.add(:title, _('Please describe more what the request is about in the subject. There is no need to say it is an FOI request, we add that on anyway.'))
+ end
+ end
end
diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb
index 871b81b1f..469aabc4a 100644
--- a/app/models/info_request_event.rb
+++ b/app/models/info_request_event.rb
@@ -20,7 +20,7 @@
# models/info_request_event.rb:
#
# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class InfoRequestEvent < ActiveRecord::Base
belongs_to :info_request
@@ -405,7 +405,7 @@ class InfoRequestEvent < ActiveRecord::Base
:comment_id => self.comment_id,
# XXX would be nice to add links here, but alas the
- # code to make them is in views only. See views/request/details.rhtml
+ # code to make them is in views only. See views/request/details.html.erb
# perhaps can call with @template somehow
}
diff --git a/app/models/mail_server_log.rb b/app/models/mail_server_log.rb
index 755584b90..7f61377ce 100644
--- a/app/models/mail_server_log.rb
+++ b/app/models/mail_server_log.rb
@@ -15,9 +15,7 @@
# We load log file lines for requests in here, for display in the admin interface.
#
# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-#
-# $Id: exim_log.rb,v 1.14 2009-09-17 21:10:05 francis Exp $
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class MailServerLog < ActiveRecord::Base
belongs_to :info_request
@@ -53,7 +51,7 @@ class MailServerLog < ActiveRecord::Base
done.save!
f = is_gz ? Zlib::GzipReader.open(file_name) : File.open(file_name, 'r')
- case(Configuration::mta_log_type.to_sym)
+ case(AlaveteliConfiguration::mta_log_type.to_sym)
when :exim
load_exim_log_data(f, done)
when :postfix
@@ -123,13 +121,13 @@ class MailServerLog < ActiveRecord::Base
# We also check the email prefix so that we could, for instance, separately handle a staging and production
# instance running on the same server with different email prefixes.
def MailServerLog.email_addresses_on_line(line)
- prefix = Regexp::quote(Configuration::incoming_email_prefix)
- domain = Regexp::quote(Configuration::incoming_email_domain)
+ prefix = Regexp::quote(AlaveteliConfiguration::incoming_email_prefix)
+ domain = Regexp::quote(AlaveteliConfiguration::incoming_email_domain)
line.scan(/#{prefix}request-[^\s]+@#{domain}/).sort.uniq
end
def MailServerLog.request_sent?(ir)
- case(Configuration::mta_log_type.to_sym)
+ case(AlaveteliConfiguration::mta_log_type.to_sym)
when :exim
request_exim_sent?(ir)
when :postfix
diff --git a/app/models/mail_server_log_done.rb b/app/models/mail_server_log_done.rb
index 3fb20f0b3..0e7e9eec3 100644
--- a/app/models/mail_server_log_done.rb
+++ b/app/models/mail_server_log_done.rb
@@ -13,7 +13,7 @@
# Stores that a particular mail server log file has been loaded in, see mail_server_log.rb
#
# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class MailServerLogDone < ActiveRecord::Base
has_many :mail_server_logs
diff --git a/app/models/outgoing_mailer.rb b/app/models/outgoing_mailer.rb
deleted file mode 100644
index 503166b8a..000000000
--- a/app/models/outgoing_mailer.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# models/outgoing_mailer.rb:
-# Emails which go to public bodies on behalf of users.
-#
-# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-# Note: The layout for this wraps messages by lines rather than (blank line
-# separated) paragraphs, as is the convention for all the other mailers. This
-# turned out to fit better with user exepectations when formatting messages.
-#
-# XXX The other mail templates are written to use blank line separated
-# paragraphs. They could be rewritten, and the wrapping method made uniform
-# throughout the application.
-
-class OutgoingMailer < ApplicationMailer
-
- # Email to public body requesting info
- def initial_request(info_request, outgoing_message)
- @wrap_lines_as_paragraphs = true
- @from = info_request.incoming_name_and_email
- @recipients = info_request.recipient_name_and_email
- @subject = info_request.email_subject_request
- @headers["message-id"] = OutgoingMailer.id_for_message(outgoing_message)
- @body = {:info_request => info_request, :outgoing_message => outgoing_message,
- :contact_email => Configuration::contact_email }
- end
-
- # Later message to public body regarding existing request
- def followup(info_request, outgoing_message, incoming_message_followup)
- @wrap_lines_as_paragraphs = true
- @from = info_request.incoming_name_and_email
- @recipients = OutgoingMailer.name_and_email_for_followup(info_request, incoming_message_followup)
- @subject = OutgoingMailer.subject_for_followup(info_request, outgoing_message)
- @headers["message-id"] = OutgoingMailer.id_for_message(outgoing_message)
- @body = {:info_request => info_request, :outgoing_message => outgoing_message,
- :incoming_message_followup => incoming_message_followup,
- :contact_email => Configuration::contact_email }
- end
-
- # XXX the condition checking valid_to_reply_to? also appears in views/request/_followup.rhtml,
- # it shouldn't really, should call something here.
- # XXX also OutgoingMessage.get_salutation
- # XXX these look like they should be members of IncomingMessage, but logically they
- # need to work even when IncomingMessage is nil
- def OutgoingMailer.name_and_email_for_followup(info_request, incoming_message_followup)
- if incoming_message_followup.nil? || !incoming_message_followup.valid_to_reply_to?
- return info_request.recipient_name_and_email
- else
- # calling safe_mail_from from so censor rules are run
- return MailHandler.address_from_name_and_email(incoming_message_followup.safe_mail_from,
- incoming_message_followup.from_email)
- end
- end
- # Used in the preview of followup
- def OutgoingMailer.name_for_followup(info_request, incoming_message_followup)
- if incoming_message_followup.nil? || !incoming_message_followup.valid_to_reply_to?
- return info_request.public_body.name
- else
- # calling safe_mail_from from so censor rules are run
- return incoming_message_followup.safe_mail_from || info_request.public_body.name
- end
- end
- # Used when making list of followup places to remove duplicates
- def OutgoingMailer.email_for_followup(info_request, incoming_message_followup)
- if incoming_message_followup.nil? || !incoming_message_followup.valid_to_reply_to?
- return info_request.recipient_email
- else
- return incoming_message_followup.from_email
- end
- end
- # Subject to use for followup
- def OutgoingMailer.subject_for_followup(info_request, outgoing_message)
- if outgoing_message.what_doing == 'internal_review'
- return "Internal review of " + info_request.email_subject_request
- else
- return info_request.email_subject_followup(outgoing_message.incoming_message_followup)
- end
- end
- # Whether we have a valid email address for a followup
- def OutgoingMailer.is_followupable?(info_request, incoming_message_followup)
- if incoming_message_followup.nil? || !incoming_message_followup.valid_to_reply_to?
- return info_request.recipient_email_valid_for_followup?
- else
- # email has been checked in incoming_message_followup.valid_to_reply_to? above
- return true
- end
- end
- # Message-ID to use
- def OutgoingMailer.id_for_message(outgoing_message)
- message_id = "ogm-" + outgoing_message.id.to_s
- t = Time.now
- message_id += "+" + '%08x%05x-%04x' % [t.to_i, t.tv_usec, rand(0xffff)]
- message_id += "@" + Configuration::incoming_email_domain
- return "<" + message_id + ">"
- end
-
-end
-
diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb
index 248125808..dbe2cf1ca 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -20,7 +20,7 @@
# else. e.g. An initial request for information, or a complaint.
#
# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class OutgoingMessage < ActiveRecord::Base
strip_attributes!
@@ -51,6 +51,8 @@ class OutgoingMessage < ActiveRecord::Base
end
end
+ after_initialize :set_default_letter
+
# How the default letter starts and ends
def get_salutation
ret = ""
@@ -86,7 +88,7 @@ class OutgoingMessage < ActiveRecord::Base
"'" + self.info_request.title + "'." +
"\n\n\n\n [ " + self.get_internal_review_insert_here_note + " ] \n\n\n\n" +
"A full history of my FOI request and all correspondence is available on the Internet at this address:\n" +
- "http://" + Configuration::domain + "/request/" + self.info_request.url_title
+ "http://" + AlaveteliConfiguration::domain + "/request/" + self.info_request.url_title
else
""
end
@@ -130,13 +132,6 @@ class OutgoingMessage < ActiveRecord::Base
MySociety::Validate.contains_postcode?(self.body)
end
- # Set default letter
- def after_initialize
- if self.body.nil?
- self.body = get_default_message
- end
- end
-
# Deliver outgoing message
# Note: You can test this from script/console with, say:
# InfoRequest.find(1).outgoing_messages[0].send_message
@@ -147,7 +142,7 @@ class OutgoingMessage < ActiveRecord::Base
self.status = 'sent'
self.save!
- mail_message = OutgoingMailer.deliver_initial_request(self.info_request, self)
+ mail_message = OutgoingMailer.initial_request(self.info_request, self).deliver
self.info_request.log_event(log_event_type, {
:email => mail_message.to_addrs.join(", "),
:outgoing_message_id => self.id,
@@ -159,7 +154,7 @@ class OutgoingMessage < ActiveRecord::Base
self.status = 'sent'
self.save!
- mail_message = OutgoingMailer.deliver_followup(self.info_request, self, self.incoming_message_followup)
+ mail_message = OutgoingMailer.followup(self.info_request, self, self.incoming_message_followup).deliver
self.info_request.log_event('followup_' + log_event_type, {
:email => mail_message.to_addrs.join(", "),
:outgoing_message_id => self.id,
@@ -253,6 +248,12 @@ class OutgoingMessage < ActiveRecord::Base
private
+ def set_default_letter
+ if self.body.nil?
+ self.body = get_default_message
+ end
+ end
+
def format_of_body
if self.body.empty? || self.body =~ /\A#{get_salutation}\s+#{get_signoff}/ || self.body =~ /#{get_internal_review_insert_here_note}/
if self.message_type == 'followup'
diff --git a/app/models/post_redirect.rb b/app/models/post_redirect.rb
index 31f08c21a..409069cb6 100644
--- a/app/models/post_redirect.rb
+++ b/app/models/post_redirect.rb
@@ -24,7 +24,7 @@
# fakes the redirect to include POST parameters in request later.
#
# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
require 'openssl' # for random bytes function
@@ -32,6 +32,8 @@ class PostRedirect < ActiveRecord::Base
# Optional, does a login confirm before redirect for use in email links.
belongs_to :user
+ after_initialize :generate_token
+
# We store YAML version of POST parameters in the database
def post_params=(params)
self.post_params_yaml = params.to_yaml
@@ -62,18 +64,6 @@ class PostRedirect < ActiveRecord::Base
MySociety::Util.generate_token
end
- # Make the token
- def after_initialize
- # The token is used to return you to what you are doing after the login form.
- if not self.token
- self.token = PostRedirect.generate_random_token
- end
- # There is a separate token to use in the URL if we send a confirmation email.
- if not self.email_token
- self.email_token = PostRedirect.generate_random_token
- end
- end
-
# Used by (rspec) test code only
def self.get_last_post_redirect
# XXX yeuch - no other easy way of getting the token so we can check
@@ -89,6 +79,18 @@ class PostRedirect < ActiveRecord::Base
PostRedirect.delete_all "updated_at < (now() - interval '2 months')"
end
+ private
+
+ def generate_token
+ # The token is used to return you to what you are doing after the login form.
+ if not self.token
+ self.token = PostRedirect.generate_random_token
+ end
+ # There is a separate token to use in the URL if we send a confirmation email.
+ if not self.email_token
+ self.email_token = PostRedirect.generate_random_token
+ end
+ end
end
diff --git a/app/models/profile_photo.rb b/app/models/profile_photo.rb
index f6aec6338..5d542daf1 100644
--- a/app/models/profile_photo.rb
+++ b/app/models/profile_photo.rb
@@ -13,7 +13,7 @@
# Image of user that goes on their profile.
#
# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class ProfilePhoto < ActiveRecord::Base
WIDTH = 96
@@ -29,25 +29,9 @@ class ProfilePhoto < ActiveRecord::Base
attr_accessor :x, :y, :w, :h
- # convert binary data blob into ImageMagick image when assigned
attr_accessor :image
- def after_initialize
- if data.nil?
- self.image = nil
- return
- end
-
- image_list = Magick::ImageList.new
- begin
- image_list.from_blob(data)
- rescue Magick::ImageMagickError
- self.image = nil
- return
- end
- self.image = image_list[0] # XXX perhaps take largest image or somesuch if there were multiple in the file?
- self.convert_image
- end
+ after_initialize :convert_data_to_image
# make image valid format and size
def convert_image
@@ -112,6 +96,25 @@ class ProfilePhoto < ActiveRecord::Base
raise "Internal error, real pictures must have a user"
end
end
+
+ # Convert binary data blob into ImageMagick image when assigned
+ def convert_data_to_image
+ if data.nil?
+ self.image = nil
+ return
+ end
+
+ image_list = Magick::ImageList.new
+ begin
+ image_list.from_blob(data)
+ rescue Magick::ImageMagickError
+ self.image = nil
+ return
+ end
+
+ self.image = image_list[0] # XXX perhaps take largest image or somesuch if there were multiple in the file?
+ self.convert_image
+ end
end
diff --git a/app/models/public_body.rb b/app/models/public_body.rb
index b4d36fe91..a76aeb189 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -45,7 +45,7 @@ class PublicBody < ActiveRecord::Base
before_save :set_api_key, :set_default_publication_scheme
# Every public body except for the internal admin one is visible
- named_scope :visible, lambda {
+ scope :visible, lambda {
{
:conditions => "public_bodies.id <> #{PublicBody.internal_admin_body.id}"
}
@@ -54,7 +54,7 @@ class PublicBody < ActiveRecord::Base
translates :name, :short_name, :request_email, :url_name, :notes, :first_letter, :publication_scheme
# Convenience methods for creating/editing translations via forms
- def translation(locale)
+ def find_translation_by_locale(locale)
self.translations.find_by_locale(locale)
end
@@ -79,7 +79,7 @@ class PublicBody < ActiveRecord::Base
if translation_attrs.respond_to? :each_value # Hash => updating
translation_attrs.each_value do |attrs|
next if skip?(attrs)
- t = translation(attrs[:locale]) || PublicBody::Translation.new
+ t = translation_for(attrs[:locale]) || PublicBody::Translation.new
t.attributes = attrs
calculate_cached_fields(t)
t.save!
@@ -332,7 +332,7 @@ class PublicBody < ActiveRecord::Base
pb = PublicBody.new(
:name => 'Internal admin authority',
:short_name => "",
- :request_email => Configuration::contact_email,
+ :request_email => AlaveteliConfiguration::contact_email,
:home_page => "",
:notes => "",
:publication_scheme => "",
@@ -548,7 +548,7 @@ class PublicBody < ActiveRecord::Base
# Returns nil if configuration variable not set
def override_request_email
- e = Configuration::override_all_public_body_request_emails
+ e = AlaveteliConfiguration::override_all_public_body_request_emails
e if e != ""
end
@@ -632,6 +632,8 @@ class PublicBody < ActiveRecord::Base
end
end
+ private
+
def request_email_if_requestable
# Request_email can be blank, meaning we don't have details
if self.is_requestable?
diff --git a/app/models/purge_request.rb b/app/models/purge_request.rb
index 48a16f9e6..e48f3cc6f 100644
--- a/app/models/purge_request.rb
+++ b/app/models/purge_request.rb
@@ -14,7 +14,7 @@
# A queue of URLs to purge
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
#
class PurgeRequest < ActiveRecord::Base
diff --git a/app/models/raw_email.rb b/app/models/raw_email.rb
index de7978b82..6bf01bc74 100644
--- a/app/models/raw_email.rb
+++ b/app/models/raw_email.rb
@@ -10,7 +10,7 @@
# The fat part of models/incoming_message.rb
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class RawEmail < ActiveRecord::Base
# deliberately don't strip_attributes, so keeps raw email properly
@@ -23,10 +23,10 @@ class RawEmail < ActiveRecord::Base
raise "Failed to find the id number of the associated request: has it been saved?"
end
- if ENV["RAILS_ENV"] == "test"
+ if Rails.env.test?
return File.join(Rails.root, 'files/raw_email_test')
else
- return File.join(Configuration::raw_emails_location,
+ return File.join(AlaveteliConfiguration::raw_emails_location,
request_id[0..2], request_id)
end
end
diff --git a/app/models/request_mailer.rb b/app/models/request_mailer.rb
deleted file mode 100644
index 955f73ef4..000000000
--- a/app/models/request_mailer.rb
+++ /dev/null
@@ -1,457 +0,0 @@
-# models/request_mailer.rb:
-# Alerts relating to requests.
-#
-# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-require 'alaveteli_file_types'
-if Rails.env == 'test' && RUBY_VERSION.to_f >= 1.9
- # Avoid spec/script/mailin_spec.rb running script/runner as a test suite
- # http://stackoverflow.com/questions/1899009/why-are-tests-running-in-production-mode-and-causing-my-script-runners-to-fail
- Test::Unit.run = true
-end
-class RequestMailer < ApplicationMailer
-
-
- # Used when an FOI officer uploads a response from their web browser - this is
- # the "fake" email used to store in the same format in the database as if they
- # had emailed it.
- def fake_response(info_request, from_user, body, attachment_name, attachment_content)
- @from = from_user.name_and_email
- @recipients = info_request.incoming_name_and_email
- @body = {
- :body => body
- }
- if !attachment_name.nil? && !attachment_content.nil?
- content_type = AlaveteliFileTypes.filename_to_mimetype(attachment_name) || 'application/octet-stream'
-
- attachment :content_type => content_type,
- :body => attachment_content,
- :filename => attachment_name
- end
- end
-
- # Used when a response is uploaded using the API
- def external_response(info_request, body, sent_at, attachments)
- @from = blackhole_email
- @recipients = info_request.incoming_name_and_email
- @body = { :body => body }
-
- # ActionMailer only works properly when the time is in the local timezone:
- # see https://rails.lighthouseapp.com/projects/8994/tickets/3113-actionmailer-only-works-correctly-with-sent_on-times-that-are-in-the-local-time-zone
- @sent_on = sent_at.dup.localtime
-
- attachments.each do |attachment_hash|
- attachment attachment_hash
- end
- end
-
- # Incoming message arrived for a request, but new responses have been stopped.
- def stopped_responses(info_request, email, raw_email_data)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # we don't care about bounces, likely from spammers
- 'Auto-Submitted' => 'auto-replied' # http://tools.ietf.org/html/rfc3834
- @recipients = email.from_addrs[0].to_s
- @subject = _("Your response to an FOI request was not delivered")
- attachment :content_type => 'message/rfc822', :body => raw_email_data,
- :filename => "original.eml", :transfer_encoding => '7bit', :content_disposition => 'inline'
- @body = {
- :info_request => info_request,
- :contact_email => Configuration::contact_email
- }
- end
-
- # An FOI response is outside the scope of the system, and needs admin attention
- def requires_admin(info_request, set_by = nil, message = "")
- user = set_by || info_request.user
- @from = user.name_and_email
- @recipients = contact_from_name_and_email
- @subject = _("FOI response requires admin ({{reason}}) - {{title}}", :reason => info_request.described_state, :title => info_request.title)
- url = request_url(info_request)
- admin_url = admin_request_show_url(info_request)
- @body = {:reported_by => user, :message => message, :info_request => info_request, :url => url, :admin_url => admin_url }
- end
-
- # Tell the requester that a new response has arrived
- 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)
-
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = info_request.user.name_and_email
- @subject = (_("New response to your FOI request - ") + info_request.title).html_safe
- @body = { :incoming_message => incoming_message, :info_request => info_request, :url => url }
- end
-
- # Tell the requester that the public body is late in replying
- def overdue_alert(info_request, user)
- respond_url = respond_to_last_url(info_request) + "#followup"
-
- post_redirect = PostRedirect.new(
- :uri => respond_url,
- :user_id => user.id)
- post_redirect.save!
- url = confirm_url(:email_token => post_redirect.email_token)
-
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = user.name_and_email
- @subject = (_("Delayed response to your FOI request - ") + info_request.title).html_safe
- @body = { :info_request => info_request, :url => url }
- end
-
- # Tell the requester that the public body is very late in replying
- def very_overdue_alert(info_request, user)
- respond_url = respond_to_last_url(info_request) + "#followup"
-
- post_redirect = PostRedirect.new(
- :uri => respond_url,
- :user_id => user.id)
- post_redirect.save!
- url = confirm_url(:email_token => post_redirect.email_token)
-
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = user.name_and_email
- @subject = (_("You're long overdue a response to your FOI request - ") + info_request.title).html_safe
- @body = { :info_request => info_request, :url => url }
- end
-
- # Tell the requester that they need to say if the new response
- # contains info or not
- def new_response_reminder_alert(info_request, incoming_message)
- # Make a link going to the form to describe state, and which logs the
- # user in.
- post_redirect = PostRedirect.new(
- :uri => request_url(info_request) + "#describe_state_form_1",
- :user_id => info_request.user.id)
- post_redirect.save!
- url = confirm_url(:email_token => post_redirect.email_token)
-
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = info_request.user.name_and_email
- @subject = _("Was the response you got to your FOI request any good?")
- @body = { :incoming_message => incoming_message, :info_request => info_request, :url => url }
- end
-
- # Tell the requester that someone updated their old unclassified request
- def old_unclassified_updated(info_request)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = info_request.user.name_and_email
- @subject = _("Someone has updated the status of your request")
- url = request_url(info_request)
- @body = {:info_request => info_request, :url => url}
- end
-
- # Tell the requester that they need to clarify their request
- def not_clarified_alert(info_request, incoming_message)
- respond_url = show_response_url(:id => info_request.id, :incoming_message_id => incoming_message.id)
- respond_url = respond_url + "#followup"
-
- post_redirect = PostRedirect.new(
- :uri => respond_url,
- :user_id => info_request.user.id)
- post_redirect.save!
- url = confirm_url(:email_token => post_redirect.email_token)
-
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = info_request.user.name_and_email
- @subject = (_("Clarify your FOI request - ") + info_request.title).html_safe
- @body = { :incoming_message => incoming_message, :info_request => info_request, :url => url }
- end
-
- # Tell requester that somebody add an annotation to their request
- def comment_on_alert(info_request, comment)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = info_request.user.name_and_email
- @subject = (_("Somebody added a note to your FOI request - ") + info_request.title).html_safe
- @body = { :comment => comment, :info_request => info_request, :url => comment_url(comment) }
- end
- def comment_on_alert_plural(info_request, count, earliest_unalerted_comment)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from, # not much we can do if the user's email is broken
- 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'X-Auto-Response-Suppress' => 'OOF'
- @recipients = info_request.user.name_and_email
- @subject = (_("Some notes have been added to your FOI request - ") + info_request.title).html_safe
- @body = { :count => count, :info_request => info_request, :url => comment_url(earliest_unalerted_comment) }
- end
-
- # Class function, called by script/mailin with all incoming responses.
- # [ This is a copy (Monkeypatch!) of function from action_mailer/base.rb,
- # but which additionally passes the raw_email to the member function, as we
- # want to record it.
- #
- # That is because we want to be sure we properly record the actual message
- # received in its raw form - so any information won't be lost in a round
- # trip via the mail handler, or by bugs in it, and so we can use something
- # other than TMail at a later date. And so we can offer an option to download the
- # actual original mail sent by the authority in the admin interface (so
- # can check that attachment decoding failures are problems in the message,
- # not in our code). ]
- def self.receive(raw_email)
- logger.info "Received mail:\n #{raw_email}" unless logger.nil?
- mail = MailHandler.mail_from_raw_email(raw_email)
- new.receive(mail, raw_email)
- end
-
- # Find which info requests the email is for
- def requests_matching_email(email)
- # We deliberately don't use Envelope-to here, so ones that are BCC
- # drop into the holding pen for checking.
- reply_info_requests = [] # XXX should be set?
- for address in (email.to || []) + (email.cc || [])
- reply_info_request = InfoRequest.find_by_incoming_email(address)
- reply_info_requests.push(reply_info_request) if reply_info_request
- end
- return reply_info_requests
- end
-
- # Member function, called on the new class made in self.receive above
- def receive(email, raw_email)
- # Find which info requests the email is for
- reply_info_requests = self.requests_matching_email(email)
- # Nothing found, so save in holding pen
- if reply_info_requests.size == 0
- reason = _("Could not identify the request from the email address")
- request = InfoRequest.holding_pen_request
- request.receive(email, raw_email, false, reason)
- return
- end
-
- # Send the message to each request, to be archived with it
- for reply_info_request in reply_info_requests
- # If environment variable STOP_DUPLICATES is set, don't send message with same id again
- if ENV['STOP_DUPLICATES']
- if reply_info_request.already_received?(email, raw_email)
- raise "message " + email.message_id + " already received by request"
- end
- end
- reply_info_request.receive(email, raw_email)
- end
- end
-
- # Send email alerts for overdue requests
- def self.alert_overdue_requests()
- info_requests = InfoRequest.find(:all,
- :conditions => [
- "described_state = 'waiting_response'
- AND awaiting_description = ?
- AND user_id is not null
- AND (SELECT id
- FROM user_info_request_sent_alerts
- WHERE alert_type = 'very_overdue_1'
- AND info_request_id = info_requests.id
- AND user_id = info_requests.user_id
- AND info_request_event_id = (SELECT max(id)
- FROM info_request_events
- WHERE event_type in ('sent',
- 'followup_sent',
- 'resent',
- 'followup_resent')
- AND info_request_id = info_requests.id)
- ) IS NULL", false
- ],
- :include => [ :user ]
- )
- for info_request in info_requests
- alert_event_id = info_request.last_event_forming_initial_request.id
- # Only overdue requests
- calculated_status = info_request.calculate_status
- if ['waiting_response_overdue', 'waiting_response_very_overdue'].include?(calculated_status)
- if calculated_status == 'waiting_response_overdue'
- alert_type = 'overdue_1'
- elsif calculated_status == 'waiting_response_very_overdue'
- alert_type = 'very_overdue_1'
- else
- raise "unknown request status"
- end
-
- # For now, just to the user who created the request
- sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = ?
- AND user_id = ?
- AND info_request_id = ?
- AND info_request_event_id = ?",
- alert_type,
- info_request.user_id,
- info_request.id,
- alert_event_id])
- if sent_already.nil?
- # Alert not yet sent for this user, so send it
- store_sent = UserInfoRequestSentAlert.new
- store_sent.info_request = info_request
- store_sent.user = info_request.user
- store_sent.alert_type = alert_type
- store_sent.info_request_event_id = alert_event_id
- # Only send the alert if the user can act on it by making a followup
- # (otherwise they are banned, and there is no point sending it)
- if info_request.user.can_make_followup?
- if calculated_status == 'waiting_response_overdue'
- RequestMailer.deliver_overdue_alert(info_request, info_request.user)
- elsif calculated_status == 'waiting_response_very_overdue'
- RequestMailer.deliver_very_overdue_alert(info_request, info_request.user)
- else
- raise "unknown request status"
- end
- end
- store_sent.save!
- end
- end
- end
- end
-
- # Send email alerts for new responses which haven't been classified. By default,
- # it goes out 3 days after last update of event, then after 10, then after 24.
- def self.alert_new_response_reminders
- Configuration::new_response_reminder_after_days.each_with_index do |days, i|
- self.alert_new_response_reminders_internal(days, "new_response_reminder_#{i+1}")
- end
- end
- def self.alert_new_response_reminders_internal(days_since, type_code)
- info_requests = InfoRequest.find_old_unclassified(:order => 'info_requests.id',
- :include => [:user],
- :age_in_days => days_since)
-
- for info_request in info_requests
- alert_event_id = info_request.get_last_response_event_id
- last_response_message = info_request.get_last_response
- if alert_event_id.nil?
- raise "internal error, no last response while making alert new response reminder, request id " + info_request.id.to_s
- end
- # To the user who created the request
- sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = ? and user_id = ? and info_request_id = ? and info_request_event_id = ?", type_code, info_request.user_id, info_request.id, alert_event_id])
- if sent_already.nil?
- # Alert not yet sent for this user
- store_sent = UserInfoRequestSentAlert.new
- store_sent.info_request = info_request
- store_sent.user = info_request.user
- store_sent.alert_type = type_code
- store_sent.info_request_event_id = alert_event_id
- # XXX uses same template for reminder 1 and reminder 2 right now.
- RequestMailer.deliver_new_response_reminder_alert(info_request, last_response_message)
- store_sent.save!
- end
- end
- end
-
- # Send email alerts for requests which need clarification. Goes out 3 days
- # after last update of event.
- def self.alert_not_clarified_request()
- info_requests = InfoRequest.find(:all, :conditions => [ "awaiting_description = ? and described_state = 'waiting_clarification' and info_requests.updated_at < ?", false, Time.now() - 3.days ], :include => [ :user ], :order => "info_requests.id" )
- for info_request in info_requests
- alert_event_id = info_request.get_last_response_event_id
- last_response_message = info_request.get_last_response
- if alert_event_id.nil?
- raise "internal error, no last response while making alert not clarified reminder, request id " + info_request.id.to_s
- end
- # To the user who created the request
- sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = 'not_clarified_1' and user_id = ? and info_request_id = ? and info_request_event_id = ?", info_request.user_id, info_request.id, alert_event_id])
- if sent_already.nil?
- # Alert not yet sent for this user
- store_sent = UserInfoRequestSentAlert.new
- store_sent.info_request = info_request
- store_sent.user = info_request.user
- store_sent.alert_type = 'not_clarified_1'
- store_sent.info_request_event_id = alert_event_id
- # Only send the alert if the user can act on it by making a followup
- # (otherwise they are banned, and there is no point sending it)
- if info_request.user.can_make_followup?
- RequestMailer.deliver_not_clarified_alert(info_request, last_response_message)
- end
- store_sent.save!
- end
- end
- end
-
- # Send email alert to request submitter for new comments on the request.
- def self.alert_comment_on_request()
-
- # We only check comments made in the last month - this means if the
- # cron jobs broke for more than a month events would be lost, but no
- # matter. I suspect the performance gain will be needed (with an index on updated_at)
-
- # XXX the :order part info_request_events.created_at is a work around
- # for a very old Rails bug which means eager loading does not respect
- # association orders.
- # http://dev.rubyonrails.org/ticket/3438
- # http://lists.rubyonrails.org/pipermail/rails-core/2006-July/001798.html
- # That that patch has not been applied, despite bribes of beer, is
- # typical of the lack of quality of Rails.
-
- info_requests = InfoRequest.find(:all,
- :conditions => [
- "info_requests.id in (
- select info_request_id
- from info_request_events
- where event_type = 'comment'
- and created_at > (now() - '1 month'::interval)
- )"
- ],
- :include => [ { :info_request_events => :user_info_request_sent_alerts } ],
- :order => "info_requests.id, info_request_events.created_at"
- )
- for info_request in info_requests
-
- next if info_request.is_external?
- # Count number of new comments to alert on
- earliest_unalerted_comment_event = nil
- last_comment_event = nil
- count = 0
- for e in info_request.info_request_events.reverse
- # alert on comments, which were not made by the user who originally made the request
- if e.event_type == 'comment' && e.comment.user_id != info_request.user_id
- last_comment_event = e if last_comment_event.nil?
-
- alerted_for = e.user_info_request_sent_alerts.find(:first, :conditions => [ "alert_type = 'comment_1' and user_id = ?", info_request.user_id])
- if alerted_for.nil?
- count = count + 1
- earliest_unalerted_comment_event = e
- else
- break
- end
- end
- end
-
- # Alert needs sending if there are new comments
- if count > 0
- store_sent = UserInfoRequestSentAlert.new
- store_sent.info_request = info_request
- store_sent.user = info_request.user
- store_sent.alert_type = 'comment_1'
- store_sent.info_request_event_id = last_comment_event.id
- if count > 1
- RequestMailer.deliver_comment_on_alert_plural(info_request, count, earliest_unalerted_comment_event.comment)
- elsif count == 1
- RequestMailer.deliver_comment_on_alert(info_request, last_comment_event.comment)
- else
- raise "internal error"
- end
- store_sent.save!
- end
- end
- end
-
-
-end
-
-
diff --git a/app/models/track_mailer.rb b/app/models/track_mailer.rb
deleted file mode 100644
index 7262c82f3..000000000
--- a/app/models/track_mailer.rb
+++ /dev/null
@@ -1,134 +0,0 @@
-# models/track_mailer.rb:
-# Emails which go to users who are tracking things.
-#
-# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-class TrackMailer < ApplicationMailer
- def event_digest(user, email_about_things)
- post_redirect = PostRedirect.new(
- :uri => user_url(user) + "#email_subscriptions",
- :user_id => user.id)
- post_redirect.save!
- unsubscribe_url = confirm_url(:email_token => post_redirect.email_token)
-
- @from = contact_from_name_and_email
- headers 'Auto-Submitted' => 'auto-generated', # http://tools.ietf.org/html/rfc3834
- 'Precedence' => 'bulk' # http://www.vbulletin.com/forum/project.php?issueid=27687 (Exchange hack)
- # 'Return-Path' => blackhole_email, 'Reply-To' => @from # we don't care about bounces for tracks
- # (We let it return bounces for now, so we can manually kill the tracks that bounce so Yahoo
- # etc. don't decide we are spammers.)
-
- @recipients = user.name_and_email
- @subject = _("Your {{site_name}} email alert", :site_name => site_name)
- @body = { :user => user, :email_about_things => email_about_things, :unsubscribe_url => unsubscribe_url }
- end
-
- def contact_from_name_and_email
- "#{Configuration::track_sender_name} <#{Configuration::track_sender_email}>"
- end
-
- # Send email alerts for tracked things. Never more than one email
- # a day, nor about events which are more than a week old, nor
- # events about which emails have been sent within the last two
- # weeks.
-
- # Useful query to run by hand to see how many alerts are due:
- # User.find(:all, :conditions => [ "last_daily_track_email < ?", Time.now - 1.day ]).size
- def self.alert_tracks
- done_something = false
- now = Time.now()
- users = User.find(:all, :conditions => [ "last_daily_track_email < ?", now - 1.day ])
- if users.empty?
- return done_something
- end
- for user in users
- next if !user.should_be_emailed? || !user.receive_email_alerts
-
- email_about_things = []
- track_things = TrackThing.find(:all, :conditions => [ "tracking_user_id = ? and track_medium = ?", user.id, 'email_daily' ])
- for track_thing in track_things
- # What have we alerted on already?
- #
- # We only use track_things_sent_emails records which are less than 14 days old.
- # In the search query loop below, we also only use items described in last 7 days.
- # An item described that recently definitely can't appear in track_things_sent_emails
- # earlier, so this is safe (with a week long margin of error). If the alerts break
- # for a whole week, then they will miss some items. Tough.
- done_info_request_events = {}
- tt_sent = track_thing.track_things_sent_emails.find(:all, :conditions => ['created_at > ?', now - 14.days])
- for t in tt_sent
- if not t.info_request_event_id.nil?
- done_info_request_events[t.info_request_event_id] = 1
- end
- end
-
- # Query for things in this track. We use described_at for the
- # ordering, so we catch anything new (before described), or
- # anything whose new status has been described.
- xapian_object = InfoRequest.full_search([InfoRequestEvent], track_thing.track_query, 'described_at', true, nil, 100, 1)
- # Go through looking for unalerted things
- alert_results = []
- for result in xapian_object.results
- if result[:model].class.to_s != "InfoRequestEvent"
- raise "need to add other types to TrackMailer.alert_tracks (unalerted)"
- end
-
- next if track_thing.created_at >= result[:model].described_at # made before the track was created
- next if result[:model].described_at < now - 7.days # older than 1 week (see 14 days / 7 days in comment above)
- next if done_info_request_events.include?(result[:model].id) # definitely already done
-
- # OK alert this one
- alert_results.push(result)
- end
- # If there were more alerts for this track, then store them
- if alert_results.size > 0
- email_about_things.push([track_thing, alert_results, xapian_object])
- end
- end
-
- # If we have anything to send, then send everything for the user in one mail
- if email_about_things.size > 0
- # Send the email
-
- I18n.with_locale(user.get_locale) do
- TrackMailer.deliver_event_digest(user, email_about_things)
- end
- end
-
- # Record that we've now sent those alerts to that user
- for track_thing, alert_results in email_about_things
- for result in alert_results
- track_things_sent_email = TrackThingsSentEmail.new
- track_things_sent_email.track_thing_id = track_thing.id
- if result[:model].class.to_s == "InfoRequestEvent"
- track_things_sent_email.info_request_event_id = result[:model].id
- else
- raise "need to add other types to TrackMailer.alert_tracks (mark alerted)"
- end
- track_things_sent_email.save!
- end
- end
- user.last_daily_track_email = now
- user.no_xapian_reindex = true
- user.save!
- done_something = true
- end
- return done_something
- end
-
- def self.alert_tracks_loop
- # Run alert_tracks in an endless loop, sleeping when there is nothing to do
- while true
- sleep_seconds = 1
- while !alert_tracks
- sleep sleep_seconds
- sleep_seconds *= 2
- sleep_seconds = 300 if sleep_seconds > 300
- end
- end
- end
-
-end
-
-
diff --git a/app/models/track_thing.rb b/app/models/track_thing.rb
index a0c74bdb6..66b8a5c47 100644
--- a/app/models/track_thing.rb
+++ b/app/models/track_thing.rb
@@ -19,7 +19,7 @@
# When somebody is getting alerts for something.
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
require 'set'
@@ -260,7 +260,7 @@ class TrackThing < ActiveRecord::Base
:title_in_email => self.public_body.law_only_short + " requests to '" + self.public_body.name + "'",
:title_in_rss => self.public_body.law_only_short + " requests to '" + self.public_body.name + "'",
# Authentication
- :web => _("To follow requests made using {{site_name}} to the public authority '{{public_body_name}}'", :site_name=>Configuration::site_name, :public_body_name=>CGI.escapeHTML(self.public_body.name)),
+ :web => _("To follow requests made using {{site_name}} to the public authority '{{public_body_name}}'", :site_name=>AlaveteliConfiguration::site_name, :public_body_name=>CGI.escapeHTML(self.public_body.name)),
:email => _("Then you will be notified whenever someone requests something or gets a response from '{{public_body_name}}'.", :public_body_name=>CGI.escapeHTML(self.public_body.name)),
:email_subject => _("Confirm you want to follow requests to '{{public_body_name}}'", :public_body_name=>self.public_body.name),
# RSS sorting
diff --git a/app/models/track_things_sent_email.rb b/app/models/track_things_sent_email.rb
index a0a4c0f0c..a9ea2520e 100644
--- a/app/models/track_things_sent_email.rb
+++ b/app/models/track_things_sent_email.rb
@@ -16,7 +16,7 @@
# Record that alert has arrived.
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class TrackThingsSentEmail < ActiveRecord::Base
belongs_to :info_request_event
diff --git a/app/models/user.rb b/app/models/user.rb
index 37edbe360..306d6ad4a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -58,6 +58,9 @@ class User < ActiveRecord::Base
],
:terms => [ [ :variety, 'V', "variety" ] ],
:if => :indexed_by_search?
+
+ after_initialize :set_defaults
+
def created_at_numeric
# format it here as no datetime support in Xapian's value ranges
return self.created_at.strftime("%Y%m%d%H%M%S")
@@ -67,17 +70,6 @@ class User < ActiveRecord::Base
"user"
end
- def after_initialize
- if self.admin_level.nil?
- self.admin_level = 'none'
- end
- if self.new_record?
- # make alert emails go out at a random time for each new user, so
- # overall they are spread out throughout the day.
- self.last_daily_track_email = User.random_time_in_last_day
- end
- end
-
# requested_by: and commented_by: search queries also need updating after save
after_update :reindex_referencing_models
def reindex_referencing_models
@@ -138,14 +130,14 @@ class User < ActiveRecord::Base
if user
# There is user with email, check password
if !user.has_this_password?(params[:password])
- user.errors.add_to_base(auth_fail_message)
+ user.errors.add(:base, auth_fail_message)
end
else
# No user of same email, make one (that we don't save in the database)
# for the forms code to use.
user = User.new(params)
# deliberately same message as above so as not to leak whether registered
- user.errors.add_to_base(auth_fail_message)
+ user.errors.add(:base, auth_fail_message)
end
user
end
@@ -198,12 +190,12 @@ class User < ActiveRecord::Base
# The "internal admin" is a special user for internal use.
def User.internal_admin_user
- u = User.find_by_email(Configuration::contact_email)
+ u = User.find_by_email(AlaveteliConfiguration::contact_email)
if u.nil?
password = PostRedirect.generate_random_token
u = User.new(
:name => 'Internal admin user',
- :email => Configuration::contact_email,
+ :email => AlaveteliConfiguration::contact_email,
:password => password,
:password_confirmation => password
)
@@ -276,16 +268,16 @@ class User < ActiveRecord::Base
return false if self.no_limit
# Has the user issued as many as MAX_REQUESTS_PER_USER_PER_DAY requests in the past 24 hours?
- return false if Configuration::max_requests_per_user_per_day.blank?
+ return false if AlaveteliConfiguration::max_requests_per_user_per_day.blank?
recent_requests = InfoRequest.count(:conditions => ["user_id = ? and created_at > now() - '1 day'::interval", self.id])
- return (recent_requests >= Configuration::max_requests_per_user_per_day)
+ return (recent_requests >= AlaveteliConfiguration::max_requests_per_user_per_day)
end
def next_request_permitted_at
return nil if self.no_limit
- n_most_recent_requests = InfoRequest.all(:conditions => ["user_id = ? and created_at > now() - '1 day'::interval", self.id], :order => "created_at DESC", :limit => Configuration::max_requests_per_user_per_day)
- return nil if n_most_recent_requests.size < Configuration::max_requests_per_user_per_day
+ n_most_recent_requests = InfoRequest.all(:conditions => ["user_id = ? and created_at > now() - '1 day'::interval", self.id], :order => "created_at DESC", :limit => AlaveteliConfiguration::max_requests_per_user_per_day)
+ return nil if n_most_recent_requests.size < AlaveteliConfiguration::max_requests_per_user_per_day
nth_most_recent_request = n_most_recent_requests[-1]
return nth_most_recent_request.created_at + 1.day
@@ -404,6 +396,17 @@ class User < ActiveRecord::Base
self.salt = self.object_id.to_s + rand.to_s
end
+ def set_defaults
+ if self.admin_level.nil?
+ self.admin_level = 'none'
+ end
+ if self.new_record?
+ # make alert emails go out at a random time for each new user, so
+ # overall they are spread out throughout the day.
+ self.last_daily_track_email = User.random_time_in_last_day
+ end
+ end
+
def email_and_name_are_valid
if self.email != "" && !MySociety::Validate.is_valid_email(self.email)
errors.add(:email, _("Please enter a valid email address"))
diff --git a/app/models/user_info_request_sent_alert.rb b/app/models/user_info_request_sent_alert.rb
index cf20bcbf5..449a4c237 100644
--- a/app/models/user_info_request_sent_alert.rb
+++ b/app/models/user_info_request_sent_alert.rb
@@ -15,7 +15,7 @@
# given type of alert.
#
# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class UserInfoRequestSentAlert < ActiveRecord::Base
belongs_to :user
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
deleted file mode 100644
index 1be4f8aa3..000000000
--- a/app/models/user_mailer.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# models/user_mailer.rb:
-# Emails relating to user accounts. e.g. Confirming a new account
-#
-# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
-# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
-
-class UserMailer < ApplicationMailer
- def confirm_login(user, reasons, url)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from # we don't care about bounces when people are fiddling with their account
- @recipients = user.name_and_email
- @subject = reasons[:email_subject]
- @body[:reasons] = reasons
- @body[:name] = user.name
- @body[:url] = url
- end
-
- def already_registered(user, reasons, url)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from # we don't care about bounces when people are fiddling with their account
- @recipients = user.name_and_email
- @subject = reasons[:email_subject]
- @body[:reasons] = reasons
- @body[:name] = user.name
- @body[:url] = url
- end
-
- def changeemail_confirm(user, new_email, url)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from # we don't care about bounces when people are fiddling with their account
- @recipients = new_email
- @subject = _("Confirm your new email address on {{site_name}}", :site_name=>site_name)
- @body[:name] = user.name
- @body[:url] = url
- @body[:old_email] = user.email
- @body[:new_email] = new_email
- end
-
- def changeemail_already_used(old_email, new_email)
- @from = contact_from_name_and_email
- headers 'Return-Path' => blackhole_email, 'Reply-To' => @from # we don't care about bounces when people are fiddling with their account
- @recipients = new_email
- @subject = _("Unable to change email address on {{site_name}}", :site_name=>site_name)
- @body[:old_email] = old_email
- @body[:new_email] = new_email
- end
-end
-