diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 64252c45220..0173cddedff 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -49,22 +49,20 @@ class PostsController < ApplicationController key = params_key(params) error_json = nil - payload = DistributedMemoizer.memoize(key, 120) do - post_creator = PostCreator.new(current_user, params) - post = post_creator.create - if post_creator.errors.present? - - # If the post was spam, flag all the user's posts as spam - current_user.flag_linked_posts_as_spam if post_creator.spam? - - error_json = MultiJson.dump(errors: post_creator.errors.full_messages) + if (is_api?) + payload = DistributedMemoizer.memoize(key, 120) do + success, json = create_post(params) + unless success + error_json = json + raise Discourse::InvalidPost + end + json + end + else + success, payload = create_post(params) + unless success + error_json = payload raise Discourse::InvalidPost - - else - post_serializer = PostSerializer.new(post, scope: guardian, root: false) - post_serializer.topic_slug = post.topic.slug if post.topic.present? - post_serializer.draft_sequence = DraftSequence.current(current_user, post.topic.draft_key) - MultiJson.dump(post_serializer) end end @@ -74,6 +72,22 @@ class PostsController < ApplicationController render json: error_json, status: 422 end + def create_post(params) + post_creator = PostCreator.new(current_user, params) + post = post_creator.create + if post_creator.errors.present? + # If the post was spam, flag all the user's posts as spam + current_user.flag_linked_posts_as_spam if post_creator.spam? + [false, MultiJson.dump(errors: post_creator.errors.full_messages)] + + else + post_serializer = PostSerializer.new(post, scope: guardian, root: false) + post_serializer.topic_slug = post.topic.slug if post.topic.present? + post_serializer.draft_sequence = DraftSequence.current(current_user, post.topic.draft_key) + [true, MultiJson.dump(post_serializer)] + end + end + def update params.require(:post) diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 76c235771a3..0c4391371bb 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -215,7 +215,7 @@ describe PostCreator do context "disabled" do before do - SiteSetting.stubs(:unique_posts_mins).returns(0) + SiteSetting.unique_posts_mins = 0 creator.create end @@ -229,22 +229,37 @@ describe PostCreator do let(:new_post_creator) { PostCreator.new(user, basic_topic_params) } before do - SiteSetting.stubs(:unique_posts_mins).returns(10) - creator.create + 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 end it "returns blank for another post with the same content" do + creator.create new_post_creator.create new_post_creator.errors.should be_present end it "returns a post for admins" do + creator.create user.admin = true new_post_creator.create new_post_creator.errors.should be_blank end it "returns a post for moderators" do + creator.create user.moderator = true new_post_creator.create new_post_creator.errors.should be_blank diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb index c3aff3ab629..1a5c687cf9c 100644 --- a/spec/controllers/posts_controller_spec.rb +++ b/spec/controllers/posts_controller_spec.rb @@ -367,6 +367,25 @@ describe PostsController do include_examples 'action requires login', :post, :create + context 'api' do + it 'allows dupes through' do + raw = "this is a test post 123 #{SecureRandom.hash}" + title = "this is a title #{SecureRandom.hash}" + + user = Fabricate(:user) + master_key = ApiKey.create_master_key.key + + xhr :post, :create, {api_username: user.username, api_key: master_key, raw: raw, title: title, wpid: 1} + response.should be_success + original = response.body + + xhr :post, :create, {api_username: user.username_lower, api_key: master_key, raw: raw, title: title, wpid: 2} + response.should be_success + + response.body.should == original + end + end + describe 'when logged in' do let!(:user) { log_in } @@ -389,15 +408,14 @@ describe PostsController do end it 'protects against dupes' do - # TODO we really should be using a mock redis here - xhr :post, :create, {raw: 'this is a test post 123', title: 'this is a test title 123', wpid: 1} - response.should be_success - original = response.body + raw = "this is a test post 123 #{SecureRandom.hash}" + title = "this is a title #{SecureRandom.hash}" - xhr :post, :create, {raw: 'this is a test post 123', title: 'this is a test title 123', wpid: 2} + xhr :post, :create, {raw: raw, title: title, wpid: 1} response.should be_success - response.body.should == original + xhr :post, :create, {raw: raw, title: title, wpid: 2} + response.should_not be_success end context "errors" do