From ce1cb1bf7de0ce4973aac73c157e91167738cd70 Mon Sep 17 00:00:00 2001 From: Ben Sully Date: Sat, 21 Jan 2017 12:53:40 +0000 Subject: [PATCH] Allow Channel.send_message to reply to a thread This makes it easier to meet Slack's Best Practices for bots (https://api.slack.com/docs/message-threading#best_practices) which states that they should reply to threaded messages in the same thread. --- docs-src/real_time_messaging.rst | 16 ++++++++++++++++ slackclient/_channel.py | 14 +++++++++++++- slackclient/_client.py | 12 ++++++++++-- tests/test_channel.py | 31 +++++++++++++++++++++++++++++-- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/docs-src/real_time_messaging.rst b/docs-src/real_time_messaging.rst index 7a2c2c7c7..520f50f48 100644 --- a/docs-src/real_time_messaging.rst +++ b/docs-src/real_time_messaging.rst @@ -76,6 +76,22 @@ You can send a message to Slack by sending JSON over the websocket connection. You can send a message to a private group or direct message channel in the same way, but using a Group ID (``C024BE91L``) or DM channel ID (``D024BE91L``). +You can send a message in reply to a thread using the ``thread`` argument, and +optionally broadcast that message back to the channel by setting +``reply_broadcast`` to ``True``. + +:: + + from slackclient import SlackClient + + slack_token = os.environ["SLACK_API_TOKEN"] + sc = SlackClient(slack_token) + + sc.rtm_send_message("welcome-test", "test", "1482960137.003543", True) + +See `Threading messages `_ +for more details on using threads. + The RTM API only supports posting messages with `basic formatting `_. It does not support attachments or other message formatting modes. diff --git a/slackclient/_channel.py b/slackclient/_channel.py index e63f2f279..f0ef86962 100644 --- a/slackclient/_channel.py +++ b/slackclient/_channel.py @@ -26,15 +26,27 @@ def __str__(self): def __repr__(self): return self.__str__() - def send_message(self, message): + def send_message(self, message, thread=None, reply_broadcast=False): ''' Sends a message to a this Channel. + Include the parent message's thread_ts value in `thread` + to send to a thread. + :Args: message (message) - the string you'd like to send to the channel + thread (str or None) - the parent message ID, if sending to a + thread + reply_broadcast (bool) - if messaging a thread, whether to + also send the message back to the channel :Returns: None ''' message_json = {"type": "message", "channel": self.id, "text": message} + if thread is not None: + message_json["thread_ts"] = thread + if reply_broadcast: + message_json['reply_broadcast'] = True + self.server.send_to_websocket(message_json) diff --git a/slackclient/_client.py b/slackclient/_client.py index 129e993ff..00b0225cd 100644 --- a/slackclient/_client.py +++ b/slackclient/_client.py @@ -131,7 +131,7 @@ def rtm_read(self): else: raise SlackNotConnected - def rtm_send_message(self, channel, message): + def rtm_send_message(self, channel, message, thread=None, reply_broadcast=None): ''' Sends a message to a given channel. @@ -139,12 +139,20 @@ def rtm_send_message(self, channel, message): channel (str) - the string identifier for a channel or channel name (e.g. 'C1234ABC', 'bot-test' or '#bot-test') message (message) - the string you'd like to send to the channel + thread (str or None) - the parent message ID, if sending to a + thread + reply_broadcast (bool) - if messaging a thread, whether to + also send the message back to the channel :Returns: None ''' - return self.server.channels.find(channel).send_message(message) + return self.server.channels.find(channel).send_message( + message, + thread, + reply_broadcast, + ) def process_changes(self, data): ''' diff --git a/tests/test_channel.py b/tests/test_channel.py index a4604dd97..4680b548d 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -26,6 +26,33 @@ def test_channel_is_hashable(channel): assert channel_map[channel] == 'C12345678' assert (channel_map[channel] == 'foo') is False -@pytest.mark.xfail -def test_channel_send_message(channel): + +def test_channel_send_message(channel, mocker, monkeypatch): + mock_server = mocker.Mock() + monkeypatch.setattr(channel, 'server', mock_server) channel.send_message('hi') + mock_server.send_to_websocket.assert_called_with({ + 'text': 'hi', + 'channel': channel.id, + 'type': 'message', + }) + + +def test_channel_send_message_to_thread(channel, mocker, monkeypatch): + mock_server = mocker.Mock() + monkeypatch.setattr(channel, 'server', mock_server) + channel.send_message('hi', thread='123456.789') + mock_server.send_to_websocket.assert_called_with({ + 'text': 'hi', + 'channel': channel.id, + 'type': 'message', + 'thread_ts': '123456.789', + }) + channel.send_message('hi', thread='123456.789', reply_broadcast=True) + mock_server.send_to_websocket.assert_called_with({ + 'text': 'hi', + 'channel': channel.id, + 'type': 'message', + 'thread_ts': '123456.789', + 'reply_broadcast': True, + })