Skip to content

Commit 3422a23

Browse files
authored
Make WebhookClient (sync/async) #send method accept link unfurl params (#1047)
1 parent a087d71 commit 3422a23

7 files changed

Lines changed: 153 additions & 36 deletions

File tree

integration_tests/webhook/test_async_webhook.py

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import os
2+
from tests.helpers import async_test
23
import unittest
4+
import time
35

46
from integration_tests.env_variable_names import (
57
SLACK_SDK_TEST_INCOMING_WEBHOOK_URL,
68
SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME,
79
SLACK_SDK_TEST_BOT_TOKEN,
810
)
9-
from integration_tests.helpers import async_test
1011
from slack_sdk.web.async_client import AsyncWebClient
1112
from slack_sdk.webhook.async_client import AsyncWebhookClient
1213
from slack_sdk.models.attachments import Attachment, AttachmentField
@@ -16,8 +17,22 @@
1617

1718

1819
class TestAsyncWebhook(unittest.TestCase):
19-
def setUp(self):
20-
pass
20+
@async_test
21+
async def setUp(self):
22+
if not hasattr(self, "channel_id"):
23+
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
24+
channel_name = os.environ[
25+
SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME
26+
].replace("#", "")
27+
client = AsyncWebClient(token=token)
28+
self.channel_id = None
29+
async for resp in await client.conversations_list(limit=10):
30+
for c in resp["channels"]:
31+
if c["name"] == channel_name:
32+
self.channel_id = c["id"]
33+
break
34+
if self.channel_id is not None:
35+
break
2136

2237
def tearDown(self):
2338
pass
@@ -31,24 +46,55 @@ async def test_webhook(self):
3146
self.assertEqual("ok", response.body)
3247

3348
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
34-
channel_name = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME].replace(
35-
"#", ""
36-
)
3749
client = AsyncWebClient(token=token)
38-
channel_id = None
39-
async for resp in await client.conversations_list(limit=10):
40-
for c in resp["channels"]:
41-
if c["name"] == channel_name:
42-
channel_id = c["id"]
43-
break
44-
if channel_id is not None:
45-
break
46-
47-
history = await client.conversations_history(channel=channel_id, limit=1)
50+
history = await client.conversations_history(channel=self.channel_id, limit=1)
4851
self.assertIsNotNone(history)
4952
actual_text = history["messages"][0]["text"]
5053
self.assertEqual("Hello!", actual_text)
5154

55+
@async_test
56+
async def test_with_unfurls_off(self):
57+
url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL]
58+
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
59+
webhook = AsyncWebhookClient(url)
60+
client = AsyncWebClient(token=token)
61+
# send message that does not unfurl
62+
response = await webhook.send(
63+
text="<https://imgs.xkcd.com/comics/desert_golfing_2x.png|Desert Golfing>",
64+
unfurl_links=False,
65+
unfurl_media=False,
66+
)
67+
self.assertEqual(200, response.status_code)
68+
self.assertEqual("ok", response.body)
69+
# wait to allow Slack API to edit message with attachments
70+
time.sleep(2)
71+
history = await client.conversations_history(channel=self.channel_id, limit=1)
72+
self.assertIsNotNone(history)
73+
self.assertTrue("attachments" not in history["messages"][0])
74+
75+
@async_test
76+
async def test_with_unfurls_on(self):
77+
# Slack API rate limits unfurls of unique links so test will
78+
# fail when repeated. For testing, either use a different URL
79+
# for text option or delete existing attachments in webhook channel.
80+
url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL]
81+
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
82+
webhook = AsyncWebhookClient(url)
83+
client = AsyncWebClient(token=token)
84+
# send message that does unfurl
85+
response = await webhook.send(
86+
text="<https://imgs.xkcd.com/comics/red_spiders_small.jpg|Spiders>",
87+
unfurl_links=True,
88+
unfurl_media=True,
89+
)
90+
self.assertEqual(200, response.status_code)
91+
self.assertEqual("ok", response.body)
92+
# wait to allow Slack API to edit message with attachments
93+
time.sleep(2)
94+
history = await client.conversations_history(channel=self.channel_id, limit=1)
95+
self.assertIsNotNone(history)
96+
self.assertTrue("attachments" in history["messages"][0])
97+
5298
@async_test
5399
async def test_with_blocks(self):
54100
url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL]

integration_tests/webhook/test_webhook.py

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import unittest
3+
import time
34

45
from integration_tests.env_variable_names import (
56
SLACK_SDK_TEST_INCOMING_WEBHOOK_URL,
@@ -16,7 +17,20 @@
1617

1718
class TestWebhook(unittest.TestCase):
1819
def setUp(self):
19-
pass
20+
if not hasattr(self, "channel_id"):
21+
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
22+
channel_name = os.environ[
23+
SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME
24+
].replace("#", "")
25+
client = WebClient(token=token)
26+
self.channel_id = None
27+
for resp in client.conversations_list(limit=10):
28+
for c in resp["channels"]:
29+
if c["name"] == channel_name:
30+
self.channel_id = c["id"]
31+
break
32+
if self.channel_id is not None:
33+
break
2034

2135
def tearDown(self):
2236
pass
@@ -29,24 +43,53 @@ def test_webhook(self):
2943
self.assertEqual("ok", response.body)
3044

3145
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
32-
channel_name = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_CHANNEL_NAME].replace(
33-
"#", ""
34-
)
3546
client = WebClient(token=token)
36-
channel_id = None
37-
for resp in client.conversations_list(limit=10):
38-
for c in resp["channels"]:
39-
if c["name"] == channel_name:
40-
channel_id = c["id"]
41-
break
42-
if channel_id is not None:
43-
break
44-
45-
history = client.conversations_history(channel=channel_id, limit=1)
47+
history = client.conversations_history(channel=self.channel_id, limit=1)
4648
self.assertIsNotNone(history)
4749
actual_text = history["messages"][0]["text"]
4850
self.assertEqual("Hello!", actual_text)
4951

52+
def test_with_unfurls_off(self):
53+
url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL]
54+
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
55+
webhook = WebhookClient(url)
56+
client = WebClient(token=token)
57+
# send message that does not unfurl
58+
response = webhook.send(
59+
text="<https://imgs.xkcd.com/comics/desert_golfing_2x.png|Desert Golfing>",
60+
unfurl_links=False,
61+
unfurl_media=False,
62+
)
63+
self.assertEqual(200, response.status_code)
64+
self.assertEqual("ok", response.body)
65+
# wait to allow Slack API to edit message with attachments
66+
time.sleep(2)
67+
history = client.conversations_history(channel=self.channel_id, limit=1)
68+
self.assertIsNotNone(history)
69+
self.assertTrue("attachments" not in history["messages"][0])
70+
71+
def test_with_unfurls_on(self):
72+
# Slack API rate limits unfurls of unique links so test will
73+
# fail when repeated. For testing, either use a different URL
74+
# for text option or delete existing attachments in webhook channel.
75+
url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL]
76+
token = os.environ[SLACK_SDK_TEST_BOT_TOKEN]
77+
webhook = WebhookClient(url)
78+
client = WebClient(token=token)
79+
# send message that does unfurl
80+
response = webhook.send(
81+
text="<https://imgs.xkcd.com/comics/red_spiders_small.jpg|Spiders>",
82+
unfurl_links=True,
83+
unfurl_media=True,
84+
)
85+
self.assertEqual(200, response.status_code)
86+
self.assertEqual("ok", response.body)
87+
# wait to allow Slack API to edit message with attachments
88+
time.sleep(2)
89+
history = client.conversations_history(channel=self.channel_id, limit=1)
90+
self.assertIsNotNone(history)
91+
self.assertTrue("attachments" in history["messages"][0])
92+
5093
def test_with_blocks(self):
5194
url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL]
5295
webhook = WebhookClient(url)

slack_sdk/webhook/async_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ async def send(
8787
response_type: Optional[str] = None,
8888
replace_original: Optional[bool] = None,
8989
delete_original: Optional[bool] = None,
90+
unfurl_links: Optional[bool] = None,
91+
unfurl_media: Optional[bool] = None,
9092
headers: Optional[Dict[str, str]] = None,
9193
) -> WebhookResponse:
9294
"""Performs a Slack API request and returns the result.
@@ -98,6 +100,8 @@ async def send(
98100
response_type: The type of message (either 'in_channel' or 'ephemeral')
99101
replace_original: True if you use this option for response_url requests
100102
delete_original: True if you use this option for response_url requests
103+
unfurl_links: Option to indicate whether text url should unfurl
104+
unfurl_media: Option to indicate whether media url should unfurl
101105
headers: Request headers to append only for this request
102106
103107
Returns:
@@ -113,6 +117,8 @@ async def send(
113117
"response_type": response_type,
114118
"replace_original": replace_original,
115119
"delete_original": delete_original,
120+
"unfurl_links": unfurl_links,
121+
"unfurl_media": unfurl_media,
116122
},
117123
headers=headers,
118124
)

slack_sdk/webhook/client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def send(
7777
response_type: Optional[str] = None,
7878
replace_original: Optional[bool] = None,
7979
delete_original: Optional[bool] = None,
80+
unfurl_links: Optional[bool] = None,
81+
unfurl_media: Optional[bool] = None,
8082
headers: Optional[Dict[str, str]] = None,
8183
) -> WebhookResponse:
8284
"""Performs a Slack API request and returns the result.
@@ -89,6 +91,8 @@ def send(
8991
response_type: The type of message (either 'in_channel' or 'ephemeral')
9092
replace_original: True if you use this option for response_url requests
9193
delete_original: True if you use this option for response_url requests
94+
unfurl_links: Option to indicate whether text url should unfurl
95+
unfurl_media: Option to indicate whether media url should unfurl
9296
headers: Request headers to append only for this request
9397
9498
Returns:
@@ -104,6 +108,8 @@ def send(
104108
"response_type": response_type,
105109
"replace_original": replace_original,
106110
"delete_original": delete_original,
111+
"unfurl_links": unfurl_links,
112+
"unfurl_media": unfurl_media,
107113
},
108114
headers=headers,
109115
)

slack_sdk/webhook/internal_utils.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44
from slack_sdk.web.internal_utils import (
55
_parse_web_class_objects,
66
get_user_agent,
7-
convert_bool_to_0_or_1,
87
)
98
from .webhook_response import WebhookResponse
109

1110

1211
def _build_body(original_body: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
1312
if original_body:
1413
body = {k: v for k, v in original_body.items() if v is not None}
15-
body = convert_bool_to_0_or_1(body)
1614
_parse_web_class_objects(body)
1715
return body
1816
return None

tests/webhook/test_async_webhook.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import asyncio
1+
from tests.helpers import async_test
22
import unittest
33

4-
import aiohttp
5-
64
from slack.web.classes.attachments import Attachment, AttachmentField
75
from slack.web.classes.blocks import SectionBlock, ImageBlock
86
from slack.webhook import AsyncWebhookClient, WebhookResponse
9-
from tests.helpers import async_test
107
from tests.webhook.mock_web_api_server import (
118
cleanup_mock_web_api_server,
129
setup_mock_web_api_server,
@@ -31,6 +28,17 @@ async def test_send(self):
3128
resp = await client.send(text="hello!", response_type="in_channel")
3229
self.assertEqual("ok", resp.body)
3330

31+
@async_test
32+
async def test_send_with_url_unfurl_opts_issue_1045(self):
33+
client = AsyncWebhookClient("http://localhost:8888")
34+
resp: WebhookResponse = await client.send(
35+
text="<https://imgs.xkcd.com/comics/1991_and_2021_2x.png|XKCD>",
36+
unfurl_links=False,
37+
unfurl_media=False,
38+
)
39+
self.assertEqual(200, resp.status_code)
40+
self.assertEqual("ok", resp.body)
41+
3442
@async_test
3543
async def test_send_blocks(self):
3644
client = AsyncWebhookClient("http://localhost:8888")

tests/webhook/test_webhook.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ def test_send(self):
2828
resp = client.send(text="hello!", response_type="in_channel")
2929
self.assertEqual("ok", resp.body)
3030

31+
def test_send_with_url_unfurl_opts_issue_1045(self):
32+
client = WebhookClient("http://localhost:8888")
33+
resp: WebhookResponse = client.send(
34+
text="<https://imgs.xkcd.com/comics/1991_and_2021_2x.png|XKCD>",
35+
unfurl_links=False,
36+
unfurl_media=False,
37+
)
38+
self.assertEqual(200, resp.status_code)
39+
self.assertEqual("ok", resp.body)
40+
3141
def test_send_blocks(self):
3242
client = WebhookClient("http://localhost:8888")
3343

0 commit comments

Comments
 (0)