From 7fee3c61de7feeaa5e784f3a36df15beeea3c931 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 29 Nov 2019 09:30:54 -0500 Subject: [PATCH] Support for custom messages and redirects when creating posts (#8434) * Support for custom messages and redirects when creating posts When a post/topic is created Discourse serializes a `NewPostResult` object. Normally this contains a status like `created_post` or errors describing why the post could not be created. There are times when a plugin might want to take the inputted post and do something in the background. In this case, the plugin can return a custom `message` and `route_to` attribute in the `NewPostResult`. If present, the message will be displayed in an alert, and when "Ok" is clicked the user will be routed to the new URL. * Destroy the draft in parallel --- .../discourse/controllers/composer.js.es6 | 11 ++++++++++ app/serializers/new_post_result_serializer.rb | 20 ++++++++++++++++++- lib/new_post_result.rb | 2 ++ .../new_post_result_serializer_spec.rb | 17 ++++++++++++++++ .../acceptance/composer-test.js.es6 | 20 +++++++++++++++++++ .../helpers/create-pretender.js.es6 | 9 +++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 spec/serializers/new_post_result_serializer_spec.rb diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index ae1393bd34e..a379d8f7e11 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -709,6 +709,17 @@ export default Controller.extend({ if (result.responseJson.action === "create_post") { this.appEvents.trigger("post:highlight", result.payload.post_number); } + + if (result.responseJson.route_to) { + this.destroyDraft(); + if (result.responseJson.message) { + return bootbox.alert(result.responseJson.message, () => { + DiscourseURL.routeTo(result.responseJson.route_to); + }); + } + return DiscourseURL.routeTo(result.responseJson.route_to); + } + this.close(); const currentUser = this.currentUser; diff --git a/app/serializers/new_post_result_serializer.rb b/app/serializers/new_post_result_serializer.rb index ca6eee7f9c7..9232062711e 100644 --- a/app/serializers/new_post_result_serializer.rb +++ b/app/serializers/new_post_result_serializer.rb @@ -6,7 +6,9 @@ class NewPostResultSerializer < ApplicationSerializer :errors, :success, :pending_count, - :reason + :reason, + :message, + :route_to has_one :pending_post, serializer: TopicPendingPostSerializer, root: false, embed: :objects @@ -64,4 +66,20 @@ class NewPostResultSerializer < ApplicationSerializer pending_count.present? end + def route_to + object.route_to + end + + def include_route_to? + object.route_to.present? + end + + def message + object.message + end + + def include_message? + object.message.present? + end + end diff --git a/lib/new_post_result.rb b/lib/new_post_result.rb index 70bf3f7262f..25d61f497ab 100644 --- a/lib/new_post_result.rb +++ b/lib/new_post_result.rb @@ -9,6 +9,8 @@ class NewPostResult attr_accessor :post attr_accessor :reviewable attr_accessor :pending_count + attr_accessor :route_to + attr_accessor :message def initialize(action, success = false) @action = action diff --git a/spec/serializers/new_post_result_serializer_spec.rb b/spec/serializers/new_post_result_serializer_spec.rb new file mode 100644 index 00000000000..4a1fe6dc22b --- /dev/null +++ b/spec/serializers/new_post_result_serializer_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe NewPostResultSerializer do + + it "includes the message and route_to if present" do + result = NewPostResult.new(:custom, true) + result.message = 'hello :)' + result.route_to = "/cool-route" + + serializer = described_class.new(result) + expect(serializer.success).to eq(true) + expect(serializer.message).to eq('hello :)') + expect(serializer.route_to).to eq('/cool-route') + end +end diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6 index 273275cde55..d85bb9a2785 100644 --- a/test/javascripts/acceptance/composer-test.js.es6 +++ b/test/javascripts/acceptance/composer-test.js.es6 @@ -234,6 +234,26 @@ QUnit.test("Create an enqueued Topic", async assert => { assert.ok(invisible(".d-modal"), "the modal can be dismissed"); }); +QUnit.test("Can display a message and route to a URL", async assert => { + await visit("/"); + await click("#create-topic"); + await fillIn("#reply-title", "This title doesn't matter"); + await fillIn(".d-editor-input", "custom message"); + await click("#reply-control button.create"); + assert.equal( + find(".bootbox .modal-body").text(), + "This is a custom response" + ); + assert.equal(currentURL(), "/", "it doesn't change routes"); + + await click(".bootbox .btn-primary"); + assert.equal( + currentURL(), + "/faq", + "can navigate to a `route_to` destination" + ); +}); + QUnit.test("Create a Reply", async assert => { await visit("/t/internationalization-localization/280"); diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index 46e9e11c84d..618a94942ed 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -497,6 +497,15 @@ export default function() { }); } + if (data.raw === "custom message") { + return response(200, { + success: true, + action: "custom", + message: "This is a custom response", + route_to: "/faq" + }); + } + return response(200, { success: true, action: "create_post",