Skip to content

Commit 5dacf44

Browse files
authored
Merge branch 'main' into dependabot/pip/asgiref-gte-3.12.1-and-lt-4
2 parents 8d842d8 + 698687c commit 5dacf44

6 files changed

Lines changed: 72 additions & 22 deletions

File tree

‎docs/english/concepts/custom-steps-dynamic-options.md‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,13 @@ The `inputs` attribute defines the parameters to be passed as inputs to the step
8888

8989
The following format can be used to reference any input parameter defined by the step: `{{input_parameters.<PARAMETER_NAME>}}`.
9090

91-
In addition, the `{{client.query}}` parameter can be used as a placeholder for an input value. The `{{client.builder_context}}` parameter will inject the [`slack#/types/user_context`](/tools/deno-slack-sdk/reference/slack-types/#usercontext) of the user building the workflow as the value to the input parameter.
91+
In addition, the `{{client.query}}` parameter can be used as a placeholder for an input value. The `{{client.builder_context}}` parameter will inject the [`slack#/types/user_context`](/reference/types/user_context-type) of the user building the workflow as the value to the input parameter.
9292

9393
### Types of dynamic options UIs {#dynamic-option-UIs}
9494

9595
The above example demonstrates one possible UI to be rendered for builders: a single-select drop-down menu of dynamic options. However, dynamic options in Workflow Builder can be rendered in one of two ways: as a drop-down menu (single-select or multi-select), or as a set of fields.
9696

97-
The type is dictated by the output parameter of the custom step used as a dynamic option. In order to use a custom step in a dynamic option context, its output must adhere to a defined interface, that is, it must have an `options` parameter of type [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select) or [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field), as shown in the following code snippet.
97+
The type is dictated by the output parameter of the custom step used as a dynamic option. In order to use a custom step in a dynamic option context, its output must adhere to a defined interface, that is, it must have an `options` parameter of type [`options_select`](/reference/types/options_select-type) or [`options_field`](/reference/types/options_field-type), as shown in the following code snippet.
9898

9999
```js
100100
"output_parameters": {
@@ -109,9 +109,9 @@ The type is dictated by the output parameter of the custom step used as a dynami
109109

110110
#### Drop-down menus {#drop-down}
111111

112-
Your dynamic input parameter can be rendered as a drop-down menu, which will use the options obtained from a custom step with an `options` output parameter of the type [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select).
112+
Your dynamic input parameter can be rendered as a drop-down menu, which will use the options obtained from a custom step with an `options` output parameter of the type [`options_select`](/reference/types/options_select-type).
113113

114-
The drop-down menu UI component can be rendered in two ways: single-select, or multi-select. To render the dynamic input as a single-select menu, the input parameter defining the dynamic option must be of the type [`string`](/tools/deno-slack-sdk/reference/slack-types#string).
114+
The drop-down menu UI component can be rendered in two ways: single-select, or multi-select. To render the dynamic input as a single-select menu, the input parameter defining the dynamic option must be of the type [`string`](/reference/types/string-type).
115115

116116
```js
117117
"step-with-dynamic-input": {
@@ -133,7 +133,7 @@ The drop-down menu UI component can be rendered in two ways: single-select, or m
133133
}
134134
```
135135

136-
To render the dynamic input as a multi-select menu, the input parameter defining the dynamic option must be of the type [`array`](/tools/deno-slack-sdk/reference/slack-types#array), and its `items` must be of type [`string`](/tools/deno-slack-sdk/reference/slack-types#string).
136+
To render the dynamic input as a multi-select menu, the input parameter defining the dynamic option must be of the type [`array`](/reference/types/array-type), and its `items` must be of type [`string`](/reference/types/string-type).
137137

138138
```js
139139
"step-with-dynamic-input": {
@@ -159,9 +159,9 @@ To render the dynamic input as a multi-select menu, the input parameter defining
159159

160160
#### Fields {#fields}
161161

162-
In the code snippet below, the input parameter is rendered as a set of fields with keys and values. The option fields are obtained from a custom step with an `options` output parameter of type [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field).
162+
In the code snippet below, the input parameter is rendered as a set of fields with keys and values. The option fields are obtained from a custom step with an `options` output parameter of type [`options_field`](/reference/types/options_field-type).
163163

164-
The input parameter that defines the dynamic option must be of type [`object`](/tools/deno-slack-sdk/reference/slack-types#object), as the completed set of fields in Workflow Builder will be passed to the custom step as an [untyped object](/tools/deno-slack-sdk/reference/slack-types#untyped-object) during workflow execution.
164+
The input parameter that defines the dynamic option must be of type [`object`](/reference/types/object-type), as the completed set of fields in Workflow Builder will be passed to the custom step as an [untyped object](/reference/types/object-type#untyped-object) during workflow execution.
165165

166166
```js
167167
"test-field-dynamic-options": {
@@ -185,15 +185,15 @@ The input parameter that defines the dynamic option must be of type [`object`](/
185185

186186
### Dynamic option types {#dynamic-option-types}
187187

188-
As mentioned earlier, in order to use a custom step as a dynamic option, its output must adhere to a defined interface: it must have an `options` output parameter of the type either [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select) or [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field).
188+
As mentioned earlier, in order to use a custom step as a dynamic option, its output must adhere to a defined interface: it must have an `options` output parameter of the type either [`options_select`](/reference/types/options_select-type) or [`options_field`](/reference/types/options_field-type).
189189

190-
To take a look at these in more detail, refer to our [Options Slack type](/tools/deno-slack-sdk/reference/slack-types#options) documentation.
190+
To take a look at these in more detail, refer to our [Options Slack type](/reference/types) documentation.
191191

192192
## Dynamic options handler {#dynamic-option-handler}
193193

194194
Each custom step defined in the manifest needs a corresponding handler in your Slack app. Although implemented similarly to existing function execution event handlers, there are two key differences between regular custom step invocations and those used for dynamic options:
195195

196-
* The custom step must have an `options` output parameter that is of type [`options_select`](/tools/deno-slack-sdk/reference/slack-types#options_select) or [`options_field`](/tools/deno-slack-sdk/reference/slack-types#options_field).
196+
* The custom step must have an `options` output parameter that is of type [`options_select`](/reference/types/options_select-type) or [`options_field`](/reference/types/options_field-type).
197197
* The [`function_executed`](/reference/events/function_executed) event must be handled synchronously. This optimizes the response time of returned dynamic options and provides a crisp builder experience.
198198

199199
### Asynchronous event handling {#async}

‎docs/english/tutorial/ai-chatbot/ai-chatbot.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ To test this, leave the channel you just invited Bolty to and rejoin it. This wi
195195

196196
![Channel summary](7.png)
197197

198-
The central part of this functionality is shown in the following code snippet. Note the use of the [`user_context`](/tools/deno-slack-sdk/reference/slack-types#usercontext) object, a Slack type that represents the user who is interacting with our workflow, as well as the `history` of the channel that will be summarized, which includes the ten most recent messages.
198+
The central part of this functionality is shown in the following code snippet. Note the use of the [`user_context`](/reference/types/user_context-type) object, a Slack type that represents the user who is interacting with our workflow, as well as the `history` of the channel that will be summarized, which includes the ten most recent messages.
199199

200200
```python
201201
from ai.providers import get_provider_response

‎docs/japanese/concepts/updating-pushing-views.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
**`views_push`**
1010

11-
既存のモーダルの上に新しいモーダルをスタックのように追加する場合は、組み込みのクライアントで `views_push` API を呼び出します。この API 呼び出しでは、有効な `trigger_id` と新しい[ビューのペイロード](/reference/interaction-payloads/view-interactions-payload/#view_submission)を指定します。`views_push` の引数は [モーダルの開始](#creating-modals) と同じです。モーダルを開いた後、このモーダルのスタックに追加できるモーダルビューは 2 つまでです。
11+
既存のモーダルの上に新しいモーダルをスタックのように追加する場合は、組み込みのクライアントで `views_push` API を呼び出します。この API 呼び出しでは、有効な `trigger_id` と新しい[ビューのペイロード](/reference/interaction-payloads/view-interactions-payload/#view_submission)を指定します。`views_push` の引数は [モーダルの開始](/tools/bolt-python/ja-jp/concepts/opening-modals) と同じです。モーダルを開いた後、このモーダルのスタックに追加できるモーダルビューは 2 つまでです。
1212

1313
モーダルの更新と多重表示に関する詳細は、[API ドキュメント](/surfaces/modals)を参照してください。
1414

‎requirements/adapter_dev.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@ tornado>=6.5.8,<7; python_version >= "3.9"
7777
# Note: Socket Mode 3rd party implementation
7878
websocket_client>=1.2.3,<1.9; python_version < "3.9"
7979
websocket_client>=1.9.0,<1.9.1; python_version >= "3.9" and python_version < "3.10"
80-
websocket_client>=1.9.1,<2; python_version >= "3.10"
80+
websocket_client>=1.9.2,<2; python_version >= "3.10"

‎slack_bolt/adapter/aws_lambda/handler.py‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,22 @@ def handle(self, event, context):
7171

7272

7373
def to_bolt_request(event) -> BoltRequest:
74-
body = event.get("body", "")
75-
if event["isBase64Encoded"]:
74+
body = event.get("body") or ""
75+
if event.get("isBase64Encoded") is True and body:
7676
body = base64.b64decode(body).decode("utf-8")
77-
cookies: Sequence[str] = event.get("cookies", [])
78-
if cookies is None or len(cookies) == 0:
77+
cookies: Sequence[str] = event.get("cookies") or []
78+
if len(cookies) == 0:
7979
# In the case of format v1
80-
multiValueHeaders = event.get("multiValueHeaders", {})
81-
cookies = multiValueHeaders.get("cookie", [])
80+
multiValueHeaders = event.get("multiValueHeaders") or {}
81+
cookies = multiValueHeaders.get("cookie") or []
8282
if len(cookies) == 0:
8383
# Try using uppercase
84-
cookies = multiValueHeaders.get("Cookie", [])
85-
headers = event.get("headers", {})
84+
cookies = multiValueHeaders.get("Cookie") or []
85+
headers = dict(event.get("headers") or {})
8686
headers["cookie"] = cookies
8787
return BoltRequest(
8888
body=body,
89-
query=event.get("queryStringParameters", {}),
89+
query=event.get("queryStringParameters") or {},
9090
headers=headers,
9191
)
9292

‎tests/adapter_tests/aws/test_aws_lambda.py‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import base64
12
import json
23
from time import time
34
from urllib.parse import quote
@@ -70,6 +71,55 @@ def test_not_found(self):
7071
response = not_found()
7172
assert response["statusCode"] == 404
7273

74+
def test_null_fields_in_api_gateway_event(self):
75+
app = App(client=self.web_client, signing_secret=self.signing_secret)
76+
event = {
77+
"httpMethod": "POST",
78+
"requestContext": {"httpMethod": "POST"},
79+
"headers": None,
80+
"multiValueHeaders": None,
81+
"queryStringParameters": None,
82+
"body": "{}",
83+
"isBase64Encoded": False,
84+
}
85+
response = SlackRequestHandler(app).handle(event, self.context)
86+
assert response["statusCode"] == 401
87+
assert event["headers"] is None
88+
89+
def test_missing_is_base64_encoded_and_null_body(self):
90+
app = App(client=self.web_client, signing_secret=self.signing_secret)
91+
event = {"requestContext": {"http": {"method": "POST"}}, "headers": {}, "body": "{}"}
92+
assert SlackRequestHandler(app).handle(event, self.context)["statusCode"] == 401
93+
event = {"requestContext": {"http": {"method": "POST"}}, "headers": {}, "body": None, "isBase64Encoded": True}
94+
assert SlackRequestHandler(app).handle(event, self.context)["statusCode"] == 401
95+
96+
def test_base64_encoded_body(self):
97+
app = App(client=self.web_client, signing_secret=self.signing_secret)
98+
99+
def event_handler():
100+
pass
101+
102+
app.event("app_mention")(event_handler)
103+
input = {
104+
"token": "verification_token",
105+
"team_id": "T111",
106+
"api_app_id": "A111",
107+
"event": {"type": "app_mention", "text": "<@W111> Hi", "user": "W222", "team": "T111", "channel": "C111"},
108+
"type": "event_callback",
109+
"event_id": "Ev111",
110+
"event_time": 1595926230,
111+
}
112+
timestamp, body = str(int(time())), json.dumps(input)
113+
event = {
114+
"body": base64.b64encode(body.encode("utf-8")).decode("ascii"),
115+
"queryStringParameters": None,
116+
"headers": self.build_headers(timestamp, body),
117+
"requestContext": {"http": {"method": "POST"}},
118+
"isBase64Encoded": True,
119+
}
120+
response = SlackRequestHandler(app).handle(event, self.context)
121+
assert response["statusCode"] == 200
122+
73123
def test_first_value(self):
74124
assert _first_value({"foo": [1, 2, 3]}, "foo") == 1
75125
assert _first_value({"foo": []}, "foo") is None

0 commit comments

Comments
 (0)