|
| 1 | +# Responding to Slack events |
| 2 | +The code for this step is also available [here](/tutorial/PythOnBoardingBot). |
| 3 | + |
| 4 | +## Install the dependencies |
| 5 | +> 💡 **[“Requirements files”](https://pip.pypa.io/en/stable/user_guide/#id12)** are files containing a list of items to be installed using pip install. Details on the format of the files are here: [Requirements File Format](https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format). |
| 6 | +
|
| 7 | +- In the root directory create a "requirements.txt" file. |
| 8 | +- Add the following contents to that file and save the file. |
| 9 | +``` |
| 10 | +slackclient>=2.0.0 |
| 11 | +certifi |
| 12 | +``` |
| 13 | +> 💡 Certifi is a carefully curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. It has been extracted from the Requests project. |
| 14 | +
|
| 15 | +- Next you can install those dependencies by running the following command from your terminal: |
| 16 | +``` |
| 17 | +$ pip3 install -r requirements.txt |
| 18 | +-> Successfully installed slackclient-2.0.0 |
| 19 | +``` |
| 20 | + |
| 21 | +## Creating the app |
| 22 | + |
| 23 | +- Create an `app.py` file to run the app. |
| 24 | + |
| 25 | +The first thing we'll need to do is import the code our app needs to run. |
| 26 | +- In `app.py` add the following code: |
| 27 | +```Python |
| 28 | +import os |
| 29 | +import logging |
| 30 | +import slack |
| 31 | +import ssl as ssl_lib |
| 32 | +import certifi |
| 33 | +from onboarding_tutorial import OnboardingTutorial |
| 34 | +``` |
| 35 | + |
| 36 | +Next we'll need our app to store some data. For simplicity we'll store our app data in-memory with the following data structure: `{"channel": {"user_id": OnboardingTutorial}}`. |
| 37 | +- Add the the following line to `app.py`. |
| 38 | +```Python |
| 39 | +onboarding_tutorials_sent = {} |
| 40 | +``` |
| 41 | + |
| 42 | +Let's add a function that's responsible for creating and sending the onboarding welcome message to new users. We'll also save the time stamp of the message when it's posted so we can update this message in the future. |
| 43 | +- Add the following lines of code to `app.py`. |
| 44 | +```Python |
| 45 | +def start_onboarding(web_client: slack.WebClient, user_id: str, channel: str): |
| 46 | + # Create a new onboarding tutorial. |
| 47 | + onboarding_tutorial = OnboardingTutorial(channel) |
| 48 | + |
| 49 | + # Get the onboarding message payload |
| 50 | + message = onboarding_tutorial.get_message_payload() |
| 51 | + |
| 52 | + # Post the onboarding message in Slack |
| 53 | + response = web_client.chat_postMessage(**message) |
| 54 | + |
| 55 | + # Capture the timestamp of the message we've just posted so |
| 56 | + # we can use it to update the message after a user |
| 57 | + # has completed an onboarding task. |
| 58 | + onboarding_tutorial.timestamp = response["ts"] |
| 59 | + |
| 60 | + # Store the message sent in onboarding_tutorials_sent |
| 61 | + if channel not in onboarding_tutorials_sent: |
| 62 | + onboarding_tutorials_sent[channel] = {} |
| 63 | + onboarding_tutorials_sent[channel][user_id] = onboarding_tutorial |
| 64 | +``` |
| 65 | +*Note:* We're using the `WebClient` to send messages into Slack. |
| 66 | +> 💡 **[WebClient](/slack/web/client.py)** A WebClient allows apps to communicate with the Slack Platform's Web API. This client handles constructing and sending HTTP requests to Slack as well as parsing any responses received into a `SlackResponse` dictionary-like object. |
| 67 | +
|
| 68 | +### Responding to events in Slack |
| 69 | +When events occurr in Slack there are two primary ways to be notified about them. We can send you an HTTP Request through our Events API (preferred) or you can stream events through a websocket connection with our RTM API. The RTM API is only recommended if you're behind a firewall and cannot receive incoming web requests from Slack. |
| 70 | + |
| 71 | +In this tutorial we'll be using the RTM API via the `RTMClient`. If you're interested in using the Events API take a look at the [SlackEventAdapter](https://github.com/slackapi/python-slack-events-api). We'll be adding support for the Events API into this library soon (See [#403](https://github.com/slackapi/python-slackclient/issues/403)). |
| 72 | + |
| 73 | +> 💡 **[RTMClient](/slack/rtm/client.py)** An RTMClient allows apps to communicate with the Slack Platform's RTM API. The event-driven architecture of this client allows you to simply link callbacks to their corresponding events. When an event occurs this client executes your callback while passing along any information it receives. |
| 74 | +
|
| 75 | +Back to our application, it's time to link our onboarding functionality to Slack events. |
| 76 | +- Add the following lines of code to `app.py`. |
| 77 | +```Python |
| 78 | +# ================ Team Join Event =============== # |
| 79 | +# When the user first joins a team, the type of the event will be 'team_join'. |
| 80 | +# Here we'll link the onboarding_message callback to the 'team_join' event. |
| 81 | +@slack.RTMClient.run_on(event="team_join") |
| 82 | +def onboarding_message(**payload): |
| 83 | + """Create and send an onboarding welcome message to new users. Save the |
| 84 | + time stamp of this message so we can update this message in the future. |
| 85 | + """ |
| 86 | + # Get the id of the Slack user associated with the incoming event |
| 87 | + user_id = payload["data"]["user"]["id"] |
| 88 | + # Get WebClient so you can communicate back to Slack. |
| 89 | + web_client = payload["web_client"] |
| 90 | + |
| 91 | + # Open a DM with the new user. |
| 92 | + response = web_client.im_open(user_id) |
| 93 | + channel = response["channel"]["id"] |
| 94 | + |
| 95 | + # Post the onboarding message. |
| 96 | + start_onboarding(web_client, user_id, channel) |
| 97 | + |
| 98 | + |
| 99 | +# ============= Reaction Added Events ============= # |
| 100 | +# When a users adds an emoji reaction to the onboarding message, |
| 101 | +# the type of the event will be 'reaction_added'. |
| 102 | +# Here we'll link the update_emoji callback to the 'reaction_added' event. |
| 103 | +@slack.RTMClient.run_on(event="reaction_added") |
| 104 | +def update_emoji(**payload): |
| 105 | + """Update onboarding welcome message after recieving a "reaction_added" |
| 106 | + event from Slack. Update timestamp for welcome message as well. |
| 107 | + """ |
| 108 | + data = payload["data"] |
| 109 | + web_client = payload["web_client"] |
| 110 | + channel_id = data["item"]["channel"] |
| 111 | + user_id = data["user"] |
| 112 | + |
| 113 | + # Get the original tutorial sent. |
| 114 | + onboarding_tutorial = onboarding_tutorials_sent[channel_id][user_id] |
| 115 | + |
| 116 | + # Mark the reaction task as completed. |
| 117 | + onboarding_tutorial.reaction_task_completed = True |
| 118 | + |
| 119 | + # Get the new message payload |
| 120 | + message = onboarding_tutorial.get_message_payload() |
| 121 | + |
| 122 | + # Post the updated message in Slack |
| 123 | + updated_message = web_client.chat_update(**message) |
| 124 | + |
| 125 | + # Update the timestamp saved on the onboarding tutorial object |
| 126 | + onboarding_tutorial.timestamp = updated_message["ts"] |
| 127 | + |
| 128 | + |
| 129 | +# =============== Pin Added Events ================ # |
| 130 | +# When a users pins a message the type of the event will be 'pin_added'. |
| 131 | +# Here we'll link the update_pin callback to the 'reaction_added' event. |
| 132 | +@slack.RTMClient.run_on(event="pin_added") |
| 133 | +def update_pin(**payload): |
| 134 | + """Update onboarding welcome message after recieving a "pin_added" |
| 135 | + event from Slack. Update timestamp for welcome message as well. |
| 136 | + """ |
| 137 | + data = payload["data"] |
| 138 | + web_client = payload["web_client"] |
| 139 | + channel_id = data["channel_id"] |
| 140 | + user_id = data["user"] |
| 141 | + |
| 142 | + # Get the original tutorial sent. |
| 143 | + onboarding_tutorial = onboarding_tutorials_sent[channel_id][user_id] |
| 144 | + |
| 145 | + # Mark the pin task as completed. |
| 146 | + onboarding_tutorial.pin_task_completed = True |
| 147 | + |
| 148 | + # Get the new message payload |
| 149 | + message = onboarding_tutorial.get_message_payload() |
| 150 | + |
| 151 | + # Post the updated message in Slack |
| 152 | + updated_message = web_client.chat_update(**message) |
| 153 | + |
| 154 | + # Update the timestamp saved on the onboarding tutorial object |
| 155 | + onboarding_tutorial.timestamp = updated_message["ts"] |
| 156 | + |
| 157 | + |
| 158 | +# ============== Message Events ============= # |
| 159 | +# When a user sends a DM, the event type will be 'message'. |
| 160 | +# Here we'll link the update_share callback to the 'message' event. |
| 161 | +@slack.RTMClient.run_on(event="message") |
| 162 | +def message(**payload): |
| 163 | + """Display the onboarding welcome message after receiving a message |
| 164 | + that contains "start". |
| 165 | + """ |
| 166 | + data = payload["data"] |
| 167 | + web_client = payload["web_client"] |
| 168 | + channel_id = data.get("channel") |
| 169 | + user_id = data.get("user") |
| 170 | + text = data.get("text") |
| 171 | + |
| 172 | + if text and text.lower() == "start": |
| 173 | + return start_onboarding(web_client, user_id, channel_id) |
| 174 | +``` |
| 175 | + |
| 176 | +Finally, we need to make our app runnable. |
| 177 | +- 🏁 Add the following lines of code to the end of `app.py`. |
| 178 | +```Python |
| 179 | +if __name__ == "__main__": |
| 180 | + slack_token = os.environ["SLACK_BOT_TOKEN"] |
| 181 | + rtm_client = slack.RTMClient(slack_token) |
| 182 | + rtm_client.start() |
| 183 | +``` |
| 184 | + |
| 185 | +--- |
| 186 | + |
| 187 | +**Next section: [04 - Running the app](/tutorial/04-running-the-app.md).** |
| 188 | + |
| 189 | +**Previous section: [02 - Building a message](/tutorial/01-building-a-message.md).** |
| 190 | + |
| 191 | +**Back to the [Table of contents](/tutorial/#table-of-contents).** |
0 commit comments