2013-11-25 11:29:37 -05:00
# -*- encoding : utf-8 -*-
2013-06-10 16:46:08 -04:00
require 'spec_helper'
require 'email/receiver'
describe Email :: Receiver do
2013-06-13 18:11:10 -04:00
before do
2014-07-31 18:46:02 +10:00
SiteSetting . reply_by_email_address = " reply+%{reply_key}@appmail.adventuretime.ooo "
SiteSetting . email_in = false
2014-08-26 17:08:53 -07:00
SiteSetting . title = " Discourse "
2013-06-13 18:11:10 -04:00
end
2013-06-10 16:46:08 -04:00
2014-08-26 17:08:53 -07:00
describe 'parse_body' do
def test_parse_body ( mail_string )
Email :: Receiver . new ( nil ) . parse_body ( Mail :: Message . new mail_string )
end
2014-02-28 13:05:09 +01:00
it " raises EmptyEmailError if the message is blank " do
2014-08-26 17:08:53 -07:00
expect { test_parse_body ( " " ) } . to raise_error ( Email :: Receiver :: EmptyEmailError )
2013-06-13 18:11:10 -04:00
end
2013-06-10 16:46:08 -04:00
2014-07-11 12:26:40 -07:00
it " raises EmptyEmailError if the message is not an email " do
2014-08-26 17:08:53 -07:00
expect { test_parse_body ( " asdf " * 30 ) } . to raise_error ( Email :: Receiver :: EmptyEmailError )
2013-06-10 16:46:08 -04:00
end
2014-07-11 12:26:40 -07:00
2014-08-26 17:08:53 -07:00
it " raises EmptyEmailError if there is no reply content " do
expect { test_parse_body ( fixture_file ( " emails/no_content_reply.eml " ) ) } . to raise_error ( Email :: Receiver :: EmptyEmailError )
2014-07-11 12:26:40 -07:00
end
2013-06-13 18:11:10 -04:00
2014-08-26 17:08:53 -07:00
pending " raises EmailUnparsableError if the headers are corrupted " do
expect { ; } . to raise_error ( Email :: Receiver :: EmailUnparsableError )
end
2013-06-20 12:38:03 -04:00
2014-08-26 17:08:53 -07:00
it " can parse the html section " do
test_parse_body ( fixture_file ( " emails/html_only.eml " ) ) . should == " The EC2 instance - I've seen that there tends to be odd and " +
" unrecommended settings on the Bitnami installs that I've checked out. "
2013-06-20 12:38:03 -04:00
end
2014-08-26 17:08:53 -07:00
it " supports a Dutch reply " do
test_parse_body ( fixture_file ( " emails/dutch.eml " ) ) . should == " Dit is een antwoord in het Nederlands. "
end
it " supports a Hebrew reply " do
I18n . expects ( :t ) . with ( 'user_notifications.previous_discussion' ) . returns ( 'כלטוב' )
2013-06-20 12:38:03 -04:00
2014-08-26 17:08:53 -07:00
# The force_encoding call is only needed for the test - it is passed on fine to the cooked post
2014-08-28 12:09:42 -07:00
test_parse_body ( fixture_file ( " emails/hebrew.eml " ) ) . should == " שלום "
2013-06-20 12:38:03 -04:00
end
2014-08-26 17:08:53 -07:00
it " supports a BIG5-encoded reply " do
I18n . expects ( :t ) . with ( 'user_notifications.previous_discussion' ) . returns ( '媽!我上電視了!' )
2013-07-24 14:22:32 -04:00
2014-08-26 17:08:53 -07:00
# The force_encoding call is only needed for the test - it is passed on fine to the cooked post
2014-08-28 12:09:42 -07:00
test_parse_body ( fixture_file ( " emails/big5.eml " ) ) . should == " 媽!我上電視了! "
2013-07-24 14:22:32 -04:00
end
2013-08-21 16:54:01 -04:00
2014-08-26 17:08:53 -07:00
it " removes 'via' lines if they match the site title " do
SiteSetting . title = " Discourse "
2013-11-04 15:30:24 -05:00
2014-08-26 17:08:53 -07:00
test_parse_body ( fixture_file ( " emails/via_line.eml " ) ) . should == " Hello this email has content! "
2013-11-04 15:30:24 -05:00
end
2014-09-09 16:24:20 -07:00
it " removes an 'on date wrote' quoting line " do
test_parse_body ( fixture_file ( " emails/on_wrote.eml " ) ) . should == " Sure, all you need to do is frobnicate the foobar and you'll be all set! "
end
2014-08-26 17:08:53 -07:00
it " removes the 'Previous Discussion' marker " do
test_parse_body ( fixture_file ( " emails/previous.eml " ) ) . should == " This will not include the previous discussion that is present in this email. "
end
2014-01-17 10:24:32 +08:00
2014-08-26 17:08:53 -07:00
it " handles multiple paragraphs " do
test_parse_body ( fixture_file ( " emails/paragraphs.eml " ) ) .
should == (
" Is there any reason the *old* candy can't be be kept in silos while the new candy
is imported into * new * silos?
The thing about candy is it stays delicious for a long time - - we can just keep
it there without worrying about it too much , imo .
Thanks for listening . "
)
2014-01-17 10:24:32 +08:00
end
2014-08-28 12:09:42 -07:00
it " converts back to UTF-8 at the end " do
result = test_parse_body ( fixture_file ( " emails/big5.eml " ) )
result . encoding . should == Encoding :: UTF_8
# should not throw
TextCleaner . normalize_whitespaces (
test_parse_body ( fixture_file ( " emails/big5.eml " ) )
)
end
2014-01-17 10:24:32 +08:00
end
2014-08-26 17:08:53 -07:00
describe " posting replies " do
let ( :reply_key ) { raise " Override this in a lower describe block " }
let ( :email_raw ) { raise " Override this in a lower describe block " }
# ----
let ( :receiver ) { Email :: Receiver . new ( email_raw ) }
let ( :post ) { create_post }
let ( :topic ) { post . topic }
let ( :posting_user ) { post . user }
let ( :replying_user_email ) { 'jake@adventuretime.ooo' }
let ( :replying_user ) { Fabricate ( :user , email : replying_user_email , trust_level : 2 ) }
let ( :email_log ) { EmailLog . new ( reply_key : reply_key ,
post : post ,
post_id : post . id ,
topic_id : post . topic_id ,
email_type : 'user_posted' ,
user : replying_user ,
user_id : replying_user . id ,
to_address : replying_user_email
) }
before do
email_log . save
end
# === Success Posting ===
describe " valid_reply.eml " do
let! ( :reply_key ) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let! ( :email_raw ) { fixture_file ( " emails/valid_reply.eml " ) }
it " creates a post with the correct content " do
start_count = topic . posts . count
receiver . process
topic . posts . count . should == ( start_count + 1 )
2014-09-04 13:04:22 -04:00
created_post = topic . posts . last
created_post . via_email . should be_true
created_post . cooked . strip . should == fixture_file ( " emails/valid_reply.cooked " ) . strip
2014-08-26 17:08:53 -07:00
end
end
describe " paragraphs.eml " do
let! ( :reply_key ) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let! ( :email_raw ) { fixture_file ( " emails/paragraphs.eml " ) }
2013-08-21 16:54:01 -04:00
2014-08-26 17:08:53 -07:00
it " cooks multiple paragraphs with traditional Markdown linebreaks " do
start_count = topic . posts . count
receiver . process
topic . posts . count . should == ( start_count + 1 )
topic . posts . last . cooked . strip . should == fixture_file ( " emails/paragraphs.cooked " ) . strip
topic . posts . last . cooked . should_not match / <br /
end
2013-08-21 16:54:01 -04:00
end
2013-07-24 14:22:32 -04:00
2014-08-26 17:08:53 -07:00
describe " attachment.eml " do
let! ( :reply_key ) { '636ca428858779856c226bb145ef4fad' }
let! ( :email_raw ) {
fixture_file ( " emails/attachment.eml " )
. gsub ( " TO " , " reply+ #{ reply_key } @appmail.adventuretime.ooo " )
. gsub ( " FROM " , replying_user_email )
}
let ( :upload_sha ) { '04df605be528d03876685c52166d4b063aabb78a' }
it " creates a post with an attachment " do
start_count = topic . posts . count
Upload . find_by ( sha1 : upload_sha ) . try :destroy
receiver . process
topic . posts . count . should == ( start_count + 1 )
topic . posts . last . cooked . should match / <img src=['"]( \/ uploads \/ default \/ \ d+ \/ \ w{16} \ .png)['"] width=['"]289['"] height=['"]126['"]> /
Upload . find_by ( sha1 : upload_sha ) . should_not be_nil
end
2013-07-24 14:22:32 -04:00
end
2014-08-26 17:08:53 -07:00
# === Failure Conditions ===
2013-07-24 14:22:32 -04:00
2014-08-26 17:08:53 -07:00
describe " too_short.eml " do
let! ( :reply_key ) { '636ca428858779856c226bb145ef4fad' }
let! ( :email_raw ) {
fixture_file ( " emails/too_short.eml " )
. gsub ( " TO " , " reply+ #{ reply_key } @appmail.adventuretime.ooo " )
. gsub ( " FROM " , replying_user_email )
. gsub ( " SUBJECT " , " re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux' " )
}
it " raises an InvalidPost error " do
SiteSetting . min_post_length = 5
expect { receiver . process } . to raise_error ( Email :: Receiver :: InvalidPost )
end
2013-07-24 14:22:32 -04:00
end
2014-08-26 17:08:53 -07:00
describe " too_many_mentions.eml " do
let! ( :reply_key ) { '636ca428858779856c226bb145ef4fad' }
let! ( :email_raw ) { fixture_file ( " emails/too_many_mentions.eml " ) }
it " raises an InvalidPost error " do
SiteSetting . max_mentions_per_post = 10
( 1 .. 11 ) . each do | i |
Fabricate ( :user , username : " user #{ i } " ) . save
end
expect { receiver . process } . to raise_error ( Email :: Receiver :: InvalidPost )
end
end
2013-07-24 14:22:32 -04:00
end
2014-08-26 17:08:53 -07:00
describe " posting a new topic " do
let ( :category_destination ) { raise " Override this in a lower describe block " }
let ( :email_raw ) { raise " Override this in a lower describe block " }
let ( :allow_strangers ) { false }
# ----
let ( :receiver ) { Email :: Receiver . new ( email_raw ) }
let ( :user_email ) { 'jake@adventuretime.ooo' }
let ( :user ) { Fabricate ( :user , email : user_email , trust_level : 2 ) }
let ( :category ) { Fabricate ( :category , email_in : category_destination , email_in_allow_strangers : allow_strangers ) }
before do
SiteSetting . email_in = true
user . save
category . save
end
2013-06-25 14:05:14 -04:00
2014-08-26 17:08:53 -07:00
describe " too_short.eml " do
let! ( :category_destination ) { 'incoming+amazing@appmail.adventuretime.ooo' }
let ( :email_raw ) {
fixture_file ( " emails/too_short.eml " )
. gsub ( " TO " , category_destination )
. gsub ( " FROM " , user_email )
. gsub ( " SUBJECT " , " A long subject that passes the checks " )
}
2013-06-25 14:05:14 -04:00
2014-08-26 17:08:53 -07:00
it " does not create a topic if the post fails " do
before_topic_count = Topic . count
expect { receiver . process } . to raise_error ( Email :: Receiver :: InvalidPost )
Topic . count . should == before_topic_count
end
2013-06-25 14:05:14 -04:00
end
2014-08-26 17:08:53 -07:00
2013-06-25 14:05:14 -04:00
end
2014-07-31 18:46:02 +10:00
def fill_email ( mail , from , to , body = nil , subject = nil )
result = mail . gsub ( " FROM " , from ) . gsub ( " TO " , to )
if body
result . gsub! ( / Hey.* /m , body )
end
if subject
result . sub! ( / We .* / , subject )
end
result
end
def process_email ( opts )
incoming_email = fixture_file ( " emails/valid_incoming.eml " )
email = fill_email ( incoming_email , opts [ :from ] , opts [ :to ] , opts [ :body ] , opts [ :subject ] )
Email :: Receiver . new ( email ) . process
end
2013-06-13 18:11:10 -04:00
describe " with a valid email " do
let ( :reply_key ) { " 59d8df8370b7e95c5a49fbf86aeb2c93 " }
2014-07-31 18:46:02 +10:00
let ( :to ) { SiteSetting . reply_by_email_address . gsub ( " %{reply_key} " , reply_key ) }
let ( :valid_reply ) {
reply = fixture_file ( " emails/valid_reply.eml " )
to = SiteSetting . reply_by_email_address . gsub ( " %{reply_key} " , reply_key )
fill_email ( reply , " test@test.com " , to )
}
2013-06-13 18:11:10 -04:00
let ( :receiver ) { Email :: Receiver . new ( valid_reply ) }
2014-07-31 18:46:02 +10:00
let ( :post ) { create_post }
let ( :user ) { post . user }
let ( :email_log ) { EmailLog . new ( reply_key : reply_key ,
post_id : post . id ,
topic_id : post . topic_id ,
user_id : post . user_id ,
post : post ,
user : user ,
email_type : 'test' ,
to_address : 'test@test.com'
) }
2013-06-13 18:11:10 -04:00
let ( :reply_body ) {
" I could not disagree more. I am obviously biased but adventure time is the
greatest show ever created . Everyone should watch it .
- Jake out " }
describe " with an email log " do
2014-07-31 18:46:02 +10:00
it " extracts data " do
expect { receiver . process } . to raise_error ( Email :: Receiver :: EmailLogNotFound )
2013-06-13 18:11:10 -04:00
2014-07-31 18:46:02 +10:00
email_log . save!
receiver . process
2013-06-13 18:11:10 -04:00
expect ( receiver . body ) . to eq ( reply_body )
expect ( receiver . email_log ) . to eq ( email_log )
2014-03-28 09:57:12 -04:00
end
2014-04-14 22:55:57 +02:00
2014-03-28 09:57:12 -04:00
end
2013-06-10 16:46:08 -04:00
end
2014-02-27 13:44:21 +01:00
describe " processes an email to a category " do
before do
2014-07-31 18:46:02 +10:00
SiteSetting . email_in = true
2014-02-27 13:44:21 +01:00
end
2014-07-31 18:46:02 +10:00
it " correctly can target categories " do
to = " some@email.com "
2014-02-27 13:44:21 +01:00
2014-07-31 18:46:02 +10:00
Fabricate ( :category , email_in_allow_strangers : false , email_in : to )
2014-09-05 15:20:39 +10:00
SiteSetting . email_in_min_trust = TrustLevel [ 4 ] . to_s
2014-02-27 13:44:21 +01:00
2014-07-31 18:46:02 +10:00
# no email in for user
expect {
process_email ( from : " cobb@dob.com " , to : " invalid@address.com " )
2014-08-13 11:06:17 -07:00
} . to raise_error ( Email :: Receiver :: BadDestinationAddress )
2014-02-27 13:44:21 +01:00
2014-07-31 18:46:02 +10:00
# valid target invalid user
expect {
process_email ( from : " cobb@dob.com " , to : to )
} . to raise_error ( Email :: Receiver :: UserNotFoundError )
2014-02-27 13:44:21 +01:00
2014-07-31 18:46:02 +10:00
# untrusted
user = Fabricate ( :user )
expect {
process_email ( from : user . email , to : to )
} . to raise_error ( Email :: Receiver :: UserNotSufficientTrustLevelError )
2014-02-27 13:44:21 +01:00
2014-07-31 18:46:02 +10:00
# trusted
user . trust_level = 4
user . save
2014-02-24 17:36:53 +01:00
2014-07-31 18:46:02 +10:00
process_email ( from : user . email , to : to )
user . posts . count . should == 1
2014-02-24 17:36:53 +01:00
2014-07-31 18:46:02 +10:00
# email too short
message = nil
begin
process_email ( from : user . email , to : to , body : " x " , subject : " this is my new topic title " )
rescue Email :: Receiver :: InvalidPost = > e
message = e . message
2014-02-24 17:36:53 +01:00
end
2014-07-31 18:46:02 +10:00
e . message . should include ( " too short " )
2014-02-24 17:36:53 +01:00
end
end
2013-06-13 18:11:10 -04:00
2014-02-27 16:36:33 +01:00
describe " processes an unknown email sender to category " do
before do
2014-07-31 18:46:02 +10:00
SiteSetting . email_in = true
2014-02-27 16:36:33 +01:00
end
2014-07-31 18:46:02 +10:00
it " rejects anon email " do
Fabricate ( :category , email_in_allow_strangers : false , email_in : " bob@bob.com " )
expect { process_email ( from : " test@test.com " , to : " bob@bob.com " ) } . to raise_error ( Email :: Receiver :: UserNotFoundError )
2014-02-27 16:36:33 +01:00
end
2014-07-31 18:46:02 +10:00
it " creates a topic for allowed category " do
Fabricate ( :category , email_in_allow_strangers : true , email_in : " bob@bob.com " )
process_email ( from : " test@test.com " , to : " bob@bob.com " )
2014-02-27 16:36:33 +01:00
2014-07-31 18:46:02 +10:00
# This is the current implementation but it is wrong, it should register an account
Discourse . system_user . posts . order ( " id desc " ) . limit ( 1 ) . pluck ( :raw ) . first . should include ( " Hey folks " )
2014-02-27 16:36:33 +01:00
end
end
2013-06-10 16:46:08 -04:00
end