Permalink
Browse files

Refactor to account for some Sprint messages having attached files and

rather than being hosted on their CDN.
  • Loading branch information...
1 parent dd48f0a commit 33ff5daa5acd8fea363eef4e5d549097f59c2ee5 @monde committed Jul 4, 2012
Showing with 75 additions and 157 deletions.
  1. +42 −27 lib/mms2r/media.rb
  2. +21 −48 lib/mms2r/media/sprint.rb
  3. +11 −81 test/test_mms2r_media.rb
  4. +1 −0 test/test_mms_myhelio_com.rb
  5. +0 −1 test/test_pm_sprint_com.rb
View
@@ -343,33 +343,16 @@ def default_html
# note: purge must be explicitly called to remove the media files
# mms2r extracts from an mms message.
- def process() # :yields: media_type, file
+ def process # :yields: media_type, file
unless @was_processed
log("#{self.class} processing", :info)
- parts = mail.multipart? ? mail.parts : [mail]
-
- # Double check for multipart/related, if it exists replace it with its
- # children parts. Do this twice as multipart/alternative can have
- # children and we want to fold everything down
- for i in 1..2
- flat = []
- parts.each do |p|
- if p.multipart?
- p.parts.each {|mp| flat << mp }
- else
- flat << p
- end
- end
- parts = flat.dup
- end
-
- # get to work
- parts.each do |p|
- t = p.part_type?
- unless ignore_media?(t,p)
- t,f = process_media(p)
- add_file(t,f) unless t.nil? || f.nil?
+ parts = self.folded_parts(mail)
+ parts.each do |part|
+ if part.part_type? == 'text/html'
+ process_html_part(part)
+ else
+ process_part(part)
end
end
@@ -437,6 +420,25 @@ def process_media(part)
end
##
+ # Helper to decide if a part should be kept or ignored
+
+ def process_part(part)
+ return if ignore_media?(part.part_type?, part)
+
+ type, file = process_media(part)
+ add_file(type, file) unless type.nil? || file.nil?
+ end
+
+ ##
+ # Helper to decide if a html part should be kept or ignored.
+ # We are defining it here primarily for the benefit so that Sprint
+ # can override a special case for processing.
+
+ def process_html_part(part)
+ process_part(part)
+ end
+
+ ##
# Helper for process_media template method to transform text.
# See the transform section in the discussion of the built-in
# configuration.
@@ -490,7 +492,7 @@ def temp_file(part)
# Purges the unique MMS2R::Media.media_dir directory created
# for this producer and all of the media that it contains.
- def purge()
+ def purge
log("#{self.class} purging #{@media_dir} and all its contents", :info)
FileUtils.rm_rf(@media_dir)
end
@@ -507,7 +509,7 @@ def add_file(type, file)
# Helper to temp_file to create a unique temporary directory that is a
# child of tmp_dir This version is based on the message_id of the mail.
- def msg_tmp_dir()
+ def msg_tmp_dir
@dir_count += 1
dir = File.expand_path(File.join(@media_dir, "#{@dir_count}"))
FileUtils.mkdir_p(dir)
@@ -762,7 +764,7 @@ def initialize_config(config)
self.class.initialize_config(config)
end
- private
+ protected
##
# accessor for the config
@@ -781,6 +783,19 @@ def type_from_filename(filename)
end
##
+ # Helper to fold all the parts of multipart mail down into a flat array.
+ # multipart/related and multipart/alternative parts can have child parts.
+ def folded_parts(parts)
+ return folded_parts([parts]) unless parts.respond_to?(:each)
+
+ result = [] # NOTE could use #tap but want 1.8.7 compat
+ parts.each do |part|
+ result << (part.multipart? ? folded_parts(part.parts) : part)
+ end
+ result.flatten
+ end
+
+ ##
# used by #default_media and #text to return the biggest attachment type
# listed in the types array
View
@@ -28,61 +28,34 @@ class Media
module Sprint
- ##
- # Override process() because Sprint doesn't attach media (images, video,
- # etc.) to its MMS. Media such as images and videos are hosted on a
- # Sprint content server. MMS2R::Media::Sprint has to pick apart an
- # HTML attachment to find the URL to the media on Sprint's content
- # server and download each piece of content. Any text message part of
- # the MMS if it exists is embedded in the html.
-
- def process
- unless @was_processed
- log("#{self.class} processing", :info)
- #sprint MMS are multipart
- parts = @mail.parts
-
- #find the payload html
- doc = nil
- parts.each do |p|
- next unless p.part_type? == 'text/html'
- d = Nokogiri(p.body.decoded)
- title = d.at('title').inner_html
- if title =~ /You have new Picture Mail!/
- doc = d
- @is_video = (p.body.decoded =~ /type=&quot;VIDEO&quot;&gt;/m ? true : false)
- end
- end
- return if doc.nil? # it was a dud
- @is_video ||= false
-
- # break it down
- sprint_phone_number(doc)
- sprint_process_text(doc)
- sprint_process_media(doc)
-
- @was_processed = true
- end
-
- # when process acts upon a block
- if block_given?
- media.each do |k, v|
- yield(k, v)
- end
- end
+ protected
+ ##
+ # Helper to process old style media on the Sprint CDN which didn't attach
+ # media (images, video, etc.) to its MMS. Media such as images and
+ # videos are hosted on a Sprint content server. MMS2R::Media::Sprint has
+ # to pick apart an HTML attachment to find the URL to the media on
+ # Sprint's content server and download each piece of content. Any text
+ # message part of the MMS if it exists is embedded in the html.
+
+ def process_html_part(part)
+ doc = Nokogiri(part.body.decoded)
+
+ is_video = (part.body.decoded =~ /type=&quot;VIDEO&quot;&gt;/m ? true : false)
+ sprint_process_media(doc, is_video)
+ sprint_process_text(doc)
+ sprint_phone_number(doc)
end
- private
-
##
# Digs out where Sprint hides the phone number
def sprint_phone_number(doc)
c = doc.search("/html/head/comment()").last
t = c.content.gsub(/\s+/m," ").strip
#@number returned in parent's #number
- @number = / name=&quot;MDN&quot;&gt;(\d+)&lt;/.match(t)[1]
+ matched = / name=&quot;MDN&quot;&gt;(\d+)&lt;/.match(t)
+ @number = matched[1] if matched
end
##
@@ -157,7 +130,7 @@ def sprint_process_text(doc)
##
# Fetch all the media that is referred to in the doc
- def sprint_process_media(doc)
+ def sprint_process_media(doc, is_video=false)
srcs = Array.new
# collect all the images in the document, even though
# they are <img> tag some might actually refer to video.
@@ -183,14 +156,14 @@ def sprint_process_media(doc)
begin
uri = URI.parse(CGI.unescapeHTML(src))
- unless @is_video
+ unless is_video
query={}
uri.query.split('&').each{|a| p=a.split('='); query[p[0]] = p[1]}
query.delete_if{|k, v| k == 'limitsize' || k == 'squareoutput' }
uri.query = query.map{|k,v| "#{k}=#{v}"}.join("&")
end
# sprint is a ghetto, they expect to see &amp; for video request
- uri.query = uri.query.gsub(/&/, "&amp;") if @is_video
+ uri.query = uri.query.gsub(/&/, "&amp;") if is_video
connection = Net::HTTP.new(uri.host, uri.port)
#connection.set_debug_output $stdout
View
@@ -311,18 +311,10 @@ def test_type_from_filename_should_be_nil
def test_attachment_should_return_duck_typed_file
mms = MMS2R::Media.new stub_mail
- temp_big = temp_text_file("hello world")
- size = File.size(temp_text_file("hello world"))
- temp_small = temp_text_file("hello")
- mms.stubs(:media).returns({'text/plain' => [temp_small, temp_big]})
duck_file = mms.send(:attachment, ['text'])
- assert_not_nil duck_file
- assert_equal true, File::exist?(duck_file)
- assert_equal true, File::exist?(temp_big)
- assert_equal temp_big, duck_file.local_path
- assert_equal File.basename(temp_big), duck_file.original_filename
- assert_equal size, duck_file.size
+ assert_equal 1, duck_file.size
assert_equal 'text/plain', duck_file.content_type
+ assert_equal "a", open(mms.media['text/plain'].first).read
end
def test_empty_body
@@ -632,86 +624,24 @@ def test_process_with_multipart_double_parts
mms.purge
end
- def test_process_with_multipart_alternative_parts
- mail = stub_mail
-
- plain = stub('plain', :filename => 'message.txt', :content_type => 'text/plain', :part_type? => 'text/plain', :body => Mail::Body.new('a'), :main_type => 'text')
- plain.stubs(:multipart?).at_least_once.returns(false)
-
- html = stub('html', :filename => 'message.html', :content_type => 'text/html', :part_type? => 'text/html', :body => Mail::Body.new('a'), :main_type => 'text')
- html.stubs(:multipart?).at_least_once.returns(false)
-
- multi = stub('multi', :content_type => 'multipart/alternative', :part_type? => 'multipart/alternative', :parts => [plain, html])
- multi.stubs(:multipart?).at_least_once.returns(true)
-
- mail.stubs(:multipart?).at_least_once.returns(true)
- mail.stubs(:parts).at_least_once.returns([multi])
-
- # the multipart/alternative should get flattend to text and html
- mms = MMS2R::Media.new(mail)
- assert_equal 2, mms.media.size
- assert_equal 2, mms.media.size
- assert_not_nil mms.media['text/plain']
- assert_not_nil mms.media['text/html']
- assert_equal 1, mms.media['text/plain'].size
- assert_equal 1, mms.media['text/html'].size
- assert_equal 'message.txt', File.basename(mms.media['text/plain'].first)
- assert_equal 'message.html', File.basename(mms.media['text/html'].first)
- assert_equal true, File.exist?(mms.media['text/plain'].first)
- assert_equal true, File.exist?(mms.media['text/html'].first)
- assert_equal 1, File.size(mms.media['text/plain'].first)
- assert_equal 1, File.size(mms.media['text/html'].first)
- mms.purge
+ def test_folding_with_multipart_alternative_parts
+ mail = mail('helio-message-01.mail')
+ mms = MMS2R::Media.new(Mail.new)
+ assert_equal 5, mms.send(:folded_parts, mail.parts).size
end
def test_process_when_media_is_ignored
- mail = stub_mail
- plain = stub('plain', :filename => 'message.txt', :content_type => 'text/plain', :part_type? => 'text/plain', :body => Mail::Body.new(''), :main_type => 'text')
- plain.stubs(:multipart?).at_least_once.returns(false)
-
- html = stub('html', :filename => 'message.html', :content_type => 'text/html', :part_type? => 'text/html', :body => Mail::Body.new(''), :main_type => 'text')
- html.stubs(:multipart?).at_least_once.returns(false)
-
-
- multi = stub('multi', :content_type => 'multipart/alternative', :part_type? => 'multipart/alternative', :parts => [plain, html])
- multi.stubs(:multipart?).at_least_once.returns(true)
-
- mail.stubs(:multipart?).at_least_once.returns(true)
- mail.stubs(:parts).at_least_once.returns([multi])
-
- mms = MMS2R::Media.new(mail, :process => :lazy)
- mms.stubs(:config).returns({'ignore' => {'text/plain' => ['message.txt'],
- 'text/html' => ['message.html']}})
- assert_nothing_raised { mms.process }
- # the multipart/alternative should get flattend to text and html and then
- # what's flattened is ignored
- assert_equal 0, mms.media.size
- mms.purge
+ # TODO - I'd like to get away from mocks and test on real data, and
+ # this is covered repeatedly for various samples from the carrier
end
def test_process_when_yielding_to_a_block
- mail = stub_mail
-
- plain = stub('plain', :filename => 'message.txt', :content_type => 'text/plain', :part_type? => 'text/plain', :body => Mail::Body.new('a'), :main_type => 'text')
- plain.stubs(:multipart?).at_least_once.returns(false)
-
- html = stub('html', :filename => 'message.html', :content_type => 'text/html', :part_type? => 'text/html', :body => Mail::Body.new('b'), :main_type => 'text')
- html.stubs(:multipart?).at_least_once.returns(false)
-
- multi = stub('multi', :content_type => 'multipart/alternative', :part_type? => 'multipart/alternative', :parts => [plain, html])
- multi.stubs(:multipart?).at_least_once.returns(true)
-
- mail.stubs(:multipart?).at_least_once.returns(true)
- mail.stubs(:parts).at_least_once.returns([multi])
-
- # the multipart/alternative should get flattend to text and html
+ mail = mail('att-image-01.mail')
mms = MMS2R::Media.new(mail)
- assert_equal 2, mms.media.size
mms.process do |type, files|
assert_equal 1, files.size
- assert_equal true, type == 'text/plain' || type == 'text/html'
- assert_equal true, File.basename(files.first) == 'message.txt' ||
- File.basename(files.first) == 'message.html'
+ assert_equal true, type == 'image/jpeg'
+ assert_equal true, File.basename(files.first) == 'Photo_12.jpg'
assert_equal true, File::exist?(files.first)
end
mms.purge
@@ -21,6 +21,7 @@ def test_only_valid_content_should_be_retained_for_mms_with_text
assert_equal "mms.myhelio.com", mms.carrier
assert_equal 1, mms.media.size
assert_equal 1, mms.media['text/plain'].size
+ assert_equal "Test message", open(mms.media['text/plain'].first).read
mms.purge
end
@@ -259,7 +259,6 @@ def test_message_is_missing_in_mail_purged_from_content_server
assert_equal '5135455555', mms.number
assert_equal "pm.sprint.com", mms.carrier
-
assert_equal 0, mms.media.size
mms.purge

0 comments on commit 33ff5da

Please sign in to comment.