Skip to content

Commit 16a55ab

Browse files
committed
version 1.2.0b1
1 parent 51af9e0 commit 16a55ab

File tree

13 files changed

+299
-39
lines changed

13 files changed

+299
-39
lines changed

examples/socket_mode.py

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
# ------------------------------------------------
77

88
import logging
9+
10+
logging.basicConfig(level=logging.DEBUG)
11+
912
import os
1013

1114
from slack_bolt import App
12-
from slack_bolt.adapter.socket_mode.websocket_client import SocketModeHandler
15+
from slack_bolt.adapter.socket_mode import SocketModeHandler
1316

1417
# Install the Slack app and get xoxb- token in advance
1518
app = App(token=os.environ["SLACK_BOT_TOKEN"])
@@ -26,14 +29,74 @@ def event_test(event, say):
2629
say(f"Hi there, <@{event['user']}>!")
2730

2831

29-
@app.shortcut("socket-mode")
30-
def global_shortcut(ack):
32+
def ack_shortcut(ack):
3133
ack()
3234

3335

34-
if __name__ == "__main__":
35-
logging.basicConfig(level=logging.DEBUG)
36+
def open_modal(body, client):
37+
client.views_open(
38+
trigger_id=body["trigger_id"],
39+
view={
40+
"type": "modal",
41+
"callback_id": "socket_modal_submission",
42+
"submit": {"type": "plain_text", "text": "Submit",},
43+
"close": {"type": "plain_text", "text": "Cancel",},
44+
"title": {"type": "plain_text", "text": "Socket Modal",},
45+
"blocks": [
46+
{
47+
"type": "input",
48+
"block_id": "q1",
49+
"label": {"type": "plain_text", "text": "Write anything here!",},
50+
"element": {"action_id": "feedback", "type": "plain_text_input",},
51+
},
52+
{
53+
"type": "input",
54+
"block_id": "q2",
55+
"label": {
56+
"type": "plain_text",
57+
"text": "Can you tell us your favorites?",
58+
},
59+
"element": {
60+
"type": "external_select",
61+
"action_id": "favorite-animal",
62+
"min_query_length": 0,
63+
"placeholder": {
64+
"type": "plain_text",
65+
"text": "Select your favorites",
66+
},
67+
},
68+
},
69+
],
70+
},
71+
)
72+
73+
74+
app.shortcut("socket-mode")(ack=ack_shortcut, lazy=[open_modal])
75+
76+
77+
all_options = [
78+
{"text": {"type": "plain_text", "text": ":cat: Cat"}, "value": "cat",},
79+
{"text": {"type": "plain_text", "text": ":dog: Dog"}, "value": "dog",},
80+
{"text": {"type": "plain_text", "text": ":bear: Bear"}, "value": "bear",},
81+
]
3682

83+
84+
@app.options("favorite-animal")
85+
def external_data_source_handler(ack, body):
86+
keyword = body.get("value")
87+
if keyword is not None and len(keyword) > 0:
88+
options = [o for o in all_options if keyword in o["text"]["text"]]
89+
ack(options=options)
90+
else:
91+
ack(options=all_options)
92+
93+
94+
@app.view("socket_modal_submission")
95+
def submission(ack):
96+
ack()
97+
98+
99+
if __name__ == "__main__":
37100
# export SLACK_APP_TOKEN=xapp-***
38101
# export SLACK_BOT_TOKEN=xoxb-***
39102
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()

examples/socket_mode_async.py

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
# ------------------------------------------------
88

99
import logging
10+
11+
logging.basicConfig(level=logging.DEBUG)
12+
1013
import os
1114

1215
from slack_bolt.app.async_app import AsyncApp
13-
from slack_bolt.adapter.socket_mode.aiohttp import AsyncSocketModeHandler
16+
from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler
1417

1518
# Install the Slack app and get xoxb- token in advance
1619
app = AsyncApp(token=os.environ["SLACK_BOT_TOKEN"])
@@ -27,20 +30,83 @@ async def event_test(event, say):
2730
await say(f"Hi there, <@{event['user']}>!")
2831

2932

