PWSHub
Themes: Pagination size: Use the left or right arrow keys to navigate between pages 😉You can swipe to left or right to navigate between pages 😉

Build a Slack bot with Slack Machine - LogRocket Blog

[blog.logrocket.com]1 week agobyWamaitha Nyamu

Slack, a messaging program originally designed to be used in an office space, has also been adopted for personal use. According to an official statement by the company, Slack has ten million daily users with over 85,000 paying customers.

Over the years, the Slack community has been building a powerful app directory. The collection of apps contains hundreds to thousands of integrations that provide a great amount of flexibility to boost companies’ efficiency.

The Slack Machine is a robust and extendable framework that helps you develop your Slack workspace into a ChatOps powerhouse. In this guide, we will go over how to set up the Slack Machine and implement some of its features.

To jump ahead:

The current Slack Machine project folder contains one file: local_settings.py. This file will hold all of the configuration settings for the Slack Machine:

SlackMachine(Project-folder)|__local_settings.py 

Generating tokens to connect our app to the Slack Machine

Two tokens are needed to connect our app and the Slack Machine: the app-level token and bot token. To generate these tokens:

    1. Navigate to https://api.slack.com/apps
    2. Click on Create an App:Creating Slack App
    3. In the pop-up window, select From an app manifest:Selecting From An App Manifest
    4. Choose the Slack workspace where you will install the Slack bot:Choosing A Slack Workspace
    5. In the next step, we need to define a manifest. A manifest is a configuration that dictates how the Slack app will work. Read more on the meaning of each field here. Add the following code block to the manifest:
      display_information: name: Wamaitha Slack Machinefeatures: bot_user: display_name: Wamaitha Slack Machine always_online: falseoauth_config: scopes: bot: - app_mentions:read - channels:history - channels:join - channels:read - chat:write - chat:write.public - emoji:read - groups:history - groups:read - groups:write - im:history - im:read - im:write - mpim:history - mpim:read - mpim:write - pins:read - pins:write - reactions:read - reactions:write - users:read - users:read.email - channels:manage - chat:write.customize - dnd:read - files:read - files:write - links:read - links:write - metadata.message:read - usergroups:read - usergroups:write - users.profile:read - users:writesettings: event_subscriptions: bot_events: - app_mention - channel_archive - channel_created - channel_deleted - channel_id_changed - channel_left - channel_rename - channel_unarchive - group_archive - group_deleted - group_left - group_rename - group_unarchive - member_joined_channel - member_left_channel - message.channels - message.groups - message.im - message.mpim - reaction_added - reaction_removed - team_join - user_change - user_profile_changed - user_status_changed interactivity: is_enabled: true org_deploy_enabled: false socket_mode_enabled: true token_rotation_enabled: false
    6. In the Review summary & create your app pop-up, click Create:
      Creating The Slack Machine App
    7. Once the creation is done, in the Basic Information settings tab, click on Install to Workspace:Installing The App To Workspace
    8. Allow permissions to the Slack app:Allowing Permissions To The Slack App
    9. The first token we need is the SLACK_BOT_TOKEN. Navigate to OAuth & Permissions and copy the Bot User OAuth Token to the local_settings.py:Slack Bot OAuth Token
    10. To generate the app-level token, navigate to Basic Information:Generating App-Level Token
    11. Then, scroll down to App-Level Tokens and click on Generate Token and Scopes:Generate Token And Scopes
    12. In the pop-up window, give the token a name, click on the Scope dropdown, and add both scopes: connections:write and authorizations:read:
      Adding Scopes
    13. Once both scopes are selected, click on Generate. The pop-up should be as shown below:
      Generating Slack App Token
    14. Copy the generated token and save it to the local_settings.py file as SLACK_APP_TOKEN:
      Copying The Generated Token
    15. The local_settings.py file should now contain the following:
      SLACK_BOT_TOKEN="add_the_token_here"SLACK_APP_TOKEN="add_token_here"

If everything went well, the App-Level Tokens tab should look like this:

Finalized App Level Tokens Tab

Configuring Slack

Now, head over to the workspace on Slack. You should find the Slack Machine added under the Apps tab:

Slack Workspace Apps Tab

It is recommended to use the Slack Machine in a virtual environment. A virtual environment secludes the dependencies used for the app without conflicting with those installed globally on the system.

Creating a virtual environment with Python

We will use the venv Python module to create a virtual environment. The command for this follows this structure:

python -m venv name_of_environment

In this case, our virtual environment name will be venv. We create it using the command below:

python -m venv venv

N.B., If you have more than one version of Python installed, you may need to specify which Python version venv should use. More about this can be found in the venv documentation.

At this point, the project folder structure becomes:

SlackMachine(Project-folder) |__local_settings.py |__venv

To activate the virtual environment, you need to run the following commands.

On Windows, run:

venv\Scripts\activate.bat

Activating The Virtual Environment For Windows

On Linux and macOS, run:

source tutorial-env/bin/activate

Interacting with the Slack Machine

Now, we will install the Slack Machine module using pip. The module allows us to interact with the Slack API from Python.

Install the Slack Machine using:

pip install slack-machine

Run the bot on the root folder using the Slack Machine as shown below:

Running The Bot On The Root Folder

Once the connection succeeds, return to Slack. Right-click on the Slack Machine app and click on View app details:

View App Details

In the pop-up, add the app to a channel:

Add The App To A Channel

Adding The App To Desired Channel

You can add it to any channel of your choice. For this example, I added it to the #slack-machine channel. Navigate to the channel and send the bot a hello message:

Slack Bot Hello Message

By default, the Slack Machine loads the HelloPlugin and the PingPongPlugin. The HelloPlugin responds with a “hello” or “hi” when the bot is greeted. The PingPongPlugin responds with “ping” or “pong” regardless of mention.

Building custom plugins

Because of the flexible nature of the Slack Machine, we can build our own custom plugins. For this, we need to create a plugin package. Create a new plugins folder and, in it, create a customPlugin.py file.

The updated project folder structure is as shown below:

SlackMachine(Project-folder) |__local_settings.py |__venv |__plugins |__customPlugin.py

In customPlugin.py, we create a class that will contain all of our custom plugin functionalities. Our first functionality instructs the Slack app to generate a dad joke. The full code for this is:

from machine.plugins.base import MachineBasePluginfrom machine.plugins.decorators import respond_toimport requestsimport jsonclass OurCustomPluginClass(MachineBasePlugin): """ Custom plugin class for interacting with the slack-machine """ # tells a dad joke @respond_to(r"^Make me laugh") async def dad_jokes(self, msg): """ Returns a dad joke and replies the joke to the user """ random_dad_joke = requests.get("https://icanhazdadjoke.com/", headers={"Accept": "application/json"}) random_dad_joke = json.loads(random_dad_joke.text)["joke"] await msg.reply(random_dad_joke)

OurCustomPluginClass extends the MachineBasePlugin from the Slack Machine. Our dad_joke function has the respond_to decorator. The respond_to decorator acts on messages that have the Slack bot mentioned, with the specific keywords passed as a regex to the decorator.

The requests module will make an HTTP request to the dad_joke API. The JSON module comes installed with Python and is used to transform the API response into a JSON format.

The requests library can be installed using pip on the terminal:

pip install requests

The custom plugin needs to be included in the local_settings.py to run the Slack Machine.

In local_settings.py, add the code as shown:

SLACK_APP_TOKEN = "xapp-"SLACK_BOT_TOKEN = "xoxb-"PLUGINS = ["plugins.customPlugin.OurCustomPluginClass"]

Then re-run Slack Machine on the terminal in the root folder:

Running The Bot On Slack Machine's Root Folder

The output should show that the plugin class has been loaded.

The respond_to decorator requires the user to mention the bot on Slack with the specified keywords. In our case, we need to mention the bot, followed by “Make me laugh” to trigger the dad_joke function:

Slack Bot Dad Joke Function

The respond_to decorator can also be used to emit custom events. Events are a way to exchange data between plugins or expose API endpoints other plugins can use. Events are emitted using self.emit(). Our custom event will collect user emails and send them to an email channel.

First, create an email channel: #registration-emails:

Creating Slack Email Channel

The code for collecting emails is as shown below:

from machine.plugins.base import MachineBasePluginfrom machine.plugins.decorators import respond_to, on, import requestsimport jsonimport reclass OurCustomPluginClass(MachineBasePlugin): """ Custom plugin class for interacting with the slack-machine """ @respond_to(r"register (?P<email>.*)") async def register_emails(self, msg, email): """ Collect registration email from user """ email = email.split("|")[1][:-1] email_regex = "^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$" user = msg.at_sender if re.search(email_regex, email): self.emit('new_registration', email=email, user=user) else: await msg.reply_dm(f'Hey {user}, your registration email address {email} is invalid.') @on("new_registration") async def collect_emails(self, **kwargs): """ Listen for new emails """ await self.say("registration-emails", f"{kwargs['user']} - {kwargs['email']}") ]}")

The register_emails function emits an event that forwards emails to the #registration-emails channel. The event also emits the user’s ID and the specific email as part of the arguments:
Slack Register Emails Function

Event Emitted By Register Emails Function

The event emitted has a unique name, in our case new-registrations. To listen to the new-registrations event, we need the @on decorator.

The decorator needs the event name to look out for. When the new-registrations event is emitted, the collect_emails function is triggered. This function forwards the user’s name and email to the #registration-emails channel.

If the user provides an invalid email address, the Slack app sends the user a direct message:

Slack Direct Message

Slack Machine storage capabilities

The Slack Machine also provides storage capabilities. Data is stored in key-value pairs in-memory or using external databases. To demonstrate in-memory capabilities, we will generate tokens and have the user retrieve and delete them at will.

The code for this can be seen below:

from machine.plugins.base import MachineBasePluginfrom machine.plugins.decorators import respond_to, onimport requestsimport jsonimport reimport randomclass OurCustomPluginClass(MachineBasePlugin): """ Custom plugin class for interacting with the slack-machine """ @respond_to(r"generate") async def gen_token(self, msg): """ Generate random token """ user = msg.at_sender token = random.randint(1, 1000) await self.storage.set(user, token) await msg.reply_dm(f"Hey {user} your generated token is {token}") @respond_to(r"retrieve") async def retrieve_token(self, msg): """ Retrieve the stored token """ user = msg.at_sender token = await self.storage.get(user) if token:21 await msg.reply_dm(f"Hey {user} your token is {token}") else: await msg.say("Key not found! Generate a new token") @respond_to(r"delete") async def delete_token(self, msg): """ delete tokens """ user =msg.at_sender await self.storage.delete(user) await msg.say(f"data in <{user}> deleted!")

The in-memory storage capabilities come built into the MachineBasePlugin class. Still using the respond_to decorator, we have three functions:

  1. gen_token: This function generates a random token between one and 1000. The token is saved to the in-memory database using the set method. The set method takes in two arguments: the key and the value. We’ve set the user’s sender ID as the key and the generated token as the value:Slack Generate Token
    Slack Generated Token
  2. retrieve_token: This function will check the in-memory storage for a value that has the user’s sender ID. If a key exists, a private direct message of the token value is sent to the user. Otherwise, the user is informed that the key doesn’t exist:Slack Retrieve Function
  3. delete_token: This function deletes the user’s stored token:Slack Delete Function

The listen_to decorator works the same as the respond_to decorator with the key difference being that the user does not need to mention the Slack app.

For example, we can make the app listen to help messages using the code below:

from machine.plugins.base import MachineBasePluginfrom machine.plugins.decorators import respond_to, on, listen_to,processimport requestsimport jsonimport reimport randomclass OurCustomPluginClass(MachineBasePlugin): """ Custom plugin class for interacting with the slack-machine """ @listen_to(r"^help") async def help_details(self, msg): """ something """ await msg.say("Refer to the #help-channel for help")

Slack Help Request

Slack treats most interactions with the user as events. Every time the user performs an action on Slack, the Slack events API is fired. We can listen to specific events using the @process decorator. The decorator takes in the specific event we want to listen to.


More great articles from LogRocket:


In the code below, the Slack app will send a notification to the #random channel when a user creates a new channel. The whole list of events can be found here:

from machine.plugins.base import MachineBasePluginfrom machine.plugins.decorators import respond_to, on, listen_to,processimport requestsimport jsonimport reimport randomclass OurCustomPluginClass(MachineBasePlugin): """ Custom plugin class for interacting with the slack-machine """ @process("channel_created") async def check_channel_created(self): """ something """ await self.say("random", "We have a new channel")

New Slack Channel

Conclusion

In this article, we reviewed how to build a Slack bot using the Slack Machine. The Slack Machine is jam-packed with more functionality in the API documentation. Its flexibility and customization abilities help users make more apps for specific business use cases.

https://blog.logrocket.com/slack-bot-slack-machine/

Related articles:

[blog.logrocket.com] Customer exit surveys for products: How and what to ask - LogRocket Blog[tympanus.net] Web Design & Development News: Collective #739[blog.logrocket.com] Build a durable pub-sub with Kafka in Node.js - LogRocket Blog[geekflare.com] 6 Best Football (Soccer) Apps for FIFA World Cup 2022 Updates[omgubuntu.co.uk] LUbuntu 23.04 Daily Builds Available to Download