aboutsummaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/application_mailer.rb15
-rw-r--r--app/models/censor_rule.rb10
-rw-r--r--app/models/change_email_validator.rb4
-rw-r--r--app/models/incoming_message.rb4
-rw-r--r--app/models/info_request.rb70
-rw-r--r--app/models/outgoing_message.rb15
-rw-r--r--app/models/post_redirect.rb26
-rw-r--r--app/models/profile_photo.rb37
-rw-r--r--app/models/public_body.rb61
-rw-r--r--app/models/request_mailer.rb34
-rw-r--r--app/models/track_mailer.rb7
-rw-r--r--app/models/user.rb36
12 files changed, 173 insertions, 146 deletions
diff --git a/app/models/application_mailer.rb b/app/models/application_mailer.rb
index cdb279c3c..84b045795 100644
--- a/app/models/application_mailer.rb
+++ b/app/models/application_mailer.rb
@@ -30,9 +30,11 @@ class ApplicationMailer < ActionMailer::Base
# 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
+
+ # TEMPORARY: commented out method below while upgrading to Rails 3
+ #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
@@ -67,6 +69,7 @@ class ApplicationMailer < ActionMailer::Base
return nil
end
+ # FIXME: This check was disabled temporarily during the Rails 3 upgrade
if ActionMailer::VERSION::MAJOR == 2
# This method is a customised version of ActionMailer::Base.create!
@@ -142,9 +145,9 @@ class ApplicationMailer < ActionMailer::Base
# 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
+ 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..ec66074b7 100644
--- a/app/models/censor_rule.rb
+++ b/app/models/censor_rule.rb
@@ -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..37eb3c176 100644
--- a/app/models/change_email_validator.rb
+++ b/app/models/change_email_validator.rb
@@ -41,11 +41,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
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index 5c845ead3..229d3bf24 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -605,7 +605,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,7 +632,7 @@ 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])
+ attachment = self.foi_attachments.find_or_create_by_hexdigest(attrs[:hexdigest])
body = attrs.delete(:body)
attachment.update_attributes(attrs)
# Set the body separately as its handling can depend on the value of charset
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index cee9eb959..9d8fc29fd 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',
@@ -156,31 +160,8 @@ class InfoRequest < ActiveRecord::Base
rescue MissingSourceFile, NameError
end
- # only check on create, so existing models with mixed case are allowed
- def validate_on_create
- 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
-
OLD_AGE_IN_DAYS = 21.days
- def after_initialize
- if self.described_state.nil?
- self.described_state = 'waiting_response'
- end
- # FOI or EIR?
- if !self.public_body.nil? && self.public_body.eir_only?
- self.law_used = 'eir'
- end
- end
-
def visible_comments
self.comments.find(:all, :conditions => 'visible')
end
@@ -424,6 +405,14 @@ public
# A new incoming email to this request
def receive(email, raw_email_data, override_stop_new_responses = false, rejected_reason = "")
+ # Just adding a bit of extra error checking just to save a lot of deep chasing of
+ # strangeness.
+ # TODO: Remove this when we don't use the TMail backend anymore for anything
+ if (MailHandler.backend == "TMail" && !email.kind_of?(TMail::Mail)) ||
+ (MailHandler.backend == "Mail" && !email.kind_of?(Mail::Message))
+ raise "Wrong kind of mail object passed in receive"
+ end
+
if !override_stop_new_responses
allow = nil
reason = nil
@@ -1155,5 +1144,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/outgoing_message.rb b/app/models/outgoing_message.rb
index c75894e6a..0c358a7c8 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -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 = ""
@@ -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
@@ -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..dfca936e2 100644
--- a/app/models/post_redirect.rb
+++ b/app/models/post_redirect.rb
@@ -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 73d7ca12b..41cb298b3 100644
--- a/app/models/profile_photo.rb
+++ b/app/models/profile_photo.rb
@@ -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 168b9f4c7..a06e0d253 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!
@@ -106,28 +106,25 @@ class PublicBody < ActiveRecord::Base
# like find_by_url_name but also search historic url_name if none found
def self.find_by_url_name_with_historic(name)
- locale = self.locale || I18n.locale
- PublicBody.with_locale(locale) do
- found = PublicBody.find(:all,
- :conditions => ["public_body_translations.url_name=?", name],
- :joins => :translations,
- :readonly => false)
- # If many bodies are found (usually because the url_name is the same across
- # locales) return any of them
- return found.first if found.size >= 1
-
- # If none found, then search the history of short names
- old = PublicBody::Version.find_all_by_url_name(name)
- # Find unique public bodies in it
- old = old.map { |x| x.public_body_id }
- old = old.uniq
- # Maybe return the first one, so we show something relevant,
- # rather than throwing an error?
- raise "Two bodies with the same historical URL name: #{name}" if old.size > 1
- return unless old.size == 1
- # does acts_as_versioned provide a method that returns the current version?
- return PublicBody.find(old.first)
- end
+ found = PublicBody.find(:all,
+ :conditions => ["public_body_translations.url_name=?", name],
+ :joins => :translations,
+ :readonly => false)
+ # If many bodies are found (usually because the url_name is the same across
+ # locales) return any of them
+ return found.first if found.size >= 1
+
+ # If none found, then search the history of short names
+ old = PublicBody::Version.find_all_by_url_name(name)
+ # Find unique public bodies in it
+ old = old.map { |x| x.public_body_id }
+ old = old.uniq
+ # Maybe return the first one, so we show something relevant,
+ # rather than throwing an error?
+ raise "Two bodies with the same historical URL name: #{name}" if old.size > 1
+ return unless old.size == 1
+ # does acts_as_versioned provide a method that returns the current version?
+ return PublicBody.find(old.first)
end
# Set the first letter, which is used for faster queries
@@ -243,13 +240,13 @@ class PublicBody < ActiveRecord::Base
# When name or short name is changed, also change the url name
def short_name=(short_name)
- globalize.write(self.class.locale || I18n.locale, :short_name, short_name)
+ globalize.write(I18n.locale, :short_name, short_name)
self[:short_name] = short_name
self.update_url_name
end
def name=(name)
- globalize.write(self.class.locale || I18n.locale, :name, name)
+ globalize.write(I18n.locale, :name, name)
self[:name] = name
self.update_url_name
end
@@ -329,7 +326,7 @@ class PublicBody < ActiveRecord::Base
# The "internal admin" is a special body for internal use.
def PublicBody.internal_admin_body
- PublicBody.with_locale(I18n.default_locale) do
+ I18n.with_locale(I18n.default_locale) do
pb = PublicBody.find_by_url_name("internal_admin_authority")
if pb.nil?
pb = PublicBody.new(
@@ -367,7 +364,7 @@ class PublicBody < ActiveRecord::Base
# of updating them
bodies_by_name = {}
set_of_existing = Set.new()
- PublicBody.with_locale(I18n.default_locale) do
+ I18n.with_locale(I18n.default_locale) do
bodies = (tag.nil? || tag.empty?) ? PublicBody.find(:all) : PublicBody.find_by_tag(tag)
for existing_body in bodies
# Hide InternalAdminBody from import notes
@@ -410,7 +407,7 @@ class PublicBody < ActiveRecord::Base
if public_body = bodies_by_name[name] # Existing public body
available_locales.each do |locale|
- PublicBody.with_locale(locale) do
+ I18n.with_locale(locale) do
changed = ActiveSupport::OrderedHash.new
field_list.each do |field_name|
localized_field_name = (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}"
@@ -445,7 +442,7 @@ class PublicBody < ActiveRecord::Base
else # New public body
public_body = PublicBody.new(:name=>"", :short_name=>"", :request_email=>"")
available_locales.each do |locale|
- PublicBody.with_locale(locale) do
+ I18n.with_locale(locale) do
changed = ActiveSupport::OrderedHash.new
field_list.each do |field_name|
localized_field_name = (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}"
@@ -635,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/request_mailer.rb b/app/models/request_mailer.rb
index 493d6961c..116a9fe81 100644
--- a/app/models/request_mailer.rb
+++ b/app/models/request_mailer.rb
@@ -44,17 +44,17 @@ class RequestMailer < ApplicationMailer
# 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
+ headers 'Return-Path' => blackhole_email, # 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
- }
+
+ attachments.inline["original.eml"] = raw_email_data
+
+ @info_request = info_request
+ @contact_email = Configuration::contact_email
+
+ mail(:from => contact_from_name_and_email, :to => email.from_addrs[0].to_s,
+ :reply_to => contact_from_name_and_email,
+ :subject => _("Your response to an FOI request was not delivered"))
end
# An FOI response is outside the scope of the system, and needs admin attention
@@ -76,15 +76,17 @@ 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 = main_url(incoming_message_url(incoming_message))
+ @url = main_url(incoming_message_url(incoming_message))
+ @incoming_message, @info_request = incoming_message, 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
+ headers 'Return-Path' => blackhole_email,
'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
- @body = { :incoming_message => incoming_message, :info_request => info_request, :url => url }
+ mail(:from => contact_from_name_and_email, :to => info_request.user.name_and_email,
+ :subject => _("New response to your FOI request - ") + info_request.title,
+ :charset => "UTF-8",
+ # not much we can do if the user's email is broken
+ :reply_to => contact_from_name_and_email)
end
# Tell the requester that the public body is late in replying
diff --git a/app/models/track_mailer.rb b/app/models/track_mailer.rb
index 7dfa87f52..03310478a 100644
--- a/app/models/track_mailer.rb
+++ b/app/models/track_mailer.rb
@@ -91,10 +91,9 @@ class TrackMailer < ApplicationMailer
if email_about_things.size > 0
# Send the email
- previous_locale = I18n.locale
- I18n.locale = user.get_locale
- TrackMailer.deliver_event_digest(user, email_about_things)
- I18n.locale = previous_locale
+ 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
diff --git a/app/models/user.rb b/app/models/user.rb
index e6c666e47..d16a9452a 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
@@ -98,12 +90,7 @@ class User < ActiveRecord::Base
end
def get_locale
- if !self.locale.nil?
- locale = self.locale
- else
- locale = I18n.locale
- end
- return locale.to_s
+ (self.locale || I18n.locale).to_s
end
def visible_comments
@@ -141,14 +128,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
@@ -407,6 +394,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"))