30-
@app.shortcut("socket-mode")
31-
async def global_shortcut(ack):
33+
async def ack_shortcut(ack):
34+
await ack()
35+
36+
37+
async def open_modal(body, client):
38+
await client.views_open(
39+
trigger_id=body["trigger_id"],
40+
view={
41+
"type": "modal",
42+
"callback_id": "socket_modal_submission",
43+
"submit": {"type": "plain_text", "text": "Submit",},
44+
"close": {"type": "plain_text", "text": "Cancel",},
45+
"title": {"type": "plain_text", "text": "Socket Modal",},
46+
"blocks": [
47+
{
48+
"type": "input",
49+
"block_id": "q1",
50+
"label": {"type": "plain_text", "text": "Write anything here!",},
51+
"element": {"action_id": "feedback", "type": "plain_text_input",},
52+
},
53+
{
54+
"type": "input",
55+
"block_id": "q2",
56+
"label": {
57+
"type": "plain_text",
58+
"text": "Can you tell us your favorites?",
59+
},
60+
"element": {
61+
"type": "external_select",
62+
"action_id": "favorite-animal",
63+
"min_query_length": 0,
64+
"placeholder": {
65+
"type": "plain_text",
66+
"text": "Select your favorites",
67+
},
68+
},
69+
},
70+
],
71+
},
72+
)
73+
74+
75+
app.shortcut("socket-mode")(ack=ack_shortcut, lazy=[open_modal])
76+
77+
78+
all_options = [
79+
{"text": {"type": "plain_text", "text": ":cat: Cat"}, "value": "cat",},
80+
{"text": {"type": "plain_text", "text": ":dog: Dog"}, "value": "dog",},
81+
{"text": {"type": "plain_text", "text": ":bear: Bear"}, "value": "bear",},
82+
]
83+
84+
85+
@app.options("favorite-animal")
86+
async def external_data_source_handler(ack, body):
87+
keyword = body.get("value")
88+
if keyword is not None and len(keyword) > 0:
89+
options = [o for o in all_options if keyword in o["text"]["text"]]
90+
await ack(options=options)
91+
else:
92+
await ack(options=all_options)
93+
94+
95+
@app.view("socket_modal_submission")
96+
async def submission(ack):
3297
await ack()
3398

3499

35100
# export SLACK_APP_TOKEN=xapp-***
36101
# export SLACK_BOT_TOKEN=xoxb-***
37102

103+
38104
async def main():
39105
handler = AsyncSocketModeHandler(app, os.environ["SLACK_APP_TOKEN"])
40106
await handler.start_async()
41107

42108

43109
if __name__ == "__main__":
44-
logging.basicConfig(level=logging.DEBUG)
45110
import asyncio
111+
46112
asyncio.run(main())

examples/socket_mode_oauth.py

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@
66
# ------------------------------------------------
77

88
import logging
9+
10+
logging.basicConfig(level=logging.DEBUG)
11+
912
import os
1013
from slack_bolt.app import App
1114
from slack_bolt.oauth.oauth_settings import OAuthSettings
12-
from slack_bolt.adapter.socket_mode.websocket_client import SocketModeHandler
15+
from slack_bolt.adapter.socket_mode import SocketModeHandler
1316

1417
app = App(
1518
signing_secret=os.environ["SLACK_SIGNING_SECRET"],
1619
oauth_settings=OAuthSettings(
1720
client_id=os.environ["SLACK_CLIENT_ID"],
1821
client_secret=os.environ["SLACK_CLIENT_SECRET"],
1922
scopes=os.environ["SLACK_SCOPES"].split(","),
20-
)
23+
),
2124
)
2225

2326

@@ -32,13 +35,74 @@ def event_test(event, say):
3235
say(f"Hi there, <@{event['user']}>!")
3336

3437

35-
@app.shortcut("socket-mode")
36-
def global_shortcut(ack):
38+
def ack_shortcut(ack):
39+
ack()
40+
41+
42+
def open_modal(body, client):
43+
client.views_open(
44+
trigger_id=body["trigger_id"],
45+
view={
46+
"type": "modal",
47+
"callback_id": "socket_modal_submission",
48+
"submit": {"type": "plain_text", "text": "Submit",},
49+
"close": {"type": "plain_text", "text": "Cancel",},
50+
"title": {"type": "plain_text", "text": "Socket Modal",},
51+
"blocks": [
52+
{
53+
"type": "input",
54+
"block_id": "q1",
55+
"label": {"type": "plain_text", "text": "Write anything here!",},
56+
"element": {"action_id": "feedback", "type": "plain_text_input",},
57+
},
58+
{
59+
"type": "input",
60+
"block_id": "q2",
61+
"label": {
62+
"type": "plain_text",
63+
"text": "Can you tell us your favorites?",
64+
},
65+
"element": {
66+
"type": "external_select",
67+
"action_id": "favorite-animal",
68+
"min_query_length": 0,
69+
"placeholder": {
70+
"type": "plain_text",
71+
"text": "Select your favorites",
72+
},
73+
},
74+
},
75+
],
76+
},
77+
)
78+
79+
80+
app.shortcut("socket-mode")(ack=ack_shortcut, lazy=[open_modal])
81+
82+
83+
all_options = [
84+
{"text": {"type": "plain_text", "text": ":cat: Cat"}, "value": "cat",},
85+
{"text": {"type": "plain_text", "text": ":dog: Dog"}, "value": "dog",},
86+
{"text": {"type": "plain_text", "text": ":bear: Bear"}, "value": "bear",},
87+
]
88+
89+
90+
@app.options("favorite-animal")
91+
def external_data_source_handler(ack, body):
92+
keyword = body.get("value")
93+
if keyword is not None and len(keyword) > 0:
94+
options = [o for o in all_options if keyword in o["text"]["text"]]
95+
ack(options=options)
96+
else:
97+
ack(options=all_options)
98+
99+
100+
@app.view("socket_modal_submission")
101+
def submission(ack):
37102
ack()
38103

39104

40105
if __name__ == "__main__":
41-
logging.basicConfig(level=logging.DEBUG)
42106
SocketModeHandler(app, os.environ.get("SLACK_APP_TOKEN")).connect()
43107
app.start()
44108

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Don't add async module imports here
2+
from .builtin import SocketModeHandler # noqa

slack_bolt/adapter/socket_mode/aiohttp/__init__.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717

1818

1919
class SocketModeHandler(AsyncBaseSocketModeHandler):
20-
app: App
20+
app: App # type: ignore
2121
app_token: str
2222
client: SocketModeClient
2323

24-
def __init__(
25-
self, app: App, app_token: Optional[str] = None,
24+
def __init__( # type: ignore
25+
self,
26+
app: App, # type: ignore
27+
app_token: Optional[str] = None,
2628
):
2729
self.app = app
2830
self.app_token = app_token or os.environ["SLACK_APP_TOKEN"]
@@ -36,12 +38,14 @@ async def handle(self, client: SocketModeClient, req: SocketModeRequest) -> None
3638

3739

3840
class AsyncSocketModeHandler(AsyncBaseSocketModeHandler):
39-
app: AsyncApp
41+
app: AsyncApp # type: ignore
4042
app_token: str
4143
client: SocketModeClient
4244

43-
def __init__(
44-
self, app: AsyncApp, app_token: Optional[str] = None,
45+
def __init__( # type: ignore
46+
self,
47+
app: AsyncApp, # type: ignore
48+
app_token: Optional[str] = None,
4549
):
4650
self.app = app
4751
self.app_token = app_token or os.environ["SLACK_APP_TOKEN"]

slack_bolt/adapter/socket_mode/async_base_handler.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import asyncio
22
import logging
3+
from typing import Union
34

45
from slack_sdk.socket_mode.async_client import AsyncBaseSocketModeClient
56
from slack_sdk.socket_mode.request import SocketModeRequest
67

8+
from slack_bolt import App
9+
from slack_bolt.app.async_app import AsyncApp
10+
711

812
class AsyncBaseSocketModeHandler:
13+
app: Union[App, AsyncApp] # type: ignore
914
client: AsyncBaseSocketModeClient
1015

11-
async def handle(self, client: AsyncBaseSocketModeClient, req: SocketModeRequest) -> None:
16+
async def handle(
17+
self, client: AsyncBaseSocketModeClient, req: SocketModeRequest
18+
) -> None:
1219
raise NotImplementedError()
1320

1421
async def connect_async(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .aiohttp import AsyncSocketModeHandler # noqa

slack_bolt/adapter/socket_mode/async_internals.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import logging
23
from time import time
34

@@ -10,7 +11,7 @@
1011
from slack_bolt.response import BoltResponse
1112

1213

13-
async def run_async_bolt_app(app: AsyncApp, req: SocketModeRequest):
14+
async def run_async_bolt_app(app: AsyncApp, req: SocketModeRequest): # type: ignore
1415
bolt_req: AsyncBoltRequest = AsyncBoltRequest(mode="socket_mode", body=req.payload)
1516
bolt_resp: BoltResponse = await app.async_dispatch(bolt_req)
1617
return bolt_resp
@@ -20,16 +21,18 @@ async def send_async_response(
2021
client: AsyncBaseSocketModeClient,
2122
req: SocketModeRequest,
2223
bolt_resp: BoltResponse,
23-
start_time: int,
24+
start_time: float,
2425
):
2526
if bolt_resp.status == 200:
27+
content_type = bolt_resp.headers.get("content-type", [""])[0]
2628
if bolt_resp.body is None or len(bolt_resp.body) == 0:
2729
await client.send_socket_mode_response(
2830
SocketModeResponse(envelope_id=req.envelope_id)
2931
)
30-
elif bolt_resp.body.startswith("{"):
32+
elif content_type.startswith("application/json"):
33+
dict_body = json.loads(bolt_resp.body)
3134
await client.send_socket_mode_response(
32-
SocketModeResponse(envelope_id=req.envelope_id, payload=bolt_resp.body,)
35+
SocketModeResponse(envelope_id=req.envelope_id, payload=dict_body)
3336
)
3437
else:
3538
await client.send_socket_mode_response(

0 commit comments

Comments
 (0)