Quote Bracket

Overview

Quote Bracket is a system that allows a Discord community to vote on which quote is the best in the quote list. I have used it within 3 communities for various Twitch streamers.

This system used to be a lot more primitive in that it used Discord’s reactions to vote on which quote users wanted to win because the first version of it was before Discord’s Interaction system was even public. Once they added the dropdowns to the Interaction system, I decided to rework the code from the ground up to make it more resilient, nicer to use, and more professionally written, as the first version was thrown together in 3 days over a weekend.

Each time a new quote bracket is created, the system determines which quote(s) are the winners from the previous bracket, after deleting the old bracket, or removing the buttons from the message, and then sends a new bracket, indicating which quote won by adding a crown in front of their identifier.


Development

Utilizing Discord’s Interaction system to allow users to vote on quotes using the interaction dropdowns, and managing their vote using the button.

This is done by having an incoming webhook that Discord sends the event data to when a user interacts with the buttons or dropdown. A single installation of the system is able to manage brackets for any number of Discord guilds.

Configuration

The system is configured through a central TOML config file. Which is loaded by the API when starting. The config template can be seen on the GitHub page with a description of what each property means and the valid values for that property.

Authentication

There are three different types of authentication happening within the API, each strategy serves a different purpose.

Discord OAuth2 Flow

This authentication flow is used by the backend to create the Discord webhook it uses to post the bracket to. This allows the user to dynamically change what channel the bracket goes to without ever needing to re-authenticate the system.

Once the user has authenticated this way and the system has created the webhook, this authentication does not need to happen again unless the user deletes the webhook from within Discord.

Discord Payload Validation

Every time Discord POSTs interaction data to the API, it needs to be validated to ensure that it wasn’t tampered with in-transit. This authentication strategy is in use on the POST /discord/webhook endpoint, no other endpoints use this strategy.

For more information on Discord’s authentication strategy you can read more on the Discord developer documentation website

BASIC Authentication

Each Discord guild that has a bracket configured also has a password enabled in order to prevent attacks that target the private endpoints. This is applied to all of the * /{guild_id}/bracket/* endpoints which are used for managing the bracket in a guild.

Unauthenticated

There are two endpoints that are utilized by the website in order to get data about a guild’s bracket history. This allows users who look at the website to see what guilds they’re in that have a bracket setup, and the history associated with that guild.

Endpoints

The system contains three category of API endpoints:

Running

When setting up the system, I decided to try something new, using systemd to manage the process that runs the program, this allowed me to learn more about how Linux servers are setup and where certain files are, plus learning how to use .service files to make an auto-restoring service if an outage occurs on a small scale so that I possibly utilize some of those concepts at larger scales.

In order to start a new quote bracket every so often, I’m using Cron to schedule curl commands pinging the localhost API which allows us to make the request securely since it never leaves the local machine.


These images come from a combination of the three communities that I had the system running for while writing this page.

Some of the quotes in the screenshots may not be suitable for all ages, all of them are not sexual, but they may cause some uncomfiness. For this reason I have blurred the images and they will automatically un-blur when you hover over them or click them (if on mobile).

An example quote bracket from the Resonym community Discord server with one winning quote.

This is an example quote bracket from the CzechGamesEdition community that has a different quote count from the Resonym quote bracket, and shows what the Discord interaction dropdown looks like.

This is what the response message looks like to users from the APi when they try to see what quote they voted for but haven’t selected one yet.

This is the response users get when they vote on the bracket for the first time.

This is the response users see when they change their vote from one quote to another.


Oliver Akins © 2022. All rights reserved.