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/comment.rb2
-rw-r--r--app/models/contact_mailer.rb2
-rw-r--r--app/models/incoming_message.rb6
-rw-r--r--app/models/info_request.rb66
-rw-r--r--app/models/outgoing_message.rb19
-rw-r--r--app/models/post_redirect.rb26
-rw-r--r--app/models/profile_photo.rb43
-rw-r--r--app/models/public_body.rb27
-rw-r--r--app/models/request_mailer.rb14
-rw-r--r--app/models/track_thing.rb4
-rw-r--r--app/models/user.rb49
13 files changed, 160 insertions, 123 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/comment.rb b/app/models/comment.rb
index 5507910e2..bcd1efca8 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -68,7 +68,7 @@ class Comment < ActiveRecord::Base
text = CGI.escapeHTML(text)
text = MySociety::Format.make_clickable(text, :contract => 1)
text = text.gsub(/\n/, '<br>')
- return text
+ return text.html_safe
end
# When posting a new comment, use this to check user hasn't double submitted.
diff --git a/app/models/contact_mailer.rb b/app/models/contact_mailer.rb
index 16aae2f15..abde64928 100644
--- a/app/models/contact_mailer.rb
+++ b/app/models/contact_mailer.rb
@@ -7,7 +7,7 @@
class ContactMailer < ApplicationMailer
# Send message to administrator
- def message(name, email, subject, message, logged_in_user, last_request, last_body)
+ 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
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index 339a7a3e2..f70b8c0cb 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
@@ -695,7 +695,7 @@ class IncomingMessage < ActiveRecord::Base
text = text.gsub(/\n/, '<br>')
text = text.gsub(/(?:<br>\s*){2,}/, '<br><br>') # remove excess linebreaks that unnecessarily space it out
- return text
+ return text.html_safe
end
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 3355b9443..3ee1c3c08 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
@@ -284,9 +265,9 @@ public
# into some sort of separate jurisdiction dependent file
if self.public_body.url_name == 'general_register_office'
# without GQ in the subject, you just get an auto response
- _('{{law_used_full}} request GQ - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title)
+ _('{{law_used_full}} request GQ - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title.html_safe)
else
- _('{{law_used_full}} request - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title)
+ _('{{law_used_full}} request - {{title}}',:law_used_full=>self.law_used_full,:title=>self.title.html_safe)
end
end
def email_subject_followup(incoming_message = nil)
@@ -1155,5 +1136,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 2e98e1021..23b5c904b 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -50,6 +50,8 @@ class OutgoingMessage < ActiveRecord::Base
end
end
+ after_initialize :set_default_letter
+
# How the default letter starts and ends
def get_salutation
ret = ""
@@ -129,13 +131,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
-
# Check have edited letter
def validate
if self.body.empty? || self.body =~ /\A#{get_salutation}\s+#{get_signoff}/ || self.body =~ /#{get_internal_review_insert_here_note}/
@@ -252,7 +247,7 @@ class OutgoingMessage < ActiveRecord::Base
text = MySociety::Format.make_clickable(text, :contract => 1)
text.gsub!(/\[(email address|mobile number)\]/, '[<a href="/help/officers#mobiles">\1</a>]')
text = text.gsub(/\n/, '<br>')
- return text
+ return text.html_safe
end
def fully_destroy
@@ -275,6 +270,14 @@ class OutgoingMessage < ActiveRecord::Base
yield(column.human_name, self.send(column.name), column.type.to_s, column.name)
end
end
+
+ private
+
+ def set_default_letter
+ if self.body.nil?
+ self.body = get_default_message
+ end
+ end
end
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 6e605651d..41cb298b3 100644
--- a/app/models/profile_photo.rb
+++ b/app/models/profile_photo.rb
@@ -23,29 +23,15 @@ class ProfilePhoto < ActiveRecord::Base
belongs_to :user
+ validate :data_and_draft_checks
+
# deliberately don't strip_attributes, so keeps raw photo properly
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
@@ -81,7 +67,9 @@ class ProfilePhoto < ActiveRecord::Base
end
end
- def validate
+ private
+
+ def data_and_draft_checks
if self.data.nil?
errors.add(:data, N_("Please choose a file containing your photo."))
return
@@ -108,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 d59651a87..27fbb1470 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -35,6 +35,8 @@ class PublicBody < ActiveRecord::Base
validates_uniqueness_of :short_name, :message => N_("Short name is already taken"), :if => Proc.new { |pb| pb.short_name != "" }
validates_uniqueness_of :name, :message => N_("Name is already taken")
+ validate :validate_request_email_if_requestable
+
has_many :info_requests, :order => 'created_at desc'
has_many :track_things, :order => 'created_at desc'
has_many :censor_rules, :order => 'created_at desc'
@@ -43,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}"
}
@@ -52,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
@@ -132,15 +134,6 @@ class PublicBody < ActiveRecord::Base
self.first_letter = self.name.scan(/./mu)[0].upcase
end
- def validate
- # Request_email can be blank, meaning we don't have details
- if self.is_requestable?
- unless MySociety::Validate.is_valid_email(self.request_email)
- errors.add(:request_email, "Request email doesn't look like a valid email address")
- end
- end
- end
-
# If tagged "not_apply", then FOI/EIR no longer applies to authority at all
def not_apply?
return self.has_tag?('not_apply')
@@ -298,7 +291,7 @@ class PublicBody < ActiveRecord::Base
ret = ret + " and "
end
ret = ret + types[-1]
- return ret
+ return ret.html_safe
else
return _("A public authority")
end
@@ -639,4 +632,14 @@ class PublicBody < ActiveRecord::Base
end
end
+ private
+
+ def validate_request_email_if_requestable
+ # Request_email can be blank, meaning we don't have details
+ if self.is_requestable?
+ unless MySociety::Validate.is_valid_email(self.request_email)
+ errors.add(:request_email, "Request email doesn't look like a valid email address")
+ end
+ end
+ end
end
diff --git a/app/models/request_mailer.rb b/app/models/request_mailer.rb
index 493d6961c..f07e3c3d8 100644
--- a/app/models/request_mailer.rb
+++ b/app/models/request_mailer.rb
@@ -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_thing.rb b/app/models/track_thing.rb
index 2a61eb858..81800f0ae 100644
--- a/app/models/track_thing.rb
+++ b/app/models/track_thing.rb
@@ -203,7 +203,7 @@ class TrackThing < ActiveRecord::Base
:verb_on_page => _("Follow this request"),
:verb_on_page_already => _("You are already following this request"),
# Email
- :title_in_email => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title),
+ :title_in_email => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title.html_safe),
:title_in_rss => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title),
# Authentication
:web => _("To follow the request '{{request_title}}'", :request_title => CGI.escapeHTML(self.info_request.title)),
@@ -270,7 +270,7 @@ class TrackThing < ActiveRecord::Base
:verb_on_page => _("Follow this person"),
:verb_on_page_already => _("You are already following this person"),
# Email
- :title_in_email => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name),
+ :title_in_email => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name.html_safe),
:title_in_rss => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name),
# Authentication
:web => _("To follow requests by '{{user_name}}'", :user_name=>CGI.escapeHTML(self.tracked_user.name)),
diff --git a/app/models/user.rb b/app/models/user.rb
index 773e6db9d..bc04b5449 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -50,12 +50,17 @@ class User < ActiveRecord::Base
'super',
], :message => N_('Admin level is not included in list')
+ validate :email_and_name_are_valid
+
acts_as_xapian :texts => [ :name, :about_me ],
:values => [
[ :created_at_numeric, 1, "created_at", :number ] # for sorting
],
: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")
@@ -65,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
@@ -103,15 +97,6 @@ class User < ActiveRecord::Base
self.comments.find(:all, :conditions => 'visible')
end
- def validate
- if self.email != "" && !MySociety::Validate.is_valid_email(self.email)
- errors.add(:email, _("Please enter a valid email address"))
- end
- if MySociety::Validate.is_valid_email(self.name)
- errors.add(:name, _("Please enter your name, not your email address, in the name field."))
- end
- end
-
# Don't display any leading/trailing spaces
# XXX we have strip_attributes! now, so perhaps this can be removed (might
# be still needed for existing cases)
@@ -143,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
@@ -408,6 +393,26 @@ 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"))
+ end
+ if MySociety::Validate.is_valid_email(self.name)
+ errors.add(:name, _("Please enter your name, not your email address, in the name field."))
+ end
+ end
+
## Class methods
def User.encrypted_password(password, salt)
string_to_hash = password + salt # XXX need to add a secret here too?