X Tutup
Skip to content

Commit f07628d

Browse files
misscodedseratch
authored andcommitted
first pass at basic concepts section of docs
1 parent c30b0b0 commit f07628d

15 files changed

+717
-30
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: Acknowledging events
3+
lang: en
4+
slug: acknowledge
5+
order: 7
6+
---
7+
8+
<div class="section-content">
9+
10+
Actions, commands, and options events must **always** be acknowledged using the `ack()` function. This lets Slack know that the event was received and updates the Slack user interface accordingly.
11+
12+
Depending on the type of event, your acknowledgement may be different. For example, when acknowledging a dialog submission you will call `ack()` with validation errors if the submission contains errors, or with no parameters if the submission is valid.
13+
14+
We recommend calling `ack()` right away before sending a new message or fetching information from your database since you only have 3 seconds to respond.
15+
16+
</div>
17+
18+
```python
19+
# Listen for dialog submissions with a callback_id of ticket_submit
20+
@app.action("ticket_submit")
21+
def process_submission(ack, action):
22+
# Regex to determine if this is a valid email
23+
is_email = "^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$"
24+
25+
if re.match(is_email, action["submission"]["email"]):
26+
# It’s a valid email, accept the submission
27+
ack()
28+
else:
29+
# If it isn’t a valid email, acknowledge with an error
30+
errors = [{
31+
"name": "email_address",
32+
"error": "Sorry, this isn’t a valid email"
33+
}]
34+
ack({"errors": errors})
35+
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
title: Authenticating with OAuth
3+
lang: en
4+
slug: authenticating-oauth
5+
order: 14
6+
---
7+
8+
<div class="section-content">
9+
10+
Slack apps installed on multiple workspaces will need to implement OAuth, then store installation information (like access tokens) securely. By providing `client_id`, `client_secret`, `scopes`, `installation_store`, and `state_store` when initializing App, Bolt for Python will handle the work of setting up OAuth routes and verifying state. If you’re implementing a custom receiver, you can make use of our [OAuth library](https://slack.dev/python-slack-sdk/oauth), which is what Bolt for Python uses under the hood.
11+
12+
Bolt for Python will create a **Redirect URL** `slack/oauth_redirect`, which Slack uses to redirect users after they complete your app’s installation flow. You will need to add this **Redirect URL** in your app configuration settings under **OAuth and Permissions**. This path can be configured in the `OAuthSettings` argument described below.
13+
14+
Bolt for Python will also create a `slack/install` route, where you can find an **Add to Slack** button for your app to perform direct installs of your app. If you need any additional authorizations (user tokens) from users inside a team when your app is already installed or a reason to dynamically generate an install URL, you can pass your own custom URL generator to `oauth_settings` as `authorize_url_generator`.
15+
16+
To learn more about the OAuth installation flow with Slack, [read the API documentation](https://api.slack.com/authentication/oauth-v2).
17+
18+
</div>
19+
20+
```python
21+
oauth_settings = OAuthSettings(
22+
client_id=os.environ["SLACK_CLIENT_ID"],
23+
client_secret=os.environ["SLACK_CLIENT_SECRET"],
24+
scopes=["channels:read", "groups:read", "chat:write"],
25+
installation_store=FileInstallationStore(),
26+
state_store=FileOAuthStateStore(expiration_seconds=120)
27+
)
28+
29+
app = App(signing_secret=os.environ["SIGNING_SECRET"],
30+
oauth_settings=oauth_settings)
31+
```
32+
33+
<details class="secondary-wrapper">
34+
<summary class="section-head" markdown="0">
35+
<h4 class="section-head">Customizing OAuth defaults</h4>
36+
</summary>
37+
38+
<div class="secondary-content" markdown="0">
39+
You can override the default OAuth using `oauth_settings`, which can be passed in during the initialization of App. You can override the following:
40+
41+
- `authorization_url`: Used to toggle between new Slack Apps and Classic Slack Apps
42+
- `install_path`: Override default path for "Add to Slack" button
43+
- `redirect_uri`: Override default redirect url path
44+
- `callback_options`: Provide custom success and failure pages at the end of the OAuth flow
45+
- `state_store`: Provide a custom state store instead of using the built in `OAuthStateStore`
46+
47+
</div>
48+
49+
```python
50+
oauth_settings = OAuthSettings(
51+
client_id=os.environ["SLACK_CLIENT_ID"],
52+
client_secret=os.environ["SLACK_CLIENT_SECRET"],
53+
scopes=["channels:read", "groups:read", "chat:write", "incoming-webhook"],
54+
installation_store=FileInstallationStore(),
55+
state_store=FileOAuthStateStore(expiration_seconds=120),
56+
install_path="/slack/install_app",
57+
redirect_uri_path="/slack/redirect",
58+
callback_options=CallbackOptions(success=success_handler,
59+
failure=failure_handler)
60+
)
61+
62+
app = App(signing_secret=os.environ["SIGNING_SECRET"],
63+
oauth_settings=oauth_settings)
64+
```
65+
66+
</details>

docs/_basic/example.md

Lines changed: 0 additions & 30 deletions
This file was deleted.

docs/_basic/listening_actions.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
title: Listening to actions
3+
lang: en
4+
slug: action-listening
5+
order: 5
6+
---
7+
8+
<div class="section-content">
9+
Your app can listen to user actions like button clicks, and menu selects, using the `action` method.
10+
11+
Actions can be filtered on an `action_id` of type `str` or `RegExp` object. `action_id`s act as unique identifiers for interactive components on the Slack platform.
12+
13+
You’ll notice in all `action()` examples, `ack()` is used. It is required to call the `ack()` function within an action listener to acknowledge that the event was received from Slack. This is discussed in the [acknowledging events section](#acknowledge).
14+
15+
</div>
16+
17+
```python
18+
# Your middleware will be called every time an interactive component with the action_id "approve_button" is triggered
19+
@app.action("approve_button")
20+
def update_message(ack):
21+
ack()
22+
# Update the message to reflect the action
23+
```
24+
25+
<details class="secondary-wrapper">
26+
<summary class="section-head" markdown="0">
27+
<h4 class="section-head">Listening to actions using a constraint object</h4>
28+
</summary>
29+
30+
<div class="secondary-content" markdown="0">
31+
32+
You can use a constraints object to listen to `callback_id`s, `block_id`s, and `action_id`s (or any combination of them). Constraints in the object can be of type `str` or `RegExp` object.
33+
34+
</div>
35+
36+
```python
37+
# Your function will only be called when the action_id matches 'select_user' AND the block_id matches 'assign_ticket'
38+
@app.action({"action_id": "select_user", "block_id": "assign_ticket"})
39+
def update_message(ack, action, client):
40+
ack()
41+
client.reactions_add(name='white_check_mark',
42+
timestamp=action['ts'],
43+
channel=action['channel'])
44+
```
45+
46+
</details>

docs/_basic/listening_events.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: Listening to events
3+
lang: en
4+
slug: event-listening
5+
order: 3
6+
---
7+
8+
<div class="section-content">
9+
10+
You can listen to [any Events API event](https://api.slack.com/events) using the `event()` method after subscribing to it in your app configuration. This allows your app to take action when something happens in Slack, like a user reacting to a message or joining a channel.
11+
12+
The `event()` method requires an `eventType` of type `str`.
13+
14+
</div>
15+
16+
```python
17+
# When a user joins the team, send a message in a predefined channel asking them to introduce themselves
18+
@app.event("team_join")
19+
def ask_for_introduction(payload, say):
20+
welcome_channel_id = "C12345";
21+
user_id = payload["event"]["user"]
22+
text = f"Welcome to the team, <@{user_id}>! 🎉 You can introduce yourself in this channel."
23+
say(text=text, channel=welcome_channel_id)
24+
```
25+
26+
<details class="secondary-wrapper" >
27+
28+
<summary class="section-head" markdown="0">
29+
<h4 class="section-head">Filtering on message subtypes</h4>
30+
</summary>
31+
32+
<div class="secondary-content" markdown="0">
33+
The `message()` listener is equivalent to `event("message")`.
34+
35+
You can filter on subtypes of events by passing in the additional key `subtype`. Common message subtypes like `bot_message` and `message_replied` can be found [on the message event page](https://api.slack.com/events/message#message_subtypes).
36+
37+
</div>
38+
39+
```python
40+
# Matches all messages from bot users
41+
@app.message({"subtype": "message_changed"})
42+
def log_message_change(logger, payload):
43+
message = payload["event"]
44+
logger.info(f"The user {message['user']} changed the message to {message['text']}")
45+
```
46+
47+
</details>

docs/_basic/listening_messages.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
title: Listening to messages
3+
lang: en
4+
slug: message-listening
5+
order: 1
6+
---
7+
8+
<div class="section-content">
9+
10+
To listen to messages that [your app has access to receive](https://api.slack.com/messaging/retrieving#permissions), you can use the `message()` method which filters out events that aren’t of type `message`.
11+
12+
`message()` accepts an argument of type `str` or `RegEx` object that filters out any messages that don’t match the pattern.
13+
14+
</div>
15+
16+
```python
17+
# This will match any message that contains 👋
18+
@app.message(":wave:")
19+
def say_hello(payload, say):
20+
user = payload['event']['user']
21+
say(f"Hi there, <@{user}>!")
22+
```
23+
24+
<details class="secondary-wrapper">
25+
<summary markdown="0">
26+
<h4 class="secondary-header">Using a RegEx pattern</h4>
27+
</summary>
28+
29+
<div class="secondary-content" markdown="0">
30+
31+
The `re.compile()` method can be used instead of a string for more granular matching.
32+
33+
</div>
34+
35+
```python
36+
@app.message(re.compile("(hi|hello|hey)"))
37+
def say_hello_regex(say, context):
38+
# RegExp matches are inside of context.matches
39+
greeting = context['matches'][0]
40+
say(f"{greeting}, how are you?")
41+
```
42+
43+
</details>

docs/_basic/listening_modals.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
title: Listening for view submissions
3+
lang: en
4+
slug: view_submissions
5+
order: 12
6+
---
7+
8+
<div class="section-content">
9+
10+
If a <a href="https://api.slack.com/reference/block-kit/views">view payload</a> contains any input blocks, you must listen to `view_submission` events to receive their values. To listen to `view_submission` events, you can use the built-in `view()` method. `view()` requires a `callback_id` of type `str` or `RegExp`.
11+
12+
You can access the value of the `input` blocks by accessing the `state` object. `state` contains a `values` object that uses the `block_id` and unique `action_id` to store the input values.
13+
14+
Read more about view submissions in our <a href="https://api.slack.com/surfaces/modals/using#interactions">API documentation</a>.
15+
16+
</div>
17+
18+
```python
19+
# Handle a view_submission event
20+
@app.view("view_b")
21+
def handle_submission(ack, body, client, view):
22+
# Acknowledge the view_submission event
23+
ack()
24+
25+
# Do whatever you want with the input data - here we're saving it to a DB then sending the user a verifcation of their submission
26+
27+
# Assume there's an input block with `block_1` as the block_id and `input_a`
28+
val = view["state"]["values"]["block_1"]["input_a"]
29+
user = body["user"]["id"]
30+
31+
# Message to send user
32+
msg = ""
33+
34+
# TODO: Store in DB
35+
36+
if results:
37+
msg = "Your submission was successful"
38+
else:
39+
msg = "There was an error with your submission"
40+
41+
# Message the user
42+
client.chat_postMessage(channel=user, text=msg)
43+
```
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Listening and responding to commands
3+
lang: en
4+
slug: commands
5+
order: 9
6+
---
7+
8+
<div class="section-content">
9+
10+
Your app can use the `command()` method to listen to incoming slash command events. The method requires a `command_name` of type `str`.
11+
12+
Commands must be acknowledged with `ack()` to inform Slack your app has received the event.
13+
14+
There are two ways to respond to slash commands. The first way is to use `say()`, which accepts a string or JSON payload. The second is `respond()` which is a utility for the `response_url`. These are explained in more depth in the [responding to actions](#action-respond) section.
15+
16+
When configuring commands within your app configuration, you'll continue to append `/slack/events` to your request URL.
17+
18+
</div>
19+
20+
```python
21+
# The echo command simply echoes on command
22+
@app.command("/echo")
23+
def repeat_text(ack, say, command):
24+
# Acknowledge command request
25+
ack()
26+
say(f"{command['text']}")
27+
```
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Listening and responding to options
3+
lang: en
4+
slug: options
5+
order: 13
6+
---
7+
8+
<div class="section-content">
9+
The `options()` method listens for incoming option request payloads from Slack. [Similar to `action()`](#action-listening),
10+
an `action_id` or constraints object is required. In order to load external data into your select menus, you must provide an options load URL in your app configuration.
11+
12+
While it's recommended to use `action_id` for `external_select` menus, dialogs do not yet support Block Kit so you'll have to
13+
use the constraints object to filter on a `callback_id`.
14+
15+
To respond to options requests, you'll need to `ack()` with valid options. Both [external select response examples](https://api.slack.com/reference/messaging/block-elements#external-select) and [dialog response examples](https://api.slack.com/dialogs#dynamic_select_elements_external) can be found on our API site.
16+
</div>
17+
18+
```python
19+
# Example of responding to an external_select options request
20+
@app.options("external_action")
21+
def show_options(ack):
22+
options = [
23+
{
24+
"text": {"type": "plain_text", "text": "Option 1"},
25+
"value": "1-1",
26+
},
27+
{
28+
"text": {"type": "plain_text", "text": "Option 2"},
29+
"value": "1-2",
30+
},
31+
]
32+
33+
ack({"options": options})
34+
```

0 commit comments

Comments
 (0)
X Tutup