Skip to content

Commit fb1fa7a

Browse files
sd2kRoach
authored andcommitted
Allow Channel.send_message to reply to a thread (#162)
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.
1 parent 4b7f996 commit fb1fa7a

File tree

4 files changed

+68
-5
lines changed

4 files changed

+68
-5
lines changed

docs-src/real_time_messaging.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ You can send a message to Slack by sending JSON over the websocket connection.
7676
You can send a message to a private group or direct message channel in the same
7777
way, but using a Group ID (``C024BE91L``) or DM channel ID (``D024BE91L``).
7878

79+
You can send a message in reply to a thread using the ``thread`` argument, and
80+
optionally broadcast that message back to the channel by setting
81+
``reply_broadcast`` to ``True``.
82+
83+
::
84+
85+
from slackclient import SlackClient
86+
87+
slack_token = os.environ["SLACK_API_TOKEN"]
88+
sc = SlackClient(slack_token)
89+
90+
sc.rtm_send_message("welcome-test", "test", "1482960137.003543", True)
91+
92+
See `Threading messages <https://api.slack.com/docs/message-threading#threads_party>`_
93+
for more details on using threads.
94+
7995
The RTM API only supports posting messages with `basic formatting <https://api.slack.com/docs/message-formatting>`_.
8096
It does not support attachments or other message formatting modes.
8197

slackclient/_channel.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,27 @@ def __str__(self):
2626
def __repr__(self):
2727
return self.__str__()
2828

29-
def send_message(self, message):
29+
def send_message(self, message, thread=None, reply_broadcast=False):
3030
'''
3131
Sends a message to a this Channel.
3232
33+
Include the parent message's thread_ts value in `thread`
34+
to send to a thread.
35+
3336
:Args:
3437
message (message) - the string you'd like to send to the channel
38+
thread (str or None) - the parent message ID, if sending to a
39+
thread
40+
reply_broadcast (bool) - if messaging a thread, whether to
41+
also send the message back to the channel
3542
3643
:Returns:
3744
None
3845
'''
3946
message_json = {"type": "message", "channel": self.id, "text": message}
47+
if thread is not None:
48+
message_json["thread_ts"] = thread
49+
if reply_broadcast:
50+
message_json['reply_broadcast'] = True
51+
4052
self.server.send_to_websocket(message_json)

slackclient/_client.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,28 @@ def rtm_read(self):
131131
else:
132132
raise SlackNotConnected
133133

134-
def rtm_send_message(self, channel, message):
134+
def rtm_send_message(self, channel, message, thread=None, reply_broadcast=None):
135135
'''
136136
Sends a message to a given channel.
137137
138138
:Args:
139139
channel (str) - the string identifier for a channel or channel name (e.g. 'C1234ABC',
140140
'bot-test' or '#bot-test')
141141
message (message) - the string you'd like to send to the channel
142+
thread (str or None) - the parent message ID, if sending to a
143+
thread
144+
reply_broadcast (bool) - if messaging a thread, whether to
145+
also send the message back to the channel
142146
143147
:Returns:
144148
None
145149
146150
'''
147-
return self.server.channels.find(channel).send_message(message)
151+
return self.server.channels.find(channel).send_message(
152+
message,
153+
thread,
154+
reply_broadcast,
155+
)
148156

149157
def process_changes(self, data):
150158
'''

tests/test_channel.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ def test_channel_is_hashable(channel):
2626
assert channel_map[channel] == 'C12345678'
2727
assert (channel_map[channel] == 'foo') is False
2828

29-
@pytest.mark.xfail
30-
def test_channel_send_message(channel):
29+
30+
def test_channel_send_message(channel, mocker, monkeypatch):
31+
mock_server = mocker.Mock()
32+
monkeypatch.setattr(channel, 'server', mock_server)
3133
channel.send_message('hi')
34+
mock_server.send_to_websocket.assert_called_with({
35+
'text': 'hi',
36+
'channel': channel.id,
37+
'type': 'message',
38+
})
39+
40+
41+
def test_channel_send_message_to_thread(channel, mocker, monkeypatch):
42+
mock_server = mocker.Mock()
43+
monkeypatch.setattr(channel, 'server', mock_server)
44+
channel.send_message('hi', thread='123456.789')
45+
mock_server.send_to_websocket.assert_called_with({
46+
'text': 'hi',
47+
'channel': channel.id,
48+
'type': 'message',
49+
'thread_ts': '123456.789',
50+
})
51+
channel.send_message('hi', thread='123456.789', reply_broadcast=True)
52+
mock_server.send_to_websocket.assert_called_with({
53+
'text': 'hi',
54+
'channel': channel.id,
55+
'type': 'message',
56+
'thread_ts': '123456.789',
57+
'reply_broadcast': True,
58+
})

0 commit comments

Comments
 (0)