Quote Bracket
Projects | | Links: Source Code
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:
- Discord
- The
auth
folder is the two endpoints relating to the OAuth2 implementation
- The
- Bracket Management
- Site Data Providers
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.
Image Gallery
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).