Skip to content

Commit dec80e3

Browse files
committed
Fix #198 bug where str subtype constraint does not work
1 parent c18e0d8 commit dec80e3

File tree

3 files changed

+322
-0
lines changed

3 files changed

+322
-0
lines changed

slack_bolt/listener_matcher/builtins.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ def func(body: Dict[str, Any]) -> bool:
102102
if expected_subtype is None:
103103
# "subtype" in constraints is intentionally None for this pattern
104104
return "subtype" not in event
105+
elif isinstance(expected_subtype, (str, Pattern)):
106+
return "subtype" in event and _matches(
107+
expected_subtype, event["subtype"]
108+
)
105109
elif isinstance(expected_subtype, Sequence):
106110
subtypes: Sequence[
107111
Optional[Union[str, Pattern]]

tests/scenario_tests/test_events.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import re
23
from time import time, sleep
34

45
from slack_sdk.signature import SignatureVerifier
@@ -396,3 +397,159 @@ def handler2(say: Say):
396397
assert self.mock_received_requests["/auth.test"] == 1
397398
sleep(1) # wait a bit after auto ack()
398399
assert self.mock_received_requests["/chat.postMessage"] == 2
400+
401+
message_file_share_body = {
402+
"token": "verification-token",
403+
"team_id": "T111",
404+
"api_app_id": "A111",
405+
"event": {
406+
"type": "message",
407+
"text": "Here is your file!",
408+
"files": [
409+
{
410+
"id": "F111",
411+
"created": 1610493713,
412+
"timestamp": 1610493713,
413+
"name": "test.png",
414+
"title": "test.png",
415+
"mimetype": "image/png",
416+
"filetype": "png",
417+
"pretty_type": "PNG",
418+
"user": "U111",
419+
"editable": False,
420+
"size": 42706,
421+
"mode": "hosted",
422+
"is_external": False,
423+
"external_type": "",
424+
"is_public": False,
425+
"public_url_shared": False,
426+
"display_as_bot": False,
427+
"username": "",
428+
"url_private": "https://files.slack.com/files-pri/T111-F111/test.png",
429+
"url_private_download": "https://files.slack.com/files-pri/T111-F111/download/test.png",
430+
"thumb_64": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_64.png",
431+
"thumb_80": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_80.png",
432+
"thumb_360": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_360.png",
433+
"thumb_360_w": 358,
434+
"thumb_360_h": 360,
435+
"thumb_480": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_480.png",
436+
"thumb_480_w": 477,
437+
"thumb_480_h": 480,
438+
"thumb_160": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_160.png",
439+
"thumb_720": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_720.png",
440+
"thumb_720_w": 716,
441+
"thumb_720_h": 720,
442+
"original_w": 736,
443+
"original_h": 740,
444+
"thumb_tiny": "xxx",
445+
"permalink": "https://xxx.slack.com/files/U111/F111/test.png",
446+
"permalink_public": "https://slack-files.com/T111-F111-3e534ef8ca",
447+
"has_rich_preview": False,
448+
}
449+
],
450+
"upload": False,
451+
"blocks": [
452+
{
453+
"type": "rich_text",
454+
"block_id": "gvM",
455+
"elements": [
456+
{
457+
"type": "rich_text_section",
458+
"elements": [
459+
{"type": "text", "text": "Here is your file!"}
460+
],
461+
}
462+
],
463+
}
464+
],
465+
"user": "U111",
466+
"display_as_bot": False,
467+
"ts": "1610493715.001000",
468+
"channel": "G111",
469+
"subtype": "file_share",
470+
"event_ts": "1610493715.001000",
471+
"channel_type": "group",
472+
},
473+
"type": "event_callback",
474+
"event_id": "Ev111",
475+
"event_time": 1610493715,
476+
"authorizations": [
477+
{
478+
"enterprise_id": None,
479+
"team_id": "T111",
480+
"user_id": "U111",
481+
"is_bot": True,
482+
"is_enterprise_install": False,
483+
}
484+
],
485+
"is_ext_shared_channel": False,
486+
"event_context": "1-message-T111-G111",
487+
}
488+
489+
def test_message_subtypes_0(self):
490+
app = App(client=self.web_client, signing_secret=self.signing_secret)
491+
app._client = WebClient(
492+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
493+
)
494+
495+
@app.event({"type": "message", "subtype": "file_share"})
496+
def handler1(event):
497+
assert event["subtype"] == "file_share"
498+
499+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
500+
request: BoltRequest = BoltRequest(
501+
body=body, headers=self.build_headers(timestamp, body)
502+
)
503+
response = app.dispatch(request)
504+
assert response.status == 200
505+
506+
def test_message_subtypes_1(self):
507+
app = App(client=self.web_client, signing_secret=self.signing_secret)
508+
app._client = WebClient(
509+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
510+
)
511+
512+
@app.event({"type": "message", "subtype": re.compile("file_.+")})
513+
def handler1(event):
514+
assert event["subtype"] == "file_share"
515+
516+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
517+
request: BoltRequest = BoltRequest(
518+
body=body, headers=self.build_headers(timestamp, body)
519+
)
520+
response = app.dispatch(request)
521+
assert response.status == 200
522+
523+
def test_message_subtypes_2(self):
524+
app = App(client=self.web_client, signing_secret=self.signing_secret)
525+
app._client = WebClient(
526+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
527+
)
528+
529+
@app.event({"type": "message", "subtype": ["file_share"]})
530+
def handler1(event):
531+
assert event["subtype"] == "file_share"
532+
533+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
534+
request: BoltRequest = BoltRequest(
535+
body=body, headers=self.build_headers(timestamp, body)
536+
)
537+
response = app.dispatch(request)
538+
assert response.status == 200
539+
540+
def test_message_subtypes_3(self):
541+
app = App(client=self.web_client, signing_secret=self.signing_secret)
542+
app._client = WebClient(
543+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
544+
)
545+
546+
@app.event("message")
547+
def handler1(event):
548+
assert event["subtype"] == "file_share"
549+
550+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
551+
request: BoltRequest = BoltRequest(
552+
body=body, headers=self.build_headers(timestamp, body)
553+
)
554+
response = app.dispatch(request)
555+
assert response.status == 200

tests/scenario_tests_async/test_events.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import json
3+
import re
34
from random import random
45
from time import time
56

@@ -400,6 +401,166 @@ async def handler2(say: AsyncSay):
400401
await asyncio.sleep(1) # wait a bit after auto ack()
401402
assert self.mock_received_requests["/chat.postMessage"] == 2
402403

404+
message_file_share_body = {
405+
"token": "verification-token",
406+
"team_id": "T111",
407+
"api_app_id": "A111",
408+
"event": {
409+
"type": "message",
410+
"text": "Here is your file!",
411+
"files": [
412+
{
413+
"id": "F111",
414+
"created": 1610493713,
415+
"timestamp": 1610493713,
416+
"name": "test.png",
417+
"title": "test.png",
418+
"mimetype": "image/png",
419+
"filetype": "png",
420+
"pretty_type": "PNG",
421+
"user": "U111",
422+
"editable": False,
423+
"size": 42706,
424+
"mode": "hosted",
425+
"is_external": False,
426+
"external_type": "",
427+
"is_public": False,
428+
"public_url_shared": False,
429+
"display_as_bot": False,
430+
"username": "",
431+
"url_private": "https://files.slack.com/files-pri/T111-F111/test.png",
432+
"url_private_download": "https://files.slack.com/files-pri/T111-F111/download/test.png",
433+
"thumb_64": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_64.png",
434+
"thumb_80": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_80.png",
435+
"thumb_360": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_360.png",
436+
"thumb_360_w": 358,
437+
"thumb_360_h": 360,
438+
"thumb_480": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_480.png",
439+
"thumb_480_w": 477,
440+
"thumb_480_h": 480,
441+
"thumb_160": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_160.png",
442+
"thumb_720": "https://files.slack.com/files-tmb/T111-F111-8d3f9a6d4b/test_720.png",
443+
"thumb_720_w": 716,
444+
"thumb_720_h": 720,
445+
"original_w": 736,
446+
"original_h": 740,
447+
"thumb_tiny": "xxx",
448+
"permalink": "https://xxx.slack.com/files/U111/F111/test.png",
449+
"permalink_public": "https://slack-files.com/T111-F111-3e534ef8ca",
450+
"has_rich_preview": False,
451+
}
452+
],
453+
"upload": False,
454+
"blocks": [
455+
{
456+
"type": "rich_text",
457+
"block_id": "gvM",
458+
"elements": [
459+
{
460+
"type": "rich_text_section",
461+
"elements": [
462+
{"type": "text", "text": "Here is your file!"}
463+
],
464+
}
465+
],
466+
}
467+
],
468+
"user": "U111",
469+
"display_as_bot": False,
470+
"ts": "1610493715.001000",
471+
"channel": "G111",
472+
"subtype": "file_share",
473+
"event_ts": "1610493715.001000",
474+
"channel_type": "group",
475+
},
476+
"type": "event_callback",
477+
"event_id": "Ev111",
478+
"event_time": 1610493715,
479+
"authorizations": [
480+
{
481+
"enterprise_id": None,
482+
"team_id": "T111",
483+
"user_id": "U111",
484+
"is_bot": True,
485+
"is_enterprise_install": False,
486+
}
487+
],
488+
"is_ext_shared_channel": False,
489+
"event_context": "1-message-T111-G111",
490+
}
491+
492+
@pytest.mark.asyncio
493+
async def test_message_subtypes_0(self):
494+
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
495+
app._client = AsyncWebClient(
496+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
497+
)
498+
499+
@app.event({"type": "message", "subtype": "file_share"})
500+
async def handler1(event):
501+
assert event["subtype"] == "file_share"
502+
503+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
504+
request: AsyncBoltRequest = AsyncBoltRequest(
505+
body=body, headers=self.build_headers(timestamp, body)
506+
)
507+
response = await app.async_dispatch(request)
508+
assert response.status == 200
509+
510+
@pytest.mark.asyncio
511+
async def test_message_subtypes_1(self):
512+
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
513+
app._client = AsyncWebClient(
514+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
515+
)
516+
517+
@app.event({"type": "message", "subtype": re.compile("file_.+")})
518+
async def handler1(event):
519+
assert event["subtype"] == "file_share"
520+
521+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
522+
request: AsyncBoltRequest = AsyncBoltRequest(
523+
body=body, headers=self.build_headers(timestamp, body)
524+
)
525+
response = await app.async_dispatch(request)
526+
assert response.status == 200
527+
528+
@pytest.mark.asyncio
529+
async def test_message_subtypes_2(self):
530+
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
531+
app._client = AsyncWebClient(
532+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
533+
)
534+
535+
@app.event({"type": "message", "subtype": ["file_share"]})
536+
async def handler1(event):
537+
assert event["subtype"] == "file_share"
538+
539+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
540+
request: AsyncBoltRequest = AsyncBoltRequest(
541+
body=body, headers=self.build_headers(timestamp, body)
542+
)
543+
response = await app.async_dispatch(request)
544+
assert response.status == 200
545+
546+
@pytest.mark.asyncio
547+
async def test_message_subtypes_3(self):
548+
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
549+
app._client = AsyncWebClient(
550+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
551+
)
552+
553+
@app.event("message")
554+
async def handler1(event):
555+
assert event["subtype"] == "file_share"
556+
557+
timestamp, body = str(int(time())), json.dumps(self.message_file_share_body)
558+
request: AsyncBoltRequest = AsyncBoltRequest(
559+
body=body, headers=self.build_headers(timestamp, body)
560+
)
561+
response = await app.async_dispatch(request)
562+
assert response.status == 200
563+
403564

404565
app_mention_body = {
405566
"token": "verification_token",

0 commit comments

Comments
 (0)