mirror of
https://github.com/LukeHagar/toyo-discord-bot.git
synced 2025-12-06 04:21:49 +00:00
e72c1d4e426273eafc46e14464ddf2712c871f98
toyo-discord-bot
Bot for the TOYO Discord with customized commands.
Development Notes
- Write the code in the
/srcfolder. Helper functions can be included as their own.jsfiles but will then need to be marked withexportand thenimport <name> from './file.js'wherever they are going to be used. server.jsis the main bundle of code that is used by the server. This is what is hosted in cloudflare.- DEV Use
npm ngrokto host the code locally. If doing this, the Discord Application will need to be updated for where it points. Get the ngrok url and paste it in theInteractions Endpoint URLfield. - PROD Use
npm run deployto push the updated code to Wrangler/cloudflare - SECRETS Secrets/constants can be pushed into cloudflare
- push directly from the dev command line like this
npx wrangler secret put NAME_OF_VARIABLE, or - use the webui at cloudflare to create Secrets
- To Use: hen import them into the code using
const token = process.env.NAME_OF_VARIABLE;within the javascript file.
- push directly from the dev command line like this
- TODO: figure out how to do the wrangler deploy from github actions
- cloudflare guide to create the worker, then follow This Guide to set up a sample app. For the most part I just copied content out of the sample app into the new worker i created. Its janky, but it worked. shut up.
Building New Commands
NOTE THIS DOES NOT WORK!!!! no idea why. but when working on it i came across this: https://v13.discordjs.guide/creating-your-bot/command-handling.html
src/commands.js- Add a new command using the template. It needs a name for the const to use, the name value is what a user enters in the chat/yoto-store-info parameters go here, description is what pops up when the user is typingexport const GET_STORE_PAGE_COMMAND = { name: 'yoto-store-info', description: 'Get information about a listing from the Yoto store.', };register.js- Line 1 Update the import line to include the new command constant:import { AWW_COMMAND, GET_STORE_PAGE_COMMAND } from './commands.js';register.js- Line 37 Add the new command constant into the PUT command body string.body: JSON.stringify([AWW_COMMAND, GET_STORE_PAGE_COMMAND]),server.js- Line 11 Update the import line to include the new command constant:import { AWW_COMMAND, GET_STORE_PAGE_COMMAND } from './commands.js';server.js- Add a new command processor for therouter.postfunction:case GET_STORE_PAGE_COMMAND.name.toLowerCase(): { // Build the response. Best to use other function calls here so this is a short bit of code. var rawmessage = "Sorry, this function is not implemented yet."; // Send the message out to Discord. return new JsonResponse({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { content: rawmessage, }, }); }server.js- Write the code to process the actions- On the command line (in the working folder) run
npm run registerto register the commands with Discord - Publish the code to GitHub
- Test using ngrok
npm run ngrokor deploy directly to cloudflare (see above)npm run publish
Notes
- Rate Limits:
- Ensure your bot handles API rate limits gracefully to avoid being throttled by either Discord or Google.
- Security:
- Do not hardcode sensitive tokens (Discord bot token or Google credentials) in your code. Use environment variables or a secure configuration file.
- Error Handling:
- The bot includes basic error handling but can be expanded to cover specific issues like invalid ranges or insufficient permissions.
- Permissions:
- Ensure the Service Account used for the Google Sheets API has "Editor" permissions for the spreadsheet.
- Ensure the Service Account used for the Google Sheets API has "Editor" permissions for the
links_from_discordspreadsheet. - Ensure the Service Account has "Reader" access to the
Card_DBspreadsheet. - Ensure the Google Sheets API service account has "Editor" access to the
points_fetch_logspreadsheet.
- Spreadsheet ID:
- Replace the placeholder YOUR_DISCORD_USERS_SPREADSHEET_ID with the actual ID of your Google Sheet.
- Customization:
- You can extend the commands to include additional metadata, such as a description for the URL or a timestamp.
- You can modify the headers array to match the actual column headers in your spreadsheet.
How It Works
- Command:
archive-application-status- The spreadsheet query function uses the
message.author.id(Discord user ID) to find matching data in the spreadsheet. - Assumes the spreadsheet has Discord user IDs in column
Aand application statuses in columnB. Update therangeand index logic if your structure is different. - Gracefully handles cases where the user ID does not exist in the spreadsheet or when the spreadsheet is empty.
- The bot sends a read-only request to the specified range in the Google Spreadsheet.
- The bot formats the retrieved data and sends it back to the Discord channel as a reply.
- The spreadsheet query function uses the
- Command:
link-email- When a user types
link-email user@example.com, the bot stores the provided email and the user’s Discord ID in theDiscord_Usersspreadsheet. - Uses the
spreadsheets.values.appendmethod from the Google Sheets API to insert new rows into the sheet. - Ensures the provided email contains an "@" symbol to check for validity. You can add more complex validation logic if needed.
- Stores the Discord user ID in column
Aand the email address in columnBof theDiscord_Usersspreadsheet. - Replies to the Discord channel with success or error messages based on the outcome.
- Handles errors such as invalid email input or issues connecting to the Google Sheets API.
- When a user types
- Command:
submit-card- Users can type
submit-card https://example.comto submit a URL for storage in thelinks_from_discordspreadsheet. - Uses spreadsheets.values.append from the Google Sheets API to insert new rows into the sheet.
- Stores the Discord user ID in column A and the submitted URL in column B of the
links_from_discordspreadsheet. - Ensures the provided URL starts with "http" to confirm it's valid. You can extend this logic for more robust validation if needed.
- Provides feedback to the user, confirming whether the URL was successfully submitted or if an error occurred.
- Handles errors related to URL submission or connectivity issues with the Google Sheets API.
- Users can type
- Command:
check-card- Returns information about the card if the identifier is known.
- Exact ID Match: Users can type
check-card hMknito submit an identifier to search for.- If a 5-character identifier is provided, the bot performs an exact, case-sensitive match in column
A. - Returns an error if multiple entries are found with the same ID. This is a data integrity problem that needs to be solved by an administrator.
- If a 5-character identifier is provided, the bot performs an exact, case-sensitive match in column
- Non-Case-Sensitive Title Search: Users can type
check-card Make Your Own Guideto submit a title to search for.- If the search term is a string (not a 5-character ID), the bot performs a non-case-sensitive match in column
C. - Provides a list of matching IDs if multiple results are found, prompting the user to search by ID for detailed information.
- If the search term is a string (not a 5-character ID), the bot performs a non-case-sensitive match in column
- Ensures only one match is returned for ID-based searches.
- Handles cases where no matches are found.
- Returns data in the format of
header: datafor columns A, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, and R.
- Command:
fetch-points- When the user types
fetch-points, the bot retrieves the message author's Discord ID and username. - Uses the Google Sheets API to search the spreadsheet for the Discord ID in column
A. - Retrieves the points from column
K(10th index in the array). - Formats the Mee6 command
/give-item member:discordID item:Yak Point amount:Xusing the retrieved points. - Logs the execution (add logic to send the command to the bot in Discord if necessary).
- Appends a log entry to the points_fetch_log spreadsheet, recording the username, Discord ID, and points awarded.
- Handles cases where the Discord ID doesn't exist or points are invalid (not a number).
- Spreadsheet Structures: Points Spreadsheet, Points Fetch Log
- The Mee6 command must be executed in a Discord channel where Mee6 is active. You can use the Discord API to send the command to the appropriate channel programmatically.
- Includes error handling for invalid Discord IDs, invalid points values, and connectivity issues with the Google Sheets API.
- When the user types
Example Spreadsheet Structure
Application_Status
| Column A (Discord ID) | Column B (Application Status) |
|---|---|
| 123456789012 | Submitted |
| 987654321098 | Approved |
Discord_Users
| Column A (Discord ID) | Column B (Email) |
|---|---|
| 123456789012 | user1@example.com |
| 987654321098 | user2@example.com |
links_from_discord
| Column A (Discord ID) | Column B (URL) |
|---|---|
| 123456789012 | https://example.com |
| 987654321098 | https://anotherlink.com |
Card_DB
| Column A (ID) | Column B (url) | Column C (Title) | Column D | ... | Column R | | --- | --- | --- | --- | --- | | ABC12 | https://link | MyCardTitle | Data1 | ... | Data2 | | DEF34 | https://link2 | AnotherTitle | Data3 | ... | DataM |
points_db
| Column A (Discord ID) | Column B (Points Available) |
|---|---|
| 123456789012 | 10 |
| 987654321098 | 0 |
points_log
| Column A (Discord ID) | Column B (Points Given) | Column C (Action Date) |
|---|---|---|
| 123456789012 | 5 | Mar 10 2025 |
| 987654321098 | 23 | Jan 1 2025 |
Description
Languages
JavaScript
100%