diff --git a/frontend_tests/node_tests/transmit.js b/frontend_tests/node_tests/transmit.js index d2c192eb5d..590a375117 100644 --- a/frontend_tests/node_tests/transmit.js +++ b/frontend_tests/node_tests/transmit.js @@ -16,7 +16,9 @@ set_global('sent_messages', { start_tracking_message: noop, report_server_ack: noop, }); +set_global('blueslip', global.make_zblueslip()); +zrequire('people'); zrequire('transmit'); function test_with_mock_socket(test_params) { @@ -168,3 +170,97 @@ run_test('transmit_message_ajax_reload_pending', () => { assert(!error_func_called); assert(reload_initiated); }); + +run_test('reply_message_stream', () => { + const stream_message = { + type: 'stream', + stream: 'social', + subject: 'lunch', + sender_full_name: 'Alice', + }; + + const content = 'hello'; + + var send_message_args; + + transmit.send_message = (args) => { + send_message_args = args; + }; + + page_params.user_id = 44; + page_params.queue_id = 66; + sent_messages.get_new_local_id = () => 99; + + transmit.reply_message({ + message: stream_message, + content: content, + }); + + assert.deepEqual(send_message_args, { + sender_id: 44, + queue_id: 66, + local_id: 99, + type: 'stream', + to: 'social', + content: '@**Alice** hello', + subject: 'lunch', + }); +}); + +run_test('reply_message_private', () => { + const fred = { + user_id: 3, + email: 'fred@example.com', + full_name: 'Fred Frost', + }; + people.add(fred); + + people.is_my_user_id = () => false; + + const pm_message = { + type: 'private', + display_recipient: [ + {user_id: fred.user_id}, + ], + }; + + const content = 'hello'; + + var send_message_args; + + transmit.send_message = (args) => { + send_message_args = args; + }; + + page_params.user_id = 155; + page_params.queue_id = 177; + sent_messages.get_new_local_id = () => 199; + + transmit.reply_message({ + message: pm_message, + content: content, + }); + + assert.deepEqual(send_message_args, { + sender_id: 155, + queue_id: 177, + local_id: 199, + type: 'private', + to: '["fred@example.com"]', + content: 'hello', + }); +}); + +run_test('reply_message_errors', () => { + const bogus_message = { + type: 'bogus', + }; + + blueslip.set_test_data('error', 'unknown message type: bogus'); + + transmit.reply_message({ + message: bogus_message, + }); + + blueslip.clear_test_data(); +}); diff --git a/static/js/transmit.js b/static/js/transmit.js index 1ac6c75dff..bb5c5b615d 100644 --- a/static/js/transmit.js +++ b/static/js/transmit.js @@ -63,6 +63,75 @@ exports.send_message = function (request, on_success, error) { } }; +exports.reply_message = function (opts) { + // This code does an application-triggered reply to a message (as + // opposed to the user themselves doing it). Its only use case + // for now is experimental widget-aware bots, so treat this as + // somewhat beta code. To understand the use case, think of a + // bot that wants to give users 3 or 4 canned replies to some + // choice, but it wants to front-end each of these options + // with a one-click button. This function is part of that architecture. + var message = opts.message; + var content = opts.content; + + function success() { + // TODO: If server response comes back before the message event, + // we could show it earlier, although that creates some + // complexity. For now do nothing. (Note that send_message + // already handles things like reporting times to the server.) + } + + function error() { + // TODO: In our current use case, which is widgets, to meaningfully + // handle errors, we would want the widget to provide some + // kind of callback to us so it can do some appropriate UI. + // For now do nothing. + } + + var locally_echoed = false; + var local_id = sent_messages.get_new_local_id(); + + var reply = { + sender_id: page_params.user_id, + queue_id: page_params.queue_id, + local_id: local_id, + }; + + sent_messages.start_tracking_message({ + local_id: local_id, + locally_echoed: locally_echoed, + }); + + if (message.type === 'stream') { + var stream = message.stream; + + var mention = '@**' + message.sender_full_name + '**'; + + content = mention + ' ' + content; + + reply.type = 'stream'; + reply.to = stream; + reply.content = content; + reply.subject = message.subject; + + transmit.send_message(reply, success, error); + return; + } + + if (message.type === 'private') { + var pm_recipient = people.pm_reply_to(message); + + reply.type = 'private'; + reply.to = JSON.stringify(pm_recipient.split(',')); + reply.content = content; + + transmit.send_message(reply, success, error); + return; + } + + blueslip.error('unknown message type: ' + message.type); +}; + return exports; }());