2013-02-06 03:16:51 +08:00
require 'spec_helper'
require 'post_creator'
2013-04-17 04:56:18 +08:00
require 'topic_subtype'
2013-02-06 03:16:51 +08:00
describe PostCreator do
2013-05-14 09:59:55 +08:00
before do
ActiveRecord :: Base . observers . enable :all
end
2013-02-06 03:16:51 +08:00
let ( :user ) { Fabricate ( :user ) }
2013-07-08 10:44:55 +08:00
context " new topic " do
2013-02-06 03:16:51 +08:00
let ( :category ) { Fabricate ( :category , user : user ) }
2013-03-19 02:45:05 +08:00
let ( :topic ) { Fabricate ( :topic , user : user ) }
2013-07-08 10:44:55 +08:00
let ( :basic_topic_params ) { { title : " hello world topic " , raw : " my name is fred " , archetype_id : 1 } }
let ( :image_sizes ) { { 'http://an.image.host/image.jpg' = > { " width " = > 111 , " height " = > 222 } } }
2013-02-06 03:16:51 +08:00
let ( :creator ) { PostCreator . new ( user , basic_topic_params ) }
2013-07-18 06:58:25 +08:00
let ( :creator_with_category ) { PostCreator . new ( user , basic_topic_params . merge ( category : category . id ) ) }
2013-07-08 10:44:55 +08:00
let ( :creator_with_meta_data ) { PostCreator . new ( user , basic_topic_params . merge ( meta_data : { hello : " world " } ) ) }
2013-02-06 03:16:51 +08:00
let ( :creator_with_image_sizes ) { PostCreator . new ( user , basic_topic_params . merge ( image_sizes : image_sizes ) ) }
2013-07-22 09:40:39 +08:00
it " can be created with auto tracking disabled " do
p = PostCreator . create ( user , basic_topic_params . merge ( auto_track : false ) )
2013-07-22 13:06:53 +08:00
# must be 0 otherwise it will think we read the topic which is clearly untrue
TopicUser . where ( user_id : p . user_id , topic_id : p . topic_id ) . count . should == 0
2013-07-22 09:40:39 +08:00
end
2013-07-08 10:44:55 +08:00
it " ensures the user can create the topic " do
2013-02-06 03:16:51 +08:00
Guardian . any_instance . expects ( :can_create? ) . with ( Topic , nil ) . returns ( false )
lambda { creator . create } . should raise_error ( Discourse :: InvalidAccess )
end
2013-06-08 00:36:37 +08:00
context " invalid title " do
let ( :creator_invalid_title ) { PostCreator . new ( user , basic_topic_params . merge ( title : 'a' ) ) }
it " has errors " do
creator_invalid_title . create
expect ( creator_invalid_title . errors ) . to be_present
end
end
2013-10-23 09:14:31 +08:00
context " invalid raw " do
let ( :creator_invalid_raw ) { PostCreator . new ( user , basic_topic_params . merge ( raw : '' ) ) }
it " has errors " do
creator_invalid_raw . create
expect ( creator_invalid_raw . errors ) . to be_present
end
end
2013-07-08 10:44:55 +08:00
context " success " do
2013-02-06 03:16:51 +08:00
2013-05-11 04:58:23 +08:00
it " doesn't return true for spam " do
creator . create
creator . spam? . should be_false
end
2013-07-08 10:44:55 +08:00
it " does not notify on system messages " do
admin = Fabricate ( :admin )
messages = MessageBus . track_publish do
p = PostCreator . create ( admin , basic_topic_params . merge ( post_type : Post . types [ :moderator_action ] ) )
PostCreator . create ( admin , basic_topic_params . merge ( topic_id : p . topic_id , post_type : Post . types [ :moderator_action ] ) )
end
# don't notify on system messages they introduce too much noise
channels = messages . map ( & :channel )
channels . find { | s | s =~ / unread / } . should be_nil
channels . find { | s | s =~ / new / } . should be_nil
end
it " generates the correct messages for a secure topic " do
2013-05-16 13:03:03 +08:00
admin = Fabricate ( :admin )
cat = Fabricate ( :category )
2013-07-14 09:24:16 +08:00
cat . set_permissions ( :admins = > :full )
2013-05-16 13:03:03 +08:00
cat . save
created_post = nil
reply = nil
messages = MessageBus . track_publish do
2013-07-18 06:58:25 +08:00
created_post = PostCreator . new ( admin , basic_topic_params . merge ( category : cat . id ) ) . create
2013-07-08 10:44:55 +08:00
reply = PostCreator . new ( admin , raw : " this is my test reply 123 testing " , topic_id : created_post . topic_id ) . create
2013-05-16 13:03:03 +08:00
end
2014-06-25 08:55:50 +08:00
# 2 for topic, one to notify of new topic another for tracking state
2013-06-03 15:07:44 +08:00
messages . map { | m | m . channel } . sort . should == [ " /new " ,
2013-05-16 13:03:03 +08:00
" /users/ #{ admin . username } " ,
" /users/ #{ admin . username } " ,
2013-06-03 15:07:44 +08:00
" /unread/ #{ admin . id } " ,
" /unread/ #{ admin . id } " ,
2014-06-25 08:55:50 +08:00
" /topic/ #{ created_post . topic_id } " ,
2013-06-03 15:07:44 +08:00
" /topic/ #{ created_post . topic_id } "
2013-05-16 13:03:03 +08:00
] . sort
admin_ids = [ Group [ :admins ] . id ]
2013-06-03 15:07:44 +08:00
messages . any? { | m | m . group_ids != admin_ids && m . user_ids != [ admin . id ] } . should be_false
2013-02-06 03:16:51 +08:00
end
2013-06-03 15:07:44 +08:00
it 'generates the correct messages for a normal topic' do
2013-05-16 13:03:03 +08:00
p = nil
messages = MessageBus . track_publish do
p = creator . create
end
2013-06-03 15:07:44 +08:00
latest = messages . find { | m | m . channel == " /new " }
2013-05-16 13:03:03 +08:00
latest . should_not be_nil
2013-06-03 15:07:44 +08:00
read = messages . find { | m | m . channel == " /unread/ #{ p . user_id } " }
read . should_not be_nil
2013-05-16 13:03:03 +08:00
user_action = messages . find { | m | m . channel == " /users/ #{ p . user . username } " }
user_action . should_not be_nil
2014-06-25 08:55:50 +08:00
messages . length . should == 4
2013-03-19 02:45:05 +08:00
end
2013-05-16 13:03:03 +08:00
it 'extracts links from the post' do
TopicLink . expects ( :extract_from ) . with ( instance_of ( Post ) )
2013-03-19 01:55:34 +08:00
creator . create
end
it 'queues up post processing job when saved' do
2013-05-16 13:03:03 +08:00
Jobs . expects ( :enqueue ) . with ( :feature_topic_users , has_key ( :topic_id ) )
2013-03-19 01:55:34 +08:00
Jobs . expects ( :enqueue ) . with ( :process_post , has_key ( :post_id ) )
2014-03-05 11:26:42 +08:00
Jobs . expects ( :enqueue ) . with ( :notify_mailing_list_subscribers , has_key ( :post_id ) )
2013-03-19 01:55:34 +08:00
creator . create
end
it 'passes the invalidate_oneboxes along to the job if present' do
Jobs . stubs ( :enqueue ) . with ( :feature_topic_users , has_key ( :topic_id ) )
2014-03-05 11:26:42 +08:00
Jobs . expects ( :enqueue ) . with ( :notify_mailing_list_subscribers , has_key ( :post_id ) )
2013-03-19 01:55:34 +08:00
Jobs . expects ( :enqueue ) . with ( :process_post , has_key ( :invalidate_oneboxes ) )
creator . opts [ :invalidate_oneboxes ] = true
creator . create
end
it 'passes the image_sizes along to the job if present' do
Jobs . stubs ( :enqueue ) . with ( :feature_topic_users , has_key ( :topic_id ) )
2014-03-05 11:26:42 +08:00
Jobs . expects ( :enqueue ) . with ( :notify_mailing_list_subscribers , has_key ( :post_id ) )
2013-03-19 01:55:34 +08:00
Jobs . expects ( :enqueue ) . with ( :process_post , has_key ( :image_sizes ) )
creator . opts [ :image_sizes ] = { 'http://an.image.host/image.jpg' = > { 'width' = > 17 , 'height' = > 31 } }
creator . create
end
2013-02-06 03:16:51 +08:00
it 'assigns a category when supplied' do
creator_with_category . create . topic . category . should == category
end
it 'adds meta data from the post' do
creator_with_meta_data . create . topic . meta_data [ 'hello' ] . should == 'world'
end
it 'passes the image sizes through' do
Post . any_instance . expects ( :image_sizes = ) . with ( image_sizes )
creator_with_image_sizes . create
2013-02-26 00:42:20 +08:00
end
2013-04-05 12:29:46 +08:00
it 'increases topic response counts' do
first_post = creator . create
2013-07-22 13:06:53 +08:00
# ensure topic user is correct
2014-05-06 21:41:59 +08:00
topic_user = first_post . user . topic_users . find_by ( topic_id : first_post . topic_id )
2013-07-22 13:06:53 +08:00
topic_user . should be_present
topic_user . should be_posted
topic_user . last_read_post_number . should == first_post . post_number
topic_user . seen_post_count . should == first_post . post_number
user2 = Fabricate ( :coding_horror )
2013-10-04 11:28:49 +08:00
user2 . user_stat . topic_reply_count . should == 0
first_post . user . user_stat . reload . topic_reply_count . should == 0
2013-04-05 12:29:46 +08:00
PostCreator . new ( user2 , topic_id : first_post . topic_id , raw : " this is my test post 123 " ) . create
2013-10-04 11:28:49 +08:00
first_post . user . user_stat . reload . topic_reply_count . should == 0
user2 . user_stat . reload . topic_reply_count . should == 1
2013-04-05 12:29:46 +08:00
end
2014-03-19 01:40:40 +08:00
it 'sets topic excerpt if first post, but not second post' do
first_post = creator . create
topic = first_post . topic . reload
topic . excerpt . should be_present
expect {
PostCreator . new ( first_post . user , topic_id : first_post . topic_id , raw : " this is the second post " ) . create
topic . reload
} . to_not change { topic . excerpt }
end
2013-02-26 00:42:20 +08:00
end
2013-02-06 03:16:51 +08:00
2013-05-08 02:25:41 +08:00
context 'when auto-close param is given' do
2013-11-29 00:06:04 +08:00
it 'ensures the user can auto-close the topic, but ignores auto-close param silently' do
2013-05-08 02:25:41 +08:00
Guardian . any_instance . stubs ( :can_moderate? ) . returns ( false )
2013-11-29 00:06:04 +08:00
post = PostCreator . new ( user , basic_topic_params . merge ( auto_close_time : 2 ) ) . create
post . topic . auto_close_at . should be_nil
2013-05-08 02:25:41 +08:00
end
end
2013-02-06 03:16:51 +08:00
end
2013-03-19 01:55:34 +08:00
context 'uniqueness' do
let! ( :topic ) { Fabricate ( :topic , user : user ) }
let ( :basic_topic_params ) { { raw : 'test reply' , topic_id : topic . id , reply_to_post_number : 4 } }
let ( :creator ) { PostCreator . new ( user , basic_topic_params ) }
context " disabled " do
before do
2014-07-14 13:59:58 +08:00
SiteSetting . unique_posts_mins = 0
2013-03-19 01:55:34 +08:00
creator . create
end
it " returns true for another post with the same content " do
new_creator = PostCreator . new ( user , basic_topic_params )
new_creator . create . should be_present
end
end
context 'enabled' do
let ( :new_post_creator ) { PostCreator . new ( user , basic_topic_params ) }
before do
2014-07-14 13:59:58 +08:00
SiteSetting . unique_posts_mins = 10
end
it " fails for dupe post accross topic " do
first = create_post
second = create_post
dupe = " hello 123 test #{ SecureRandom . hex } "
response_1 = create_post ( raw : dupe , user : first . user , topic_id : first . topic_id )
response_2 = create_post ( raw : dupe , user : first . user , topic_id : second . topic_id )
response_1 . errors . count . should == 0
response_2 . errors . count . should == 1
2013-03-19 01:55:34 +08:00
end
it " returns blank for another post with the same content " do
2014-07-14 13:59:58 +08:00
creator . create
2013-03-19 01:55:34 +08:00
new_post_creator . create
new_post_creator . errors . should be_present
end
it " returns a post for admins " do
2014-07-14 13:59:58 +08:00
creator . create
2013-03-19 01:55:34 +08:00
user . admin = true
new_post_creator . create
new_post_creator . errors . should be_blank
end
it " returns a post for moderators " do
2014-07-14 13:59:58 +08:00
creator . create
2013-03-20 12:05:19 +08:00
user . moderator = true
2013-03-19 01:55:34 +08:00
new_post_creator . create
new_post_creator . errors . should be_blank
end
end
end
2013-05-11 04:58:23 +08:00
context " host spam " do
let! ( :topic ) { Fabricate ( :topic , user : user ) }
let ( :basic_topic_params ) { { raw : 'test reply' , topic_id : topic . id , reply_to_post_number : 4 } }
let ( :creator ) { PostCreator . new ( user , basic_topic_params ) }
before do
Post . any_instance . expects ( :has_host_spam? ) . returns ( true )
end
it " does not create the post " do
2013-06-11 01:17:09 +08:00
GroupMessage . stubs ( :create )
2013-05-11 04:58:23 +08:00
creator . create
creator . errors . should be_present
creator . spam? . should be_true
end
2013-06-11 01:17:09 +08:00
it " sends a message to moderators " do
GroupMessage . expects ( :create ) . with do | group_name , msg_type , params |
group_name == Group [ :moderators ] . name and msg_type == :spam_post_blocked and params [ :user ] . id == user . id
end
creator . create
end
2013-05-11 04:58:23 +08:00
end
2013-04-17 15:33:34 +08:00
# more integration testing ... maximise our testing
2013-02-06 03:16:51 +08:00
context 'existing topic' do
let! ( :topic ) { Fabricate ( :topic , user : user ) }
let ( :creator ) { PostCreator . new ( user , raw : 'test reply' , topic_id : topic . id , reply_to_post_number : 4 ) }
it 'ensures the user can create the post' do
Guardian . any_instance . expects ( :can_create? ) . with ( Post , topic ) . returns ( false )
lambda { creator . create } . should raise_error ( Discourse :: InvalidAccess )
end
context 'success' do
2013-04-17 15:33:34 +08:00
it 'create correctly' do
post = creator . create
Post . count . should == 1
Topic . count . should == 1
post . reply_to_post_number . should == 4
2013-02-06 03:16:51 +08:00
end
end
end
2013-06-21 23:36:33 +08:00
context " cooking options " do
let ( :raw ) { " this is my awesome message body hello world " }
it " passes the cooking options through correctly " do
creator = PostCreator . new ( user ,
title : 'hi there welcome to my topic' ,
raw : raw ,
cooking_options : { traditional_markdown_linebreaks : true } )
Post . any_instance . expects ( :cook ) . with ( raw , has_key ( :traditional_markdown_linebreaks ) ) . returns ( raw )
creator . create
end
end
2013-04-17 15:33:34 +08:00
# integration test ... minimise db work
2013-02-06 03:16:51 +08:00
context 'private message' do
let ( :target_user1 ) { Fabricate ( :coding_horror ) }
let ( :target_user2 ) { Fabricate ( :moderator ) }
2013-04-17 15:33:34 +08:00
let ( :unrelated ) { Fabricate ( :user ) }
let ( :post ) do
PostCreator . create ( user , title : 'hi there welcome to my topic' ,
raw : " this is my awesome message @ #{ unrelated . username_lower } " ,
archetype : Archetype . private_message ,
2014-01-24 19:57:48 +08:00
target_usernames : [ target_user1 . username , target_user2 . username ] . join ( ',' ) ,
category : 1 )
2013-04-17 15:33:34 +08:00
end
2013-02-06 03:16:51 +08:00
2013-04-17 15:33:34 +08:00
it 'acts correctly' do
post . topic . archetype . should == Archetype . private_message
post . topic . topic_allowed_users . count . should == 3
2013-02-06 03:16:51 +08:00
2014-01-24 19:57:48 +08:00
# PMs can't have a category
post . topic . category . should be_nil
2013-04-17 15:33:34 +08:00
# does not notify an unrelated user
unrelated . notifications . count . should == 0
post . topic . subtype . should == TopicSubtype . user_to_user
2013-09-06 12:07:23 +08:00
2014-05-13 03:26:36 +08:00
# if an admin replies they should be added to the allowed user list
admin = Fabricate ( :admin )
PostCreator . create ( admin , raw : 'hi there welcome topic, I am a mod' ,
2013-09-06 12:07:23 +08:00
topic_id : post . topic_id )
post . topic . reload
2014-05-13 03:26:36 +08:00
post . topic . topic_allowed_users . where ( user_id : admin . id ) . count . should == 1
2013-02-06 03:16:51 +08:00
end
end
2013-05-02 13:15:17 +08:00
context 'private message to group' do
let ( :target_user1 ) { Fabricate ( :coding_horror ) }
let ( :target_user2 ) { Fabricate ( :moderator ) }
let ( :group ) do
g = Fabricate . build ( :group )
g . add ( target_user1 )
g . add ( target_user2 )
g . save
g
end
let ( :unrelated ) { Fabricate ( :user ) }
let ( :post ) do
PostCreator . create ( user , title : 'hi there welcome to my topic' ,
raw : " this is my awesome message @ #{ unrelated . username_lower } " ,
archetype : Archetype . private_message ,
target_group_names : group . name )
end
it 'acts correctly' do
post . topic . archetype . should == Archetype . private_message
post . topic . topic_allowed_users . count . should == 1
post . topic . topic_allowed_groups . count . should == 1
# does not notify an unrelated user
unrelated . notifications . count . should == 0
post . topic . subtype . should == TopicSubtype . user_to_user
target_user1 . notifications . count . should == 1
target_user2 . notifications . count . should == 1
end
end
2013-05-19 03:24:29 +08:00
context 'setting created_at' do
created_at = 1 . week . ago
let ( :topic ) do
PostCreator . create ( user ,
raw : 'This is very interesting test post content' ,
title : 'This is a very interesting test post title' ,
created_at : created_at )
end
let ( :post ) do
PostCreator . create ( user ,
raw : 'This is very interesting test post content' ,
topic_id : Topic . last ,
created_at : created_at )
end
it 'acts correctly' do
topic . created_at . should be_within ( 10 . seconds ) . of ( created_at )
post . created_at . should be_within ( 10 . seconds ) . of ( created_at )
end
end
2013-07-02 10:22:56 +08:00
context 'disable validations' do
it 'can save a post' do
creator = PostCreator . new ( user , raw : 'q' , title : 'q' , skip_validations : true )
2014-03-07 16:00:09 +08:00
creator . create
2013-07-02 10:22:56 +08:00
creator . errors . should be_nil
end
end
2013-12-11 02:47:07 +08:00
describe " word_count " do
it " has a word count " do
creator = PostCreator . new ( user , title : 'some inspired poetry for a rainy day' , raw : 'mary had a little lamb, little lamb, little lamb. mary had a little lamb' )
post = creator . create
post . word_count . should == 14
post . topic . reload
post . topic . word_count . should == 14
end
end
2014-04-04 02:42:26 +08:00
describe " embed_url " do
let ( :embed_url ) { " http://eviltrout.com/stupid-url " }
it " creates the topic_embed record " do
creator = PostCreator . new ( user ,
embed_url : embed_url ,
title : 'Reviews of Science Ovens' ,
raw : 'Did you know that you can use microwaves to cook your dinner? Science!' )
2014-06-04 09:41:42 +08:00
creator . create
2014-04-04 02:42:26 +08:00
TopicEmbed . where ( embed_url : embed_url ) . exists? . should be_true
end
end
2014-06-04 09:41:42 +08:00
describe " read credit for creator " do
it " should give credit to creator " do
post = create_post
PostTiming . find_by ( topic_id : post . topic_id ,
post_number : post . post_number ,
user_id : post . user_id ) . msecs . should be > 0
TopicUser . find_by ( topic_id : post . topic_id ,
user_id : post . user_id ) . last_read_post_number . should == 1
end
end
2014-07-31 11:15:16 +08:00
describe " suspended users " do
it " does not allow suspended users to create topics " do
user = Fabricate ( :user , suspended_at : 1 . month . ago , suspended_till : 1 . month . from_now )
creator = PostCreator . new ( user , { title : " my test title 123 " , raw : " I should not be allowed to post " } )
creator . create
creator . errors . count . should be > 0
end
end
2013-02-06 03:16:51 +08:00
end