Building a Discord Bot with Python and AWS

I’m a member of a lot of Discord servers. The one I participate in most is one with my brothers and our friends. In this server, we joke around a lot about people posting off-topic messages in the various text channels and we give them fake “warnings”. I decided to take this a step further and create a bot where we could track the warnings and then present them in a leaderboard.

The Discord bot API documentation is great and allowed me to quickly get a proof of concept up and running. I then relied on my Python, Terraform, and AWS skills to get the bot up and running quickly. Below is a simple architecture diagram that I started and will most likely be adding to as the members of the server request more features.

We have three current commands, !warning, !feature, !leaderboard. The !warning command takes input of a tagged user. It then uses the Boto3 library for Python and adds the attribute to the user in the table. Here is the code:

# Adds an attribute to a user
    def add_warning_to_user(username, attribute):
        client = boto3.resource("dynamodb", region_name="us-west-2",
                                aws_access_key_id=os.getenv('AWS_KEY'),
                                aws_secret_access_key=os.getenv('AWS_SECRET'))
        table = client.Table(table_name)
        print("adding", attribute, "to", str(username))

        try:
            response = table.update_item(
                Key={'username': str(username)},
                AttributeUpdates={attribute: {
                    'Value': str(dynamodb.get_warning_count_of_user(username, attribute) + 1)
                    }
                }
            )
            print(response)
        except ClientError as e:
            print("Failed to update count")
            print(e)
            return False
        return True

I have another function within this code that will call out to the DynamoDB table and gets the user’s current value so that we can increment the count.

The !leaderboard command takes input of an “attribute” I built it this way so that we can have future attributes added to users without having to rebuild everything from scratch. To get the data I used the DynamoDB scan function to retrieve all of the data for all the users and then filter within the Python application on just the attribute that we are requesting the leaderboard for. I then have a function that formats the leaderboard into something that the bot can publish back to the server.

    def create_table(data, attribute):
        if attribute == "warning_count":
            attribute = "Warnings"
        table = ""
        rows = []
        rows.append("``` ")
        rows.append(f"{attribute}: Leaderboard")
        for key, value in data.items():
            rows.append(f"{key}: {str(value)}")
        rows.append("``` ")
        for row in rows:
            table += " " + row + "\n "
        return table

This code I want to revisit to make the formatting cleaner as the list gets longer. But for now it works as intended.

The last function I created so that the users could submit feature requests. The code is very simple and the command !feature takes the input of all text following the command and passes it to an SNS function I wrote which sends an email to me containing the user’s feature request. I have hopes that I can transition this to create some sort of Jira task or other workflow. Below is the bot’s code to handle this interaction:

@client.command(name="feature", help="sends a feature request")
async def send_feature_request(ctx, *, args):
    print("THIS IS THE FEATURE REQUEST", args)
    if sns.send_message(args) == True:
        await ctx.send("Your request has been sent")
    else:
        await ctx.send("Failed to send your request. Plz try again later.")

Right now the bot is running inside a Docker container within my homelab. I need to create better logging and implement some sort of logging server so that I can better handle errors as well as monitoring in case of any outages.

If you have questions about building Discord bots or AWS and its various components feel free to reach out to me at any time. This was a great project that I worked on over a few days and it was great to see it come together quickly!


by

Comments

Leave a Reply