aboutsummaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/foi_attachment.rb7
-rw-r--r--app/models/incoming_message.rb53
-rw-r--r--app/models/info_request.rb83
-rw-r--r--app/models/outgoing_message.rb22
4 files changed, 77 insertions, 88 deletions
diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb
index fcde379e0..0340f2b83 100644
--- a/app/models/foi_attachment.rb
+++ b/app/models/foi_attachment.rb
@@ -71,7 +71,12 @@ class FoiAttachment < ActiveRecord::Base
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
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index c914edb7e..f959a8799 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -31,12 +31,9 @@
# 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
@@ -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
@@ -556,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
@@ -592,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
@@ -645,12 +660,16 @@ class IncomingMessage < ActiveRecord::Base
attachment = self.foi_attachments.find_or_create_by_hexdigest(attrs[:hexdigest])
attachment.update_attributes(attrs)
attachment.save!
- attachments << attachment.id
+ attachments << attachment
end
+
# Reload to refresh newly created foi_attachments
self.reload
- main_part = get_main_body_text_part
+ # 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
@@ -661,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.
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index cf1af0e87..aaf171c4c 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -108,6 +108,12 @@ class InfoRequest < ActiveRecord::Base
states
end
+ # Possible reasons that a request could be reported for administrator attention
+ def report_reasons
+ ["Contains defamatory material", "Not a valid request", "Request for personal information",
+ "Contains personal information", "Vexatious", "Other"]
+ end
+
def must_be_valid_state
errors.add(:described_state, "is not a valid state") if
!InfoRequest.enumerate_states.include? described_state
@@ -189,21 +195,6 @@ class InfoRequest < ActiveRecord::Base
self.comments.find(:all, :conditions => 'visible')
end
- # Central function to do all searches
- # (Not really the right place to put it, but everything can get it here, and it
- # does *mainly* find info requests, via their events, so hey)
- def InfoRequest.full_search(models, query, order, ascending, collapse, per_page, page)
- offset = (page - 1) * per_page
-
- return ::ActsAsXapian::Search.new(
- models, query,
- :offset => offset, :limit => per_page,
- :sort_by_prefix => order,
- :sort_by_ascending => ascending,
- :collapse_by_prefix => collapse
- )
- end
-
# If the URL name has changed, then all request: queries will break unless
# we update index for every event. Also reindex if prominence changes.
after_update :reindex_some_request_events
@@ -232,17 +223,6 @@ class InfoRequest < ActiveRecord::Base
end
end
- # For debugging
- def InfoRequest.profile_search(query)
- t = Time.now.usec
- for i in (1..10)
- t = Time.now.usec - t
- secs = t / 1000000.0
- STDOUT.write secs.to_s + " query " + i.to_s + "\n"
- results = InfoRequest.full_search([InfoRequestEvent], query, "created_at", true, nil, 25, 1).results
- end
- end
-
public
# When name is changed, also change the url name
def title=(title)
@@ -351,7 +331,10 @@ public
# copying an email, and that doesn't matter)
def InfoRequest.find_by_incoming_email(incoming_email)
id, hash = InfoRequest._extract_id_hash_from_email(incoming_email)
- return self.find_by_magic_email(id, hash)
+ if hash_from_id(id) == hash
+ # Not using find(id) because we don't exception raised if nothing found
+ find_by_id(id)
+ end
end
# Return list of info requests which *might* be right given email address
@@ -566,6 +549,15 @@ public
['requires_admin', 'error_message', 'attention_requested'].include?(described_state)
end
+ # Report this request for administrator attention
+ def report!(reason, message, user)
+ ActiveRecord::Base.transaction do
+ set_described_state('attention_requested', user, "Reason: #{reason}\n\n#{message}")
+ self.attention_requested = true # tells us if attention has ever been requested
+ save!
+ end
+ end
+
# change status, including for last event for later historical purposes
def set_described_state(new_state, set_by = nil, message = "")
old_described_state = described_state
@@ -913,24 +905,6 @@ public
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
- # function for envelope from address, until we abandoned it.
- def InfoRequest.find_by_magic_email(id, hash)
- expected_hash = InfoRequest.hash_from_id(id)
- #print "expected: " + expected_hash + "\nhash: " + hash + "\n"
- if hash != expected_hash
- return nil
- else
- begin
- return self.find(id)
- rescue ActiveRecord::RecordNotFound
- # so error email is sent to admin, rather than the exception sending weird
- # error to the public body.
- return nil
- end
- end
- end
-
# Used to find when event last changed
def InfoRequest.last_event_time_clause(event_type=nil)
event_type_clause = ''
@@ -1081,25 +1055,6 @@ public
InfoRequest.update_all "allow_new_responses_from = 'nobody' where updated_at < (now() - interval '1 year') and allow_new_responses_from in ('anybody', 'authority_only') and url_title <> 'holding_pen'"
end
- # Returns a random FOI request
- def InfoRequest.random
- max_id = InfoRequest.connection.select_value('select max(id) as a from info_requests').to_i
- info_request = nil
- count = 0
- while info_request.nil?
- if count > 100
- return nil
- end
- id = rand(max_id) + 1
- begin
- count += 1
- info_request = find(id, :conditions => ["prominence = 'normal'"])
- rescue ActiveRecord::RecordNotFound
- end
- end
- return info_request
- end
-
def json_for_api(deep)
ret = {
:id => self.id,
diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb
index dbe2cf1ca..aedfb9cad 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -23,6 +23,14 @@
# Email: hello@mysociety.org; WWW: http://www.mysociety.org/
class OutgoingMessage < ActiveRecord::Base
+ include Rails.application.routes.url_helpers
+ include LinkToHelper
+ self.default_url_options[:host] = AlaveteliConfiguration::domain
+ # https links in emails if forcing SSL
+ if AlaveteliConfiguration::force_ssl
+ self.default_url_options[:protocol] = "https"
+ end
+
strip_attributes!
belongs_to :info_request
@@ -80,15 +88,15 @@ class OutgoingMessage < ActiveRecord::Base
end
if self.what_doing == 'internal_review'
- "Please pass this on to the person who conducts Freedom of Information reviews." +
+ _("Please pass this on to the person who conducts Freedom of Information reviews.") +
"\n\n" +
- "I am writing to request an internal review of " +
- self.info_request.public_body.name +
- "'s handling of my FOI request " +
- "'" + self.info_request.title + "'." +
+ _("I am writing to request an internal review of {{public_body_name}}'s handling of my FOI request '{{info_request_title}}'.",
+ :public_body_name => self.info_request.public_body.name,
+ :info_request_title => 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://" + AlaveteliConfiguration::domain + "/request/" + self.info_request.url_title
+ _("A full history of my FOI request and all correspondence is available on the Internet at this address: {{url}}",
+ :url => request_url(self.info_request)) +
+ "\n"
else
""
end