V1.2.1 dev (#11)
* make the beginning height optional, defaulting to the trees current heigt * improved workflow * fix * new fix * Install modules * remove unnecessary call to build the tables * testing * f * f * oops * undev * fix const * new ci * versioning * Classes, Collections, and new Notification Relay * Fix CI for new env vars * Update to read contents of embeds * Update filter to check for embeds * Update to add includes check * Begin implementing role menu * Role menu ready for testing * Add missing emojis * Fixes, ready for testing * Tentative deploy * Documentation update * I think this fixes unchanging notifications * Update README.md * Make reminders visually distinct * Set Permissions * Added import for PermissionFlagsBits * Add ability to manually send ping from watch chan * CI update * Confusion * Make dev dockerization manual only * Dev Logging * Update reset command * Implement updating of notifications piecemeal * Unified error handling * Change to refresh commands not blindly update * Change to manual run only * Restructured file to allow async use * Move role menu setup and allow everyone to send it * Consolidate setupinfo into setup * Improved error handling * Update opt out method * Cleaning up junk * Added seconds parser and optout detection * Add opt out method * Consolidated to setup command * Add privacy setting and use new parser
This commit is contained in:
parent
0b6161f0e0
commit
b724229f06
0
.dockerignore
Normal file → Executable file
0
.dockerignore
Normal file → Executable file
0
.eslintrc.json
Normal file → Executable file
0
.eslintrc.json
Normal file → Executable file
13
.github/workflows/docker-image-dev.yml
vendored
Normal file → Executable file
13
.github/workflows/docker-image-dev.yml
vendored
Normal file → Executable file
@ -1,8 +1,7 @@
|
|||||||
name: Silvanus-Dev Dockerization
|
name: Silvanus-Dev Dockerization
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_dispatch:
|
||||||
branches: [ "*-dev" ]
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DHUB_UNAME: ${{ secrets.DHUB_UNAME }}
|
DHUB_UNAME: ${{ secrets.DHUB_UNAME }}
|
||||||
@ -16,9 +15,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Build the Docker image
|
- name: Build the Docker image v0idf1sh/silvanus-dev
|
||||||
run: docker build . --file Dockerfile --tag v0idf1sh/silvanus-dev
|
run: docker build . --file Dockerfile --tag v0idf1sh/silvanus-dev
|
||||||
- name: Log into Docker Hub
|
- name: Log into Docker Hub
|
||||||
run: docker login -u $DHUB_UNAME -p $DHUB_PWORD
|
run: docker login -u $DHUB_UNAME -p $DHUB_PWORD
|
||||||
- name: Push image to Docker Hub
|
- name: Push image to Docker Hub v0idf1sh/silvanus-dev
|
||||||
run: docker push v0idf1sh/silvanus-dev
|
run: docker push v0idf1sh/silvanus-dev
|
||||||
|
- name: Set up a skeleton .env file
|
||||||
|
run: echo "TOKEN=${{secrets.DEVTOKEN}}" > .env && echo "BOTID=${{ secrets.CLIENTID }}" >> .env
|
||||||
|
- name: Install modules
|
||||||
|
run: npm i
|
||||||
|
- name: Refresh commands with Discord
|
||||||
|
run: node modules/_deploy-global.js
|
29
.github/workflows/docker-image-prod.yml
vendored
Executable file
29
.github/workflows/docker-image-prod.yml
vendored
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
name: Silvanus Production Dockerization
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
DHUB_UNAME: ${{ secrets.DHUB_UNAME }}
|
||||||
|
DHUB_PWORD: ${{ secrets.DHUB_PWORD }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build the Docker image v0idf1sh/silvanus
|
||||||
|
run: docker build . --file Dockerfile --tag v0idf1sh/silvanus
|
||||||
|
- name: Log into Docker Hub
|
||||||
|
run: docker login -u $DHUB_UNAME -p $DHUB_PWORD
|
||||||
|
- name: Push image to Docker Hub v0idf1sh/silvanus
|
||||||
|
run: docker push v0idf1sh/silvanus
|
||||||
|
- name: Set up a skeleton .env file
|
||||||
|
run: echo "TOKEN=${{secrets.PRODTOKEN}}" > .env && echo "clientId=${{ secrets.PRODCLIENTID }}" >> .env
|
||||||
|
- name: Install modules
|
||||||
|
run: npm i
|
||||||
|
- name: Refresh commands with Discord
|
||||||
|
run: node modules/_deploy-global.js
|
24
.github/workflows/docker-image.yml
vendored
24
.github/workflows/docker-image.yml
vendored
@ -1,24 +0,0 @@
|
|||||||
name: Silvanus Dockerization
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
DHUB_UNAME: ${{ secrets.DHUB_UNAME }}
|
|
||||||
DHUB_PWORD: ${{ secrets.DHUB_PWORD }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Build the Docker image
|
|
||||||
run: docker build . --file Dockerfile --tag v0idf1sh/silvanus
|
|
||||||
- name: Log into Docker Hub
|
|
||||||
run: docker login -u $DHUB_UNAME -p $DHUB_PWORD
|
|
||||||
- name: Push image to Docker Hub
|
|
||||||
run: docker push v0idf1sh/silvanus
|
|
1
.gitignore
vendored
Normal file → Executable file
1
.gitignore
vendored
Normal file → Executable file
@ -7,6 +7,7 @@ env.prod
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
data/guildInfo.json
|
data/guildInfo.json
|
||||||
data/rawstring.txt
|
data/rawstring.txt
|
||||||
|
modules/input.txt
|
||||||
|
|
||||||
# Custom folders
|
# Custom folders
|
||||||
# gifs/*
|
# gifs/*
|
||||||
|
2
Dockerfile
Normal file → Executable file
2
Dockerfile
Normal file → Executable file
@ -5,4 +5,4 @@ WORKDIR /usr/src/app
|
|||||||
COPY package.json ./
|
COPY package.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
COPY . .
|
COPY . .
|
||||||
CMD [ "node", "main.js" ]
|
CMD ["/bin/sh", "-c", "node main.js 2> /logs/error.log 1> /logs/silvanus.log"]
|
25
README.md
Normal file → Executable file
25
README.md
Normal file → Executable file
@ -20,18 +20,27 @@ Otherwise, run `/setup` to set the proper channels for the bot to look in for th
|
|||||||
Use `/commands` to view a description of all my commands.
|
Use `/commands` to view a description of all my commands.
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
Silvanus requires permissions to `Send Messages` and `Send Messages in Threads` if applicable.
|
Silvanus requires permissions to `Send Messages` and `Send Messages in Threads` if applicable. If you plan to use the Role Menu Silvanus will also need permission to `Manage Roles`
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
* `/setup` - You only need to run this command if your server has its `/tree` and `/top trees` messages in separate channels.
|
* `/setup` - You only need to run this command if your server has its `/tree` and `/top trees` messages in separate channels.
|
||||||
* `/setupinfo` - Displays links to the current Tree and Tallest Trees messages configured in your server.
|
* `/setupinfo` - Displays your server's configuration information.
|
||||||
* `/compare` - Sends a refreshable embed that calculcates the height difference between your tree and the trees currently displayed on your Tallest Trees message. There is also an Active Growth Indicator (`[💧]`).
|
* `/compare` - Sends a refreshable embed that calculcates the height difference between your tree and the trees currently displayed on your Tallest Trees message. There is also an Active Growth Indicator (`[💧]`).
|
||||||
* `/setping` - Guild members with the `Manage Roles` permission can run this command to set up automatic reminders when your tree is ready to be watered.
|
* `/notifications` - Guild members with the `Manage Roles` permission can run this command to set up automatic reminders when your tree is ready to be watered or when fruit is dropping.
|
||||||
* Type a reminder message (including any `@pings` desired) and select a channel to send the reminders in.
|
* This feature relies on Grow A Tree's built-in Notification system. Refer to Grow A Tree for instructions on setting them up.
|
||||||
* Once this command has been run a new `Reset Ping` button will appear next time you refresh the `/compare` message.
|
* `watchchannel`: Select the channel you've configured Grow A Tree to send notifications in.
|
||||||
* Click the `Reset Ping` button to be sent a reminder the next time the tree is ready to be watered.
|
* `watermessage`: This option sets the message to send when the tree is ready to be watered. This can include `@pings`, links, etc.
|
||||||
* Use `/optout` to disable reminder messages for your server.
|
* `pingchannel`: Select the channel you want Silvanus to forward the notifications to.
|
||||||
|
* `fruitmessage`: Optional: This sets the message to send when the tree is dropping fruit. If not set, the `watermessage` will be used instead.
|
||||||
|
* `/rolemenu` - Creates a menu for users to give themselves Water and Fruit pingable roles.
|
||||||
|
* Requires `Manage Roles` permission to run.
|
||||||
|
* `waterrole`: Select the role to give users when they select the Water button
|
||||||
|
* `fruitrole`: Optional: Select the role to give users when they select the Fruit button
|
||||||
|
* If this option isn't set, no Fruit Role will be available for self-assignment.
|
||||||
* `/watertime` - Calculates the wait time between waters for a tree of a given height.
|
* `/watertime` - Calculates the wait time between waters for a tree of a given height.
|
||||||
* `/timetoheight` - Calculates how long it would take to go from `beginheight` to `endheight`.
|
* `height`: The height in feet to calculate for.
|
||||||
|
* `/timetoheight` - Calculates how long it would take to grow to a height
|
||||||
|
* `endheight`: The destination height, in feet.
|
||||||
|
* `beginheight`: Optional: The starting height, in feet. If this option isn't set, the current height of your tree will be used insead.
|
||||||
* `/reset` - Removes your server's configuration from the database.
|
* `/reset` - Removes your server's configuration from the database.
|
||||||
* `/help` - Displays the bot's help page and links to each command.
|
* `/help` - Displays the bot's help page and links to each command.
|
0
data/config.json
Normal file → Executable file
0
data/config.json
Normal file → Executable file
36
data/strings.json
Normal file → Executable file
36
data/strings.json
Normal file → Executable file
@ -7,7 +7,7 @@
|
|||||||
"info": "Silvanus is the ultimate Grow A Tree companion bot! Quickly compare your server's tree to others on the leaderboard with automatic calculation of tree height differences, active growth detection, watering time calculations, and more!\n\nImportant Note: Silvanus is only as up-to-date as your server's newest Tree and Tallest Trees messages. Make sure to refresh them before refreshing Silvanus' Compare message.",
|
"info": "Silvanus is the ultimate Grow A Tree companion bot! Quickly compare your server's tree to others on the leaderboard with automatic calculation of tree height differences, active growth detection, watering time calculations, and more!\n\nImportant Note: Silvanus is only as up-to-date as your server's newest Tree and Tallest Trees messages. Make sure to refresh them before refreshing Silvanus' Compare message.",
|
||||||
"setup": "If your ``/tree`` and ``/top trees`` messages are in the same channel, simple run </compare:1065346941166297128> in that channel and you're good to go!\n\nOtherwise, run </setup:1065407649363005561> to set the proper channels for the bot to look in for the ``/tree`` and ``/top trees`` messages.\n\nUse </commands:1069501270454456331> to view a description of all my commands.",
|
"setup": "If your ``/tree`` and ``/top trees`` messages are in the same channel, simple run </compare:1065346941166297128> in that channel and you're good to go!\n\nOtherwise, run </setup:1065407649363005561> to set the proper channels for the bot to look in for the ``/tree`` and ``/top trees`` messages.\n\nUse </commands:1069501270454456331> to view a description of all my commands.",
|
||||||
"permissions": "At a minimum, Silvanus requires permissions to `Send Messages` and `Send Messages in Threads` if applicable. If Analyzer is given permission to `Manage Messages`, the bot will delete the `.settree` and `.setranks` messages to reduce spam.",
|
"permissions": "At a minimum, Silvanus requires permissions to `Send Messages` and `Send Messages in Threads` if applicable. If Analyzer is given permission to `Manage Messages`, the bot will delete the `.settree` and `.setranks` messages to reduce spam.",
|
||||||
"allCommands": "</setup:1065407649363005561> - You only need to run this command if your server has its ``/tree`` and ``/top trees`` messages in separate channels.\n</setupinfo:1065413032374706196> - Displays links to the current Tree and Tallest Trees messages configured in your server.\n</compare:1065346941166297128> - Sends a refreshable embed that calculcates the height difference between your tree and the trees currently displayed on your Tallest Trees message. There is also an Active Growth Indicator (``[💧]``).\n</setping:1068373237995683902> - Guild members with the ``Manage Roles`` permission can run this command to set up automatic reminders when your tree is ready to be watered.\n Type a reminder message (including any ``@pings`` desired) and select a channel to send the reminders in.\n Once this command has been run a new ``Reset Ping`` button will appear next time you refresh the </compare:1065346941166297128> message.\n Click the ``Reset Ping`` button to be sent a reminder the next time the tree is ready to be watered.\n Use </optout:1068753032801693758> to disable reminder messages for your server.\n</watertime:1066970330029113444> - Calculates the wait time between waters for a tree of a given height.\n</timetoheight:1067727254634889227> - Calculates how long it would take to go from ``beginheight`` to ``endheight``.\n</reset:1065412317052944476> - Removes your server's configuration from the database.\n</help:1065346941166297129> - Displays the bot's help page and links to each command."
|
"allCommands": "</setup:1065407649363005561> - You only need to run this command if your server has its ``/tree`` and ``/top trees`` messages in separate channels.\n</setupinfo:1065413032374706196> - Displays your server's configuration information.\n</compare:1065346941166297128> - Sends a refreshable embed that calculcates the height difference between your tree and the trees currently displayed on your Tallest Trees message. There is also an Active Growth Indicator (``[💧]``).\n</notifications:0> - Guild members with the ``Manage Roles`` permission can run this command to set up automatic reminders when your tree is ready to be watered or when fruit is dropping.\n This feature relies on Grow A Tree's built-in Notification system. Refer to Grow A Tree for instructions on setting them up.\n ``watchchannel``: Select the channel you've configured Grow A Tree to send notifications in.\n ``watermessage``: This option sets the message to send when the tree is ready to be watered. This can include ``@pings``, links, etc.\n ``pingchannel``: Select the channel you want Silvanus to forward the notifications to.\n ``fruitmessage``: Optional: This sets the message to send when the tree is dropping fruit. If not set, the ``watermessage`` will be used instead.\n</rolemenu:0> - Creates a menu for users to give themselves Water and Fruit pingable roles.\n Requires ``Manage Roles`` permission to run.\n ``waterrole``: Select the role to give users when they select the Water button\n ``fruitrole``: Optional: Select the role to give users when they select the Fruit button\n If this option isn't set, no Fruit Role will be available for self-assignment.\n</watertime:1066970330029113444> - Calculates the wait time between waters for a tree of a given height.\n ``height``: The height in feet to calculate for.\n</timetoheight:1067727254634889227> - Calculates how long it would take to grow to a height\n ``endheight``: The destination height, in feet.\n ``beginheight``: Optional: The starting height, in feet. If this option isn't set, the current height of your tree will be used insead.\n</reset:1065412317052944476> - Removes your server's configuration from the database.\n</help:1065346941166297129> - Displays the bot's help page and links to each command."
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"compare": "</compare:1065346941166297128>",
|
"compare": "</compare:1065346941166297128>",
|
||||||
@ -19,21 +19,39 @@
|
|||||||
},
|
},
|
||||||
"embeds": {
|
"embeds": {
|
||||||
"footer": "Silvanus is not affiliated with Grow A Tree or Limbo Labs",
|
"footer": "Silvanus is not affiliated with Grow A Tree or Limbo Labs",
|
||||||
"color": "0x55FF55"
|
"color": "0x55FF55",
|
||||||
|
"errorTitle": "Oops!",
|
||||||
|
"errorPrefix": "There seems to have been a problem.",
|
||||||
|
"waterColor": "0x5555FF",
|
||||||
|
"fruitColor": "0xCC5555",
|
||||||
|
"waterTitle": "Water Notification",
|
||||||
|
"fruitTitle": "Fruit Notification",
|
||||||
|
"roleMenuTitle": "Role Menu",
|
||||||
|
"treeRoleMenu": [
|
||||||
|
"Use the buttons below to give yourself roles.\n\n",
|
||||||
|
"``💧`` - ",
|
||||||
|
": Get notifications when the tree is ready to be watered.",
|
||||||
|
"\n``🍎`` - ",
|
||||||
|
": Get notifications when fruit is falling from the tree."
|
||||||
|
],
|
||||||
|
"roleMenuFooter": "Tip: Tap the button again to remove the role."
|
||||||
},
|
},
|
||||||
"emoji": {
|
"emoji": {
|
||||||
"joint": "<:joint:862082955902976000>",
|
"joint": "<:joint:862082955902976000>",
|
||||||
"next": "⏭️",
|
"next": "⏭️",
|
||||||
"previous": "⏮️",
|
"previous": "⏮️",
|
||||||
"confirm": "☑️",
|
"confirm": "☑️",
|
||||||
"cancel": "❌"
|
"cancel": "❌",
|
||||||
|
"water": "💧",
|
||||||
|
"fruit": "🍎"
|
||||||
},
|
},
|
||||||
"urls": {
|
"urls": {
|
||||||
"avatar": "https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128",
|
"avatar": "https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128",
|
||||||
"supportServer": "https://discord.gg/g5JRGn7PxU"
|
"supportServer": "https://discord.gg/g5JRGn7PxU"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"noGuild": "Setup has not been completed yet. Try running </setup:1065407649363005561> or </help setup:1065346941166297129>"
|
"noGuild": "Setup has not been completed yet. Try running </setup:1065407649363005561> or </help setup:1065346941166297129>",
|
||||||
|
"invalidSubcommand": "Invalid subcommand detected."
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"treeAndLeaderboard": "Tree and leaderboard messages were both found, setup is complete. Run </setupinfo:1065413032374706196> to verify. Run </compare:1065346941166297128> to get started!",
|
"treeAndLeaderboard": "Tree and leaderboard messages were both found, setup is complete. Run </setupinfo:1065413032374706196> to verify. Run </compare:1065346941166297128> to get started!",
|
||||||
@ -42,7 +60,15 @@
|
|||||||
"missingLeaderboardMessage": "There was a problem finding the Tallest Trees message. Please make sure the ``/tree`` and ``/top trees`` messages are in this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
"missingLeaderboardMessage": "There was a problem finding the Tallest Trees message. Please make sure the ``/tree`` and ``/top trees`` messages are in this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
||||||
"missingLeaderboardChannel": "There was a problem finding the Tallest Trees channel, was it deleted? Please make sure the ``/tree`` and ``/top trees`` messages are in this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
"missingLeaderboardChannel": "There was a problem finding the Tallest Trees channel, was it deleted? Please make sure the ``/tree`` and ``/top trees`` messages are in this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
||||||
"missingTreeMessage": "There was a problem finding the Tree message. Please make sure the ``/tree`` and ``/top trees`` messages are this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
"missingTreeMessage": "There was a problem finding the Tree message. Please make sure the ``/tree`` and ``/top trees`` messages are this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
||||||
"missingTreeChannel": "There was a problem finding the Tree channel, was it deleted? Please make sure the ``/tree`` and ``/top trees`` messages are in this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels."
|
"missingTreeChannel": "There was a problem finding the Tree channel, was it deleted? Please make sure the ``/tree`` and ``/top trees`` messages are in this channel, or run </setup:1065407649363005561> to set the ``/tree`` and ``/top trees`` channels.",
|
||||||
|
"reset": "All guild configuration information has been removed from the database.",
|
||||||
|
"resetError": "There was a problem deleting your guild information, contact @voidf1sh#0420 for help.",
|
||||||
|
"noRoleMenu": "A role menu has not been created for this guild yet. Run </setup rolemenu:0> to create a role menu.",
|
||||||
|
"optout": "Notification relay has been disabled, to re-enable the relay use </notifications update:0> with no options."
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"water": "is ready to be watered again!",
|
||||||
|
"fruit": "Fruit is appearing!"
|
||||||
},
|
},
|
||||||
"temp": {}
|
"temp": {}
|
||||||
}
|
}
|
46
main.js
Normal file → Executable file
46
main.js
Normal file → Executable file
@ -4,7 +4,7 @@
|
|||||||
const dotenv = require('dotenv');
|
const dotenv = require('dotenv');
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
const token = process.env.TOKEN;
|
const token = process.env.TOKEN;
|
||||||
const statusChannelId = process.env.statusChannelId;
|
const statusChannelId = process.env.STATUSCHANNELID;
|
||||||
|
|
||||||
// Discord.JS
|
// Discord.JS
|
||||||
const { Client, GatewayIntentBits, Partials, ActivityType } = require('discord.js');
|
const { Client, GatewayIntentBits, Partials, ActivityType } = require('discord.js');
|
||||||
@ -25,13 +25,14 @@ const client = new Client({
|
|||||||
const fn = require('./modules/functions.js');
|
const fn = require('./modules/functions.js');
|
||||||
const strings = require('./data/strings.json');
|
const strings = require('./data/strings.json');
|
||||||
const dbfn = require('./modules/dbfn.js');
|
const dbfn = require('./modules/dbfn.js');
|
||||||
const isDev = process.env.isDev;
|
const isDev = process.env.DEBUG;
|
||||||
|
|
||||||
client.once('ready', () => {
|
client.once('ready', async () => {
|
||||||
fn.collections.slashCommands(client);
|
await fn.collectionBuilders.slashCommands(client);
|
||||||
|
await fn.collectionBuilders.guildInfos(client);
|
||||||
|
await fn.setupCollectors(client);
|
||||||
console.log('Ready!');
|
console.log('Ready!');
|
||||||
client.user.setActivity({ name: strings.activity.name, type: ActivityType.Watching });
|
client.user.setActivity({ name: strings.activity.name, type: ActivityType.Watching });
|
||||||
fn.checkReady(client);
|
|
||||||
if (isDev == 'false') {
|
if (isDev == 'false') {
|
||||||
client.channels.fetch(statusChannelId).then(channel => {
|
client.channels.fetch(statusChannelId).then(channel => {
|
||||||
channel.send(`${new Date().toISOString()} -- \nStartup Sequence Complete <@481933290912350209>`);
|
channel.send(`${new Date().toISOString()} -- \nStartup Sequence Complete <@481933290912350209>`);
|
||||||
@ -42,9 +43,9 @@ client.once('ready', () => {
|
|||||||
// slash-commands
|
// slash-commands
|
||||||
client.on('interactionCreate', async interaction => {
|
client.on('interactionCreate', async interaction => {
|
||||||
if (interaction.isCommand()) {
|
if (interaction.isCommand()) {
|
||||||
// if (isDev) {
|
if (isDev) {
|
||||||
// console.log(interaction);
|
console.log(interaction);
|
||||||
// }
|
}
|
||||||
const { commandName } = interaction;
|
const { commandName } = interaction;
|
||||||
|
|
||||||
if (client.slashCommands.has(commandName)) {
|
if (client.slashCommands.has(commandName)) {
|
||||||
@ -55,27 +56,32 @@ client.on('interactionCreate', async interaction => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interaction.isButton() && interaction.component.customId == 'refresh') {
|
if (interaction.isButton()) {
|
||||||
|
switch (interaction.component.customId) {
|
||||||
|
case 'refresh':
|
||||||
// console.log(JSON.stringify(interaction));
|
// console.log(JSON.stringify(interaction));
|
||||||
await fn.refresh(interaction).catch(err => {
|
await fn.refresh(interaction).catch(err => {
|
||||||
interaction.channel.send(fn.builders.errorEmbed(err));
|
interaction.channel.send(fn.builders.errorEmbed(err));
|
||||||
});
|
});
|
||||||
} else if (interaction.isButton() && interaction.component.customId == 'resetping') {
|
break;
|
||||||
await fn.resetPing(interaction);
|
case 'deleteping':
|
||||||
await fn.refresh(interaction).catch(err => {
|
|
||||||
interaction.channel.send(fn.builders.errorEmbed(err));
|
|
||||||
});
|
|
||||||
} else if (interaction.isButton() && interaction.component.customId == 'deleteping') {
|
|
||||||
if (interaction.message.deletable) {
|
if (interaction.message.deletable) {
|
||||||
await dbfn.setRemindedStatus(interaction.guildId, 0);
|
|
||||||
await dbfn.getGuildInfo(interaction.guildId).then(async res => {
|
|
||||||
const guildInfo = res.data;
|
|
||||||
await fn.refreshComparisonMessage(interaction.client, guildInfo);
|
|
||||||
});
|
|
||||||
await interaction.message.delete().catch(err => {
|
await interaction.message.delete().catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'waterpingrole':
|
||||||
|
const waterPingStatus = await fn.buttonHandlers.waterPing(interaction);
|
||||||
|
await interaction.reply(waterPingStatus).catch(e => console.error(e));
|
||||||
|
break;
|
||||||
|
case 'fruitpingrole':
|
||||||
|
const fruitPingStatus = await fn.buttonHandlers.fruitPing(interaction);
|
||||||
|
await interaction.reply(fruitPingStatus).catch(e => console.error(e));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
179
modules/CustomClasses.js
Executable file
179
modules/CustomClasses.js
Executable file
@ -0,0 +1,179 @@
|
|||||||
|
const mysql = require('mysql');
|
||||||
|
const db = mysql.createConnection({
|
||||||
|
host: process.env.DBHOST,
|
||||||
|
user: process.env.DBUSER,
|
||||||
|
password: process.env.DBPASS,
|
||||||
|
database: process.env.DBNAME,
|
||||||
|
port: process.env.DBPORT
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
GuildInfo: class {
|
||||||
|
constructor() {
|
||||||
|
this.guildId = "";
|
||||||
|
this.treeName = "";
|
||||||
|
this.treeHeight = 0;
|
||||||
|
this.treeMessageId = "";
|
||||||
|
this.treeChannelId = "";
|
||||||
|
this.leaderboardMessageId = "";
|
||||||
|
this.leaderboardChannelId = "";
|
||||||
|
this.waterMessage = "";
|
||||||
|
this.waterRoleId = "";
|
||||||
|
this.fruitMessage = "";
|
||||||
|
this.fruitRoleId = "";
|
||||||
|
this.reminderChannelId = "";
|
||||||
|
this.watchChannelId = "";
|
||||||
|
this.notificationsEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setId(id) {
|
||||||
|
this.guildId = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setName(name) {
|
||||||
|
this.treeName = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setHeight(height) {
|
||||||
|
this.treeHeight = height;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setTreeMessage(messageId, channelId) {
|
||||||
|
this.treeMessageId = messageId;
|
||||||
|
this.treeChannelId = channelId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setLeaderboardMessage(messageId, channelId) {
|
||||||
|
this.leaderboardMessageId = messageId;
|
||||||
|
this.leaderboardChannelId = channelId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setReminders(waterMessage, fruitMessage, reminderChannelId, watchChannelId, enabled) {
|
||||||
|
if (waterMessage) this.waterMessage = waterMessage;
|
||||||
|
if (fruitMessage) this.fruitMessage = fruitMessage;
|
||||||
|
if (reminderChannelId) this.reminderChannelId = reminderChannelId;
|
||||||
|
if (watchChannelId) this.watchChannelId = watchChannelId;
|
||||||
|
if (enabled) this.notificationsEnabled = enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
setRoles(waterRoleId, fruitRoleId) {
|
||||||
|
this.waterRoleId = waterRoleId;
|
||||||
|
if (fruitRoleId) this.fruitRoleId = fruitRoleId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
queryBuilder(query) {
|
||||||
|
let queryParts = [];
|
||||||
|
switch (query) {
|
||||||
|
case "setAll":
|
||||||
|
queryParts = [
|
||||||
|
`INSERT INTO guild_info `,
|
||||||
|
`(guild_id, `,
|
||||||
|
`tree_name, `,
|
||||||
|
`tree_height, `,
|
||||||
|
`tree_message_id, `,
|
||||||
|
`tree_channel_id, `,
|
||||||
|
`leaderboard_message_id, `,
|
||||||
|
`leaderboard_channel_id, `,
|
||||||
|
`water_message, `,
|
||||||
|
`fruit_message, `,
|
||||||
|
`reminder_channel_id, `,
|
||||||
|
`watch_channel_id) `,
|
||||||
|
`VALUES (${db.escape(this.guildId)}, `,
|
||||||
|
`${db.escape(this.treeName)}, `,
|
||||||
|
`${db.escape(this.treeHeight)}, `,
|
||||||
|
`${db.escape(this.treeMessageId)}, `,
|
||||||
|
`${db.escape(this.treeChannelId)}, `,
|
||||||
|
`${db.escape(this.leaderboardMessageId)}, `,
|
||||||
|
`${db.escape(this.leaderboardChannelId)}, `,
|
||||||
|
`${db.escape(this.waterMessage)}, `,
|
||||||
|
`${db.escape(this.fruitMessage)}, `,
|
||||||
|
`${db.escape(this.reminderChannelId)}, `,
|
||||||
|
`${db.escape(this.watchChannelId)}) `,
|
||||||
|
`ON DUPLICATE KEY UPDATE tree_name = ${db.escape(this.treeName)}, `,
|
||||||
|
`tree_height = ${db.escape(this.treeHeight)}, `,
|
||||||
|
`tree_message_id = ${db.escape(this.treeMessageId)}, `,
|
||||||
|
`tree_channel_id = ${db.escape(this.treeChannelId)}, `,
|
||||||
|
`leaderboard_message_id = ${db.escape(this.leaderboardMessageId)}, `,
|
||||||
|
`leaderboard_channel_id = ${db.escape(this.leaderboardChannelId)}, `,
|
||||||
|
`water_message = ${db.escape(this.waterMessage)}, `,
|
||||||
|
`fruit_message = ${db.escape(this.fruitMessage)}, `,
|
||||||
|
`reminder_channel_id = ${db.escape(this.reminderChannelId)}, `,
|
||||||
|
`watch_channel_id = ${db.escape(this.watchChannelId)})`
|
||||||
|
];
|
||||||
|
return queryParts.join('');
|
||||||
|
break;
|
||||||
|
case "setReminders":
|
||||||
|
queryParts = [
|
||||||
|
`INSERT INTO guild_info (guild_id, water_message, fruit_message, reminder_channel_id, watch_channel_id, notifications_enabled) VALUES (`,
|
||||||
|
`${db.escape(this.guildId)},`,
|
||||||
|
`${db.escape(this.waterMessage)},`,
|
||||||
|
`${db.escape(this.fruitMessage)},`,
|
||||||
|
`${db.escape(this.reminderChannelId)},`,
|
||||||
|
`${db.escape(this.watchChannelId)},`,
|
||||||
|
`${db.escape(this.notificationsEnabled)}`,
|
||||||
|
`) ON DUPLICATE KEY UPDATE water_message = ${db.escape(this.waterMessage)}, `,
|
||||||
|
`fruit_message = ${db.escape(this.fruitMessage)}, `,
|
||||||
|
`reminder_channel_id = ${db.escape(this.reminderChannelId)}, `,
|
||||||
|
`watch_channel_id = ${db.escape(this.watchChannelId)},`,
|
||||||
|
`notifications_enabled = ${db.escape(this.notificationsEnabled)}`
|
||||||
|
];
|
||||||
|
return queryParts.join('');
|
||||||
|
break;
|
||||||
|
case "setTreeMessage":
|
||||||
|
queryParts = [
|
||||||
|
`UPDATE guild_info SET tree_message_id = ${db.escape(this.treeMessageId)}, `,
|
||||||
|
`tree_channel_id = ${db.escape(this.treeChannelId)}, `,
|
||||||
|
`WHERE guild_id = ${db.escape(this.guildId)}`
|
||||||
|
];
|
||||||
|
return queryParts.join('');
|
||||||
|
break;
|
||||||
|
case "setLeaderboardMessage":
|
||||||
|
queryParts = [
|
||||||
|
`UPDATE guild_info SET leaderboard_message_id = ${db.escape(this.leaderboardMessageId)}, `,
|
||||||
|
`leaderboard_channel_id = ${db.escape(this.leaderboardChannelId)}, `,
|
||||||
|
`WHERE guild_id = ${db.escape(this.guildId)}`
|
||||||
|
];
|
||||||
|
return queryParts.join('');
|
||||||
|
break;
|
||||||
|
case "setRoles":
|
||||||
|
if (this.fruitRoleId != "") {
|
||||||
|
queryParts = [
|
||||||
|
`INSERT INTO guild_info (`,
|
||||||
|
`guild_id, water_role_id, fruit_role_id`,
|
||||||
|
`) VALUES (`,
|
||||||
|
`${db.escape(this.guildId)}, ${db.escape(this.waterRoleId)}, ${db.escape(this.fruitRoleId)}`,
|
||||||
|
`) ON DUPLICATE KEY UPDATE water_role_id = ${db.escape(this.waterRoleId)}, `,
|
||||||
|
`fruit_role_id = ${db.escape(this.fruitRoleId)}`
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
queryParts = [
|
||||||
|
`UPDATE guild_info SET water_role_id = ${db.escape(this.waterRoleId)} `,
|
||||||
|
`WHERE guild_id = ${db.escape(this.guildId)}`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return queryParts.join('');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generateSetupInfo() {
|
||||||
|
let setupInfoParts = [
|
||||||
|
`Here is your server's configuration:`,
|
||||||
|
`Tree Name: ${this.treeName}`,
|
||||||
|
`Tree Height: ${this.treeHeight}`,
|
||||||
|
`Tree Channel: <#${this.treeChannelId}>`,
|
||||||
|
`[Tree Link](https://discord.com/channels/${this.guildId}/${this.treeChannelId}/${this.treeMessageId})`,
|
||||||
|
`Leaderboard Channel: <#${this.leaderboardChannelId}>`,
|
||||||
|
`[Leaderboard Link](https://discord.com/channels/${this.guildId}/${this.leaderboardChannelId}/${this.leaderboardMessageId})`,
|
||||||
|
`Notification Watch Channel: <#${this.watchChannelId}>`,
|
||||||
|
`Notification Relay Channel: <#${this.reminderChannelId}>`,
|
||||||
|
`Water Message: ${this.waterMessage}`,
|
||||||
|
`Fruit Message: ${this.fruitMessage}`,
|
||||||
|
`Water Role: <@&${this.waterRoleId}>`,
|
||||||
|
`Fruit Role: <@&${this.fruitRoleId}>`
|
||||||
|
]
|
||||||
|
return setupInfoParts.join('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
modules/_clear-commands.js
Normal file → Executable file
0
modules/_clear-commands.js
Normal file → Executable file
0
modules/_deploy-commands.js
Normal file → Executable file
0
modules/_deploy-commands.js
Normal file → Executable file
28
modules/_deploy-global.js
Normal file → Executable file
28
modules/_deploy-global.js
Normal file → Executable file
@ -4,7 +4,7 @@ dotenv.config();
|
|||||||
|
|
||||||
const { REST } = require('@discordjs/rest');
|
const { REST } = require('@discordjs/rest');
|
||||||
const { Routes } = require('discord-api-types/v9');
|
const { Routes } = require('discord-api-types/v9');
|
||||||
const clientId = process.env.clientId;
|
const clientId = process.env.BOTID;
|
||||||
const token = process.env.TOKEN;
|
const token = process.env.TOKEN;
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
@ -18,13 +18,28 @@ for (const file of commandFiles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(commands);
|
console.log(`Token: ${token} Client ID: ${clientId}`);
|
||||||
|
|
||||||
const rest = new REST({ version: '9' }).setToken(token);
|
const rest = new REST({ version: '9' }).setToken(token);
|
||||||
|
|
||||||
(async () => {
|
async function deleteCommands() {
|
||||||
try {
|
try {
|
||||||
console.log('Started refreshing application (/) commands.');
|
console.log('Started deleting application (/) commands.');
|
||||||
|
|
||||||
|
await rest.put(
|
||||||
|
Routes.applicationCommands(clientId),
|
||||||
|
{ body: "" },
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('Successfully deleted application (/) commands.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadCommands() {
|
||||||
|
try {
|
||||||
|
console.log('Started reloading application (/) commands.');
|
||||||
|
|
||||||
await rest.put(
|
await rest.put(
|
||||||
Routes.applicationCommands(clientId),
|
Routes.applicationCommands(clientId),
|
||||||
@ -36,4 +51,9 @@ const rest = new REST({ version: '9' }).setToken(token);
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await deleteCommands();
|
||||||
|
await uploadCommands();
|
||||||
})();
|
})();
|
11
modules/_prepareStrings.js
Normal file → Executable file
11
modules/_prepareStrings.js
Normal file → Executable file
@ -14,20 +14,21 @@
|
|||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const replaceAll = require('string.prototype.replaceall');
|
const replaceAll = require('string.prototype.replaceall');
|
||||||
const string = fs.readFileSync('./data/rawstring.txt').toString();
|
const path = "./modules/input.txt";
|
||||||
|
const string = fs.readFileSync(path).toString();
|
||||||
let newString = replaceAll(string, '\* ', '');
|
let newString = replaceAll(string, '\* ', '');
|
||||||
newString = replaceAll(newString, '\n', '\\n');
|
newString = replaceAll(newString, '\r\n', '\\n');
|
||||||
newString = replaceAll(newString, '\t', ' - ');
|
newString = replaceAll(newString, '\t', ' - ');
|
||||||
newString = replaceAll(newString, '`/setup`', '</setup:1065407649363005561>');
|
newString = replaceAll(newString, '`/setup`', '</setup:1065407649363005561>');
|
||||||
newString = replaceAll(newString, '`/setupinfo`', '</setupinfo:1065413032374706196>');
|
newString = replaceAll(newString, '`/setupinfo`', '</setupinfo:1065413032374706196>');
|
||||||
newString = replaceAll(newString, '`/compare`', '</compare:1065346941166297128>');
|
newString = replaceAll(newString, '`/compare`', '</compare:1065346941166297128>');
|
||||||
newString = replaceAll(newString, '`/setping`', '</setping:1068373237995683902>');
|
|
||||||
newString = replaceAll(newString, '`/optout`', '</optout:1068753032801693758>');
|
|
||||||
newString = replaceAll(newString, '`/watertime`', '</watertime:1066970330029113444>');
|
newString = replaceAll(newString, '`/watertime`', '</watertime:1066970330029113444>');
|
||||||
newString = replaceAll(newString, '`/timetoheight`', '</timetoheight:1067727254634889227>');
|
newString = replaceAll(newString, '`/timetoheight`', '</timetoheight:1067727254634889227>');
|
||||||
newString = replaceAll(newString, '`/reset`', '</reset:1065412317052944476>');
|
newString = replaceAll(newString, '`/reset`', '</reset:1065412317052944476>');
|
||||||
newString = replaceAll(newString, '`/help`', '</help:1065346941166297129>');
|
newString = replaceAll(newString, '`/help`', '</help:1065346941166297129>');
|
||||||
newString = replaceAll(newString, '`/commands`', '</commands:1069501270454456331>');
|
newString = replaceAll(newString, '`/commands`', '</commands:1069501270454456331>');
|
||||||
|
newString = replaceAll(newString, '`/notifications`', '</notifications:0>');
|
||||||
|
newString = replaceAll(newString, '`/rolemenu`', '</rolemenu:0>');
|
||||||
newString = replaceAll(newString, '`', '``');
|
newString = replaceAll(newString, '`', '``');
|
||||||
fs.writeFileSync('./data/rawstring.txt', newString);
|
fs.writeFileSync(path, newString);
|
||||||
return "Done";
|
return "Done";
|
303
modules/dbfn.js
Normal file → Executable file
303
modules/dbfn.js
Normal file → Executable file
@ -2,6 +2,7 @@ const dotenv = require('dotenv');
|
|||||||
dotenv.config();
|
dotenv.config();
|
||||||
const debugMode = process.env.DEBUG || true;
|
const debugMode = process.env.DEBUG || true;
|
||||||
const mysql = require('mysql');
|
const mysql = require('mysql');
|
||||||
|
const { GuildInfo } = require('./CustomClasses.js');
|
||||||
|
|
||||||
/* Table Structures
|
/* Table Structures
|
||||||
guild_info
|
guild_info
|
||||||
@ -33,42 +34,6 @@ leaderboard
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createGuildTables(guildId) {
|
|
||||||
const db = mysql.createConnection({
|
|
||||||
host: process.env.DBHOST,
|
|
||||||
user: process.env.DBUSER,
|
|
||||||
password: process.env.DBPASS,
|
|
||||||
database: process.env.DBNAME,
|
|
||||||
port: process.env.DBPORT
|
|
||||||
});
|
|
||||||
db.connect((err) => {
|
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
|
||||||
});
|
|
||||||
// Create the guild-information and rank-information tables to be used.
|
|
||||||
const createGuildInfoTableQuery = "CREATE TABLE IF NOT EXISTS guild_info(guild_id VARCHAR(50) NOT NULL, tree_name VARCHAR(100) NOT NULL DEFAULT 'Run /setup where your tree is.', tree_height INT(10) NOT NULL DEFAULT 0, tree_message_id VARCHAR(50) NOT NULL DEFAULT 'Run /setup where your tree is.', tree_channel_id VARCHAR(50) NOT NULL DEFAULT 'Run /setup where your tree is.', leaderboard_message_id VARCHAR(50) NOT NULL DEFAULT 'Run /setup where your leaderboard is.', leaderboard_channel_id VARCHAR(50) NOT NULL DEFAULT 'Run /setup where your leaderboard is.', CONSTRAINT guild_pk PRIMARY KEY (guild_id))";
|
|
||||||
const createLeaderboardTableQuery = "CREATE TABLE IF NOT EXISTS leaderboard(id INT(10) NOT NULL AUTO_INCREMENT,guild_id VARCHAR(50) NOT NULL,tree_name VARCHAR(100) NOT NULL,tree_rank INT(10) NOT NULL,tree_height INT(10) NOT NULL DEFAULT 1,has_pin TINYINT(1) NOT NULL DEFAULT 0,timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT id_pk PRIMARY KEY(id))";
|
|
||||||
// TODO run the queries, then add a call to this function at the beginning of main.js or functions.js
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(createGuildInfoTableQuery, (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject("Error creating the guild_info table: " + err.message);
|
|
||||||
console.error("Offending query: " + createGuildInfoTableQuery);
|
|
||||||
db.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.query(createLeaderboardTableQuery, (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject("Error creating the leaderboard table: " + err.message);
|
|
||||||
console.error("Offending query: " + createLeaderboardTableQuery);
|
|
||||||
db.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve({ "status": "Successfully checked both tables.", "data": null });
|
|
||||||
db.end();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getGuildInfo(guildId) {
|
getGuildInfo(guildId) {
|
||||||
const db = mysql.createConnection({
|
const db = mysql.createConnection({
|
||||||
host: process.env.DBHOST,
|
host: process.env.DBHOST,
|
||||||
@ -91,45 +56,26 @@ module.exports = {
|
|||||||
db.end();
|
db.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*const guildInfo = { "guildId": "123",
|
|
||||||
"treeName": "name",
|
|
||||||
"treeHeight": 123,
|
|
||||||
"treeMessageId": "123",
|
|
||||||
"treeChannelId": "123",
|
|
||||||
"leaderboardMessageId": "123",
|
|
||||||
"leaderboardChannelId": "123",
|
|
||||||
"reminderMessage": "Abc",
|
|
||||||
"reminderChannelId": "123",
|
|
||||||
"remindedStatus": 0,
|
|
||||||
"comparisonMessageId": "123"
|
|
||||||
};*/
|
|
||||||
if (res.length == 0) {
|
if (res.length == 0) {
|
||||||
reject("There is no database entry for your guild yet. Try running /setup");
|
reject("There is no database entry for your guild yet. Try running /setup");
|
||||||
db.end();
|
db.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
row = res[0];
|
row = res[0];
|
||||||
const guildInfo = {
|
const guildInfo = new GuildInfo()
|
||||||
"guildId": guildId,
|
.setId(row.guild_id)
|
||||||
"treeName": row.tree_name,
|
.setName(row.tree_name)
|
||||||
"treeHeight": row.tree_height,
|
.setHeight(row.tree_height)
|
||||||
"treeMessageId": row.tree_message_id,
|
.setTreeMessage(row.tree_message_id, row.tree_channel_id)
|
||||||
"treeChannelId": row.tree_channel_id,
|
.setLeaderboardMessage(row.leaderboard_message_id, row.leaderboard_channel_id)
|
||||||
"leaderboardMessageId": row.leaderboard_message_id,
|
.setReminders(row.water_message, row.fruit_message, row.reminder_channel_id, row.watch_channel_id, row.notifications_enabled)
|
||||||
"leaderboardChannelId": row.leaderboard_channel_id,
|
.setRoles(row.water_role_id, row.fruit_role_id);
|
||||||
"reminderMessage": row.ping_role_id,
|
|
||||||
"reminderChannelId": row.ping_channel_id,
|
|
||||||
"remindedStatus": row.reminded_status,
|
|
||||||
"reminderOptIn": row.reminder_optin,
|
|
||||||
"comparisonMessageId": row.comparison_message_id,
|
|
||||||
"comparisonChannelId": row.comparison_channel_id
|
|
||||||
};
|
|
||||||
db.end();
|
db.end();
|
||||||
resolve({ "status": "Successfully fetched guild information", "data": guildInfo });
|
resolve(guildInfo);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setGuildInfo(guildInfo) {
|
getAllGuildInfos() {
|
||||||
const db = mysql.createConnection({
|
const db = mysql.createConnection({
|
||||||
host: process.env.DBHOST,
|
host: process.env.DBHOST,
|
||||||
user: process.env.DBUSER,
|
user: process.env.DBUSER,
|
||||||
@ -140,21 +86,62 @@ module.exports = {
|
|||||||
db.connect((err) => {
|
db.connect((err) => {
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
if (err) throw `Error connecting to the database: ${err.message}`;
|
||||||
});
|
});
|
||||||
// Returns a Promise, resolve({ "status": "", "data": null })
|
// Get a server's tree information from the database
|
||||||
// guildInfo = { "guildId": "123", "treeName": "name", "treeHeight": 123, "treeMessageId": "123", "treeChannelId": "123", "leaderboardMessageId": "123", "leaderboardChannelId": "123"}
|
const query = 'SELECT * FROM guild_info';
|
||||||
// Set a server's tree information in the database
|
// TODO run this query and return a promise then structure the output into a GuildInfo object. resolve with { "status": , "data": guildInfo }
|
||||||
const insertGuildInfoQuery = `INSERT INTO guild_info (guild_id, tree_name, tree_height, tree_message_id, tree_channel_id, leaderboard_message_id, leaderboard_channel_id) VALUES (${db.escape(guildInfo.guildId)}, ${db.escape(guildInfo.treeName)}, ${db.escape(guildInfo.treeHeight)},${db.escape(guildInfo.treeMessageId)}, ${db.escape(guildInfo.treeChannelId)}, ${db.escape(guildInfo.leaderboardMessageId)}, ${db.escape(guildInfo.leaderboardChannelId)}) ON DUPLICATE KEY UPDATE tree_name = ${db.escape(guildInfo.treeName)},tree_height = ${db.escape(guildInfo.treeHeight)},tree_message_id = ${db.escape(guildInfo.treeMessageId)},tree_channel_id = ${db.escape(guildInfo.treeChannelId)},leaderboard_message_id = ${db.escape(guildInfo.leaderboardMessageId)},leaderboard_channel_id = ${db.escape(guildInfo.leaderboardChannelId)}`;
|
|
||||||
// TODO run this query and return a promise, then resolve with { "status": , "data": null }
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.query(insertGuildInfoQuery, (err, res) => {
|
db.query(query, (err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
reject("Error fetching all guild infos: " + err.message);
|
||||||
|
db.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.length == 0) {
|
||||||
|
reject("There are no servers yet!");
|
||||||
|
db.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let guildInfos = [];
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
let row = res[i];
|
||||||
|
guildInfos.push(new GuildInfo()
|
||||||
|
.setId(row.guild_id)
|
||||||
|
.setName(row.tree_name)
|
||||||
|
.setHeight(row.tree_height)
|
||||||
|
.setTreeMessage(row.tree_message_id, row.tree_channel_id)
|
||||||
|
.setLeaderboardMessage(row.leaderboard_message_id, row.leaderboard_channel_id)
|
||||||
|
.setReminders(row.water_message, row.fruit_message, row.reminder_channel_id, row.watch_channel_id, row.notifications_enabled)
|
||||||
|
.setRoles(row.water_role_id, row.fruit_role_id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.end();
|
||||||
|
resolve(guildInfos);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setGuildInfo(query) {
|
||||||
|
const db = mysql.createConnection({
|
||||||
|
host: process.env.DBHOST,
|
||||||
|
user: process.env.DBUSER,
|
||||||
|
password: process.env.DBPASS,
|
||||||
|
database: process.env.DBNAME,
|
||||||
|
port: process.env.DBPORT
|
||||||
|
});
|
||||||
|
db.connect((err) => {
|
||||||
|
if (err) throw `Error connecting to the database: ${err.message}`;
|
||||||
|
});
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
db.query(query, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err + "\n" + query);
|
||||||
reject("Error setting the guild info: " + err.message);
|
reject("Error setting the guild info: " + err.message);
|
||||||
db.end();
|
db.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.end();
|
db.end();
|
||||||
resolve({ "status": "Successfully set the guild information", "data": null });
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -352,177 +339,5 @@ module.exports = {
|
|||||||
resolve({ "status": "Successfully fetched historic 24hr tree.", "data": hist24hTree });
|
resolve({ "status": "Successfully fetched historic 24hr tree.", "data": hist24hTree });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
|
||||||
setReminderInfo(guildId, reminderMessage, reminderChannelId) {
|
|
||||||
const db = mysql.createConnection({
|
|
||||||
host: process.env.DBHOST,
|
|
||||||
user: process.env.DBUSER,
|
|
||||||
password: process.env.DBPASS,
|
|
||||||
database: process.env.DBNAME,
|
|
||||||
port: process.env.DBPORT
|
|
||||||
});
|
|
||||||
db.connect((err) => {
|
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
|
||||||
});
|
|
||||||
// Returns a Promise, resolve({ "status": "", "data": leaderboard })
|
|
||||||
const insertReminderInfoQuery = `UPDATE guild_info SET ping_role_id = ${db.escape(reminderMessage)}, ping_channel_id = ${db.escape(reminderChannelId)} WHERE guild_id = ${db.escape(guildId)}`;
|
|
||||||
// TODO run the query and return a promise then process the results. resolve with { "status": , "data": leaderboard }
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(insertReminderInfoQuery, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
db.end();
|
|
||||||
reject("Error updating the reminder info: " + err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.end();
|
|
||||||
resolve({ "status": `Successfully set the reminder message to "${reminderMessage}" in <#${reminderChannelId}>`, "data": res });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setRemindedStatus(guildId, remindedStatus) {
|
|
||||||
const db = mysql.createConnection({
|
|
||||||
host: process.env.DBHOST,
|
|
||||||
user: process.env.DBUSER,
|
|
||||||
password: process.env.DBPASS,
|
|
||||||
database: process.env.DBNAME,
|
|
||||||
port: process.env.DBPORT
|
|
||||||
});
|
|
||||||
db.connect((err) => {
|
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
|
||||||
});
|
|
||||||
// Returns a Promise, resolve({ "status": "", "data": leaderboard })
|
|
||||||
const setRemindedStatusQuery = `UPDATE guild_info SET reminded_status = ${db.escape(remindedStatus)} WHERE guild_id = ${db.escape(guildId)}`;
|
|
||||||
// TODO run the query and return a promise then process the results. resolve with { "status": , "data": leaderboard }
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(setRemindedStatusQuery, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
db.end();
|
|
||||||
reject("Error updating the reminded status: " + err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.end();
|
|
||||||
resolve({ "status": `Successfully set the reminded status to ${remindedStatus}`, "data": res });
|
|
||||||
// console.log("Boop: " + remindedStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setReminderOptIn(guildId, optIn) {
|
|
||||||
const db = mysql.createConnection({
|
|
||||||
host: process.env.DBHOST,
|
|
||||||
user: process.env.DBUSER,
|
|
||||||
password: process.env.DBPASS,
|
|
||||||
database: process.env.DBNAME,
|
|
||||||
port: process.env.DBPORT
|
|
||||||
});
|
|
||||||
db.connect((err) => {
|
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
|
||||||
});
|
|
||||||
// Returns a Promise, resolve({ "status": "", "data": leaderboard })
|
|
||||||
const setReminderOptInQuery = `UPDATE guild_info SET reminder_optin = ${db.escape(optIn)} WHERE guild_id = ${db.escape(guildId)}`;
|
|
||||||
// TODO run the query and return a promise then process the results. resolve with { "status": , "data": leaderboard }
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(setReminderOptInQuery, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
db.end();
|
|
||||||
reject("Error updating the reminder opt-in status: " + err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.end();
|
|
||||||
resolve({ "status": `Successfully set the reminder opt-in status to ${optIn}`, "data": res });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getOptedInGuilds() {
|
|
||||||
const db = mysql.createConnection({
|
|
||||||
host: process.env.DBHOST,
|
|
||||||
user: process.env.DBUSER,
|
|
||||||
password: process.env.DBPASS,
|
|
||||||
database: process.env.DBNAME,
|
|
||||||
port: process.env.DBPORT
|
|
||||||
});
|
|
||||||
db.connect((err) => {
|
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
|
||||||
});
|
|
||||||
// Get a server's tree information from the database
|
|
||||||
const getOptedInGuildsQuery = `SELECT * FROM guild_info WHERE reminder_optin = 1`;
|
|
||||||
// TODO run this query and return a promise then structure the output into a GuildInfo object. resolve with { "status": , "data": guildInfo }
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(getOptedInGuildsQuery, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
reject("Error fetching guild information: " + err.message);
|
|
||||||
db.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*const guildInfo = { "guildId": "123",
|
|
||||||
"treeName": "name",
|
|
||||||
"treeHeight": 123,
|
|
||||||
"treeMessageId": "123",
|
|
||||||
"treeChannelId": "123",
|
|
||||||
"leaderboardMessageId": "123",
|
|
||||||
"leaderboardChannelId": "123",
|
|
||||||
"reminderMessage": "Abc",
|
|
||||||
"reminderChannelId": "123",
|
|
||||||
"remindedStatus": 0,
|
|
||||||
"comparisonMessageId": "123"
|
|
||||||
};*/
|
|
||||||
if (res.length == 0) {
|
|
||||||
resolve({ "status": "No servers have opted in yet" });
|
|
||||||
db.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
row = res[0];
|
|
||||||
let guilds = [];
|
|
||||||
res.forEach(row => {
|
|
||||||
guilds.push({
|
|
||||||
"guildId": row.guild_id,
|
|
||||||
"treeName": row.tree_name,
|
|
||||||
"treeHeight": row.tree_height,
|
|
||||||
"treeMessageId": row.tree_message_id,
|
|
||||||
"treeChannelId": row.tree_channel_id,
|
|
||||||
"leaderboardMessageId": row.leaderboard_message_id,
|
|
||||||
"leaderboardChannelId": row.leaderboard_channel_id,
|
|
||||||
"reminderMessage": row.ping_role_id,
|
|
||||||
"reminderChannelId": row.ping_channel_id,
|
|
||||||
"remindedStatus": row.reminded_status,
|
|
||||||
"comparisonMessageId": row.comparison_message_id,
|
|
||||||
"comparisonChannelId": row.comparison_channel_id
|
|
||||||
});
|
|
||||||
});
|
|
||||||
db.end();
|
|
||||||
resolve({ "status": "Successfully fetched guild information", "data": guilds });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setComparisonMessage(comparisonMessage, guildId) {
|
|
||||||
const db = mysql.createConnection({
|
|
||||||
host: process.env.DBHOST,
|
|
||||||
user: process.env.DBUSER,
|
|
||||||
password: process.env.DBPASS,
|
|
||||||
database: process.env.DBNAME,
|
|
||||||
port: process.env.DBPORT
|
|
||||||
});
|
|
||||||
db.connect((err) => {
|
|
||||||
if (err) throw `Error connecting to the database: ${err.message}`;
|
|
||||||
});
|
|
||||||
// Returns a Promise, resolve({ "status": "", "data": leaderboard })
|
|
||||||
const setComparisonMessageQuery = `UPDATE guild_info SET comparison_message_id = ${db.escape(comparisonMessage.id)}, comparison_channel_id = ${db.escape(comparisonMessage.channel.id)} WHERE guild_id = ${db.escape(guildId)}`;
|
|
||||||
// console.log(JSON.stringify(comparisonMessage));
|
|
||||||
// TODO run the query and return a promise then process the results. resolve with { "status": , "data": leaderboard }
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(setComparisonMessageQuery, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
db.end();
|
|
||||||
reject("Error updating the comparison message ID: " + err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.end();
|
|
||||||
resolve({ "status": `Successfully set the comparison message ID: ${comparisonMessage}`, "data": res });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
341
modules/functions.js
Normal file → Executable file
341
modules/functions.js
Normal file → Executable file
@ -11,6 +11,7 @@ const fs = require('fs');
|
|||||||
// Discord.js
|
// Discord.js
|
||||||
const Discord = require('discord.js');
|
const Discord = require('discord.js');
|
||||||
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord;
|
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord;
|
||||||
|
const { GuildInfo } = require('./CustomClasses');
|
||||||
|
|
||||||
// Various imports from other files
|
// Various imports from other files
|
||||||
const config = require('../data/config.json');
|
const config = require('../data/config.json');
|
||||||
@ -19,15 +20,9 @@ const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => fil
|
|||||||
const dbfn = require('./dbfn.js');
|
const dbfn = require('./dbfn.js');
|
||||||
const { finished } = require('stream');
|
const { finished } = require('stream');
|
||||||
|
|
||||||
dbfn.createGuildTables().then(res => {
|
|
||||||
console.log(res.status);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
const functions = {
|
const functions = {
|
||||||
// Functions for managing and creating Collections
|
// Functions for managing and creating Collections
|
||||||
collections: {
|
collectionBuilders: {
|
||||||
// Create the collection of slash commands
|
// Create the collection of slash commands
|
||||||
slashCommands(client) {
|
slashCommands(client) {
|
||||||
if (!client.slashCommands) client.slashCommands = new Discord.Collection();
|
if (!client.slashCommands) client.slashCommands = new Discord.Collection();
|
||||||
@ -39,6 +34,15 @@ const functions = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isDev) console.log('Slash Commands Collection Built');
|
if (isDev) console.log('Slash Commands Collection Built');
|
||||||
|
},
|
||||||
|
async guildInfos(client) {
|
||||||
|
const guildInfos = await dbfn.getAllGuildInfos();
|
||||||
|
if (!client.guildInfos) client.guildInfos = new Discord.Collection();
|
||||||
|
client.guildInfos.clear();
|
||||||
|
for (const guildInfo of guildInfos) {
|
||||||
|
client.guildInfos.set(guildInfo.guildId, guildInfo);
|
||||||
|
}
|
||||||
|
return 'guildInfos Collection Built';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builders: {
|
builders: {
|
||||||
@ -64,43 +68,51 @@ const functions = {
|
|||||||
.addComponents(
|
.addComponents(
|
||||||
refreshButton
|
refreshButton
|
||||||
);
|
);
|
||||||
if (guildInfo.reminderOptIn == 1 && guildInfo.remindedStatus == 1) {
|
|
||||||
const resetPingButton = new ButtonBuilder()
|
|
||||||
.setCustomId('resetping')
|
|
||||||
.setLabel('Reset Ping')
|
|
||||||
.setStyle(ButtonStyle.Secondary);
|
|
||||||
refreshActionRow.addComponents(resetPingButton);
|
|
||||||
} else if (guildInfo.reminderOptIn == 1 && guildInfo.remindedStatus == 0) {
|
|
||||||
const resetPingButton = new ButtonBuilder()
|
|
||||||
.setCustomId('resetping')
|
|
||||||
.setLabel('[Armed]')
|
|
||||||
.setStyle(ButtonStyle.Secondary);
|
|
||||||
refreshActionRow.addComponents(resetPingButton);
|
|
||||||
}
|
|
||||||
return refreshActionRow;
|
return refreshActionRow;
|
||||||
|
},
|
||||||
|
treeRoleMenu(fruit) {
|
||||||
|
let actionRow = new ActionRowBuilder().addComponents(this.buttons.waterPing());
|
||||||
|
if (fruit) {
|
||||||
|
actionRow.addComponents(this.buttons.fruitPing());
|
||||||
|
}
|
||||||
|
return actionRow;
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
acceptRules() {
|
||||||
|
return new ButtonBuilder()
|
||||||
|
.setCustomId('acceptrules')
|
||||||
|
.setLabel(`${strings.emoji.confirm} Accept Rules`)
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
},
|
||||||
|
waterPing() {
|
||||||
|
return new ButtonBuilder()
|
||||||
|
.setCustomId('waterpingrole')
|
||||||
|
.setLabel(strings.emoji.water)
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
},
|
||||||
|
fruitPing() {
|
||||||
|
return new ButtonBuilder()
|
||||||
|
.setCustomId('fruitpingrole')
|
||||||
|
.setLabel(strings.emoji.fruit)
|
||||||
|
.setStyle(ButtonStyle.Primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async refreshAction(guildId) {
|
embeds: {
|
||||||
// Create the button to go in the Action Row
|
treeRoleMenu(guildInfo) {
|
||||||
const refreshButton = new ButtonBuilder()
|
const actionRow = functions.builders.actionRows.treeRoleMenu(guildInfo.fruitRoleId == "" ? false : true);
|
||||||
.setCustomId('refresh')
|
let tempStrings = strings.embeds.treeRoleMenu;
|
||||||
.setLabel('Refresh')
|
let description = tempStrings[0] + tempStrings[1] + `<@&${guildInfo.waterRoleId}>` + tempStrings[2];
|
||||||
.setStyle(ButtonStyle.Primary);
|
if (guildInfo.fruitRoleId != "") {
|
||||||
const resetPingButton = new ButtonBuilder()
|
description += tempStrings[3] + `<@&${guildInfo.fruitRoleId}>` + tempStrings[4];
|
||||||
.setCustomId('resetping')
|
}
|
||||||
.setLabel('Reset Ping')
|
const embed = new EmbedBuilder()
|
||||||
.setStyle(ButtonStyle.Secondary);
|
.setColor(strings.embeds.color)
|
||||||
// Create the Action Row with the Button in it, to be sent with the Embed
|
.setTitle(strings.embeds.roleMenuTitle)
|
||||||
let refreshActionRow = new ActionRowBuilder()
|
.setDescription(description)
|
||||||
.addComponents(
|
.setFooter({ text: strings.embeds.roleMenuFooter });
|
||||||
refreshButton
|
return { embeds: [embed], components: [actionRow] };
|
||||||
);
|
|
||||||
const getGuildInfoResponse = await dbfn.getGuildInfo(guildId);
|
|
||||||
const guildInfo = getGuildInfoResponse.data;
|
|
||||||
if (guildInfo.reminderMessage != "" && guildInfo.reminderChannelId != "") {
|
|
||||||
refreshActionRow.addComponents(resetPingButton);
|
|
||||||
}
|
}
|
||||||
return refreshActionRow;
|
|
||||||
},
|
},
|
||||||
comparisonEmbed(content, guildInfo) {
|
comparisonEmbed(content, guildInfo) {
|
||||||
// Create the embed using the content passed to this function
|
// Create the embed using the content passed to this function
|
||||||
@ -112,11 +124,21 @@ const functions = {
|
|||||||
const messageContents = { embeds: [embed], components: [this.actionRows.comparisonActionRow(guildInfo)] };
|
const messageContents = { embeds: [embed], components: [this.actionRows.comparisonActionRow(guildInfo)] };
|
||||||
return messageContents;
|
return messageContents;
|
||||||
},
|
},
|
||||||
reminderEmbed(content, guildInfo) {
|
waterReminderEmbed(content, guildInfo) {
|
||||||
// Create the embed using the content passed to this function
|
// Create the embed using the content passed to this function
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setColor(strings.embeds.color)
|
.setColor(strings.embeds.waterColor)
|
||||||
.setTitle('Water Reminder')
|
.setTitle(strings.embeds.waterTitle)
|
||||||
|
.setDescription(`[Click here to go to your Tree](https://discord.com/channels/${guildInfo.guildId}/${guildInfo.treeChannelId}/${guildInfo.treeMessageId})`)
|
||||||
|
.setFooter({ text: `Click ♻️ to delete this message` });
|
||||||
|
const messageContents = { content: content, embeds: [embed], components: [this.actionRows.reminderActionRow()] };
|
||||||
|
return messageContents;
|
||||||
|
},
|
||||||
|
fruitReminderEmbed(content, guildInfo) {
|
||||||
|
// Create the embed using the content passed to this function
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setColor(strings.embeds.fruitColor)
|
||||||
|
.setTitle(strings.embeds.fruitTitle)
|
||||||
.setDescription(`[Click here to go to your Tree](https://discord.com/channels/${guildInfo.guildId}/${guildInfo.treeChannelId}/${guildInfo.treeMessageId})`)
|
.setDescription(`[Click here to go to your Tree](https://discord.com/channels/${guildInfo.guildId}/${guildInfo.treeChannelId}/${guildInfo.treeMessageId})`)
|
||||||
.setFooter({ text: `Click ♻️ to delete this message` });
|
.setFooter({ text: `Click ♻️ to delete this message` });
|
||||||
const messageContents = { content: content, embeds: [embed], components: [this.actionRows.reminderActionRow()] };
|
const messageContents = { content: content, embeds: [embed], components: [this.actionRows.reminderActionRow()] };
|
||||||
@ -135,8 +157,8 @@ const functions = {
|
|||||||
errorEmbed(content) {
|
errorEmbed(content) {
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setColor(0xFF0000)
|
.setColor(0xFF0000)
|
||||||
.setTitle('Error!')
|
.setTitle(strings.embeds.errorTitle)
|
||||||
.setDescription("Error: " + content)
|
.setDescription(`${strings.embeds.errorPrefix}\n${content}`)
|
||||||
.setFooter({ text: `v${package.version} - ${strings.embeds.footer}` });
|
.setFooter({ text: `v${package.version} - ${strings.embeds.footer}` });
|
||||||
const messageContents = { embeds: [embed], ephemeral: true };
|
const messageContents = { embeds: [embed], ephemeral: true };
|
||||||
return messageContents;
|
return messageContents;
|
||||||
@ -423,8 +445,9 @@ const functions = {
|
|||||||
|
|
||||||
// await dbfn.setGuildInfo(guildInfo);
|
// await dbfn.setGuildInfo(guildInfo);
|
||||||
// Bundle guildInfo into the response
|
// Bundle guildInfo into the response
|
||||||
const getGuildInfoResponse = await dbfn.getGuildInfo(guildInfo.guildId);
|
// const getGuildInfoResponse = await dbfn.getGuildInfo(guildInfo.guildId);
|
||||||
response.data = getGuildInfoResponse.data;
|
await functions.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
response.data = interaction.client.guildInfos.get(guildInfo.guildId);
|
||||||
|
|
||||||
// Set the response status, this is only used as a response to /setup
|
// Set the response status, this is only used as a response to /setup
|
||||||
if (treeFound && leaderboardFound) { // we found both the tree and leaderboard
|
if (treeFound && leaderboardFound) { // we found both the tree and leaderboard
|
||||||
@ -458,9 +481,57 @@ const functions = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
buttonHandlers: {
|
||||||
|
async fruitPing(interaction) {
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
const role = await functions.roles.fetchRole(interaction.guild, guildInfo.fruitRoleId);
|
||||||
|
let status = "No Changes Made";
|
||||||
|
if (interaction.member.roles.cache.some(role => role.id == guildInfo.fruitRoleId)) {
|
||||||
|
await functions.roles.takeRole(interaction.member, role);
|
||||||
|
status = "Removed the fruit role.";
|
||||||
|
} else {
|
||||||
|
await functions.roles.giveRole(interaction.member, role);
|
||||||
|
status = "Added the fruit role.";
|
||||||
|
}
|
||||||
|
return functions.builders.embed(status);
|
||||||
|
} else {
|
||||||
|
throw "Guild doesn't exist in database!";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async waterPing(interaction) {
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
let status = "No Changes Made";
|
||||||
|
const role = await functions.roles.fetchRole(interaction.guild, guildInfo.waterRoleId);
|
||||||
|
if (interaction.member.roles.cache.some(role => role.id == guildInfo.waterRoleId)) {
|
||||||
|
await functions.roles.takeRole(interaction.member, role);
|
||||||
|
status = "Removed the water role.";
|
||||||
|
} else {
|
||||||
|
await functions.roles.giveRole(interaction.member, role);
|
||||||
|
status = "Added the water role.";
|
||||||
|
}
|
||||||
|
return functions.builders.embed(status);
|
||||||
|
} else {
|
||||||
|
throw "Guild doesn't exist in database!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
roles: {
|
||||||
|
async fetchRole(guild, roleId) {
|
||||||
|
return await guild.roles.fetch(roleId).catch(err => console.error("Error fetching the role: " + err + "\n" + roleId));
|
||||||
|
},
|
||||||
|
async giveRole(member, role) {
|
||||||
|
await member.roles.add(role).catch(err => console.error("Error giving the role: " + err + "\n" + JSON.stringify(role)));
|
||||||
|
},
|
||||||
|
async takeRole(member, role) {
|
||||||
|
await member.roles.remove(role).catch(err => console.error("Error taking the role: " + err + "\n" + JSON.stringify(role)));
|
||||||
|
}
|
||||||
|
},
|
||||||
async refresh(interaction) {
|
async refresh(interaction) {
|
||||||
const getGuildInfoResponse = await dbfn.getGuildInfo(interaction.guildId);
|
// const getGuildInfoResponse = await dbfn.getGuildInfo(interaction.guildId);
|
||||||
let guildInfo = getGuildInfoResponse.data;
|
// let guildInfo = getGuildInfoResponse.data;
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guild.id);
|
||||||
const findMessagesResponse = await this.messages.find(interaction, guildInfo);
|
const findMessagesResponse = await this.messages.find(interaction, guildInfo);
|
||||||
if (findMessagesResponse.code == 1) {
|
if (findMessagesResponse.code == 1) {
|
||||||
guildInfo = findMessagesResponse.data;
|
guildInfo = findMessagesResponse.data;
|
||||||
@ -472,17 +543,15 @@ const functions = {
|
|||||||
const comparedRankings = await this.rankings.compare(interaction, guildInfo);
|
const comparedRankings = await this.rankings.compare(interaction, guildInfo);
|
||||||
|
|
||||||
const embed = this.builders.comparisonEmbed(comparedRankings, guildInfo);
|
const embed = this.builders.comparisonEmbed(comparedRankings, guildInfo);
|
||||||
await interaction.update(embed).then(async interactionResponse => {
|
await interaction.update(embed).catch(e => console.error(e));
|
||||||
// console.log(interactionResponse.interaction.message);
|
|
||||||
await dbfn.setComparisonMessage(interactionResponse.interaction.message, interaction.guildId);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
await interaction.update(this.builders.errorEmbed(findMessagesResponse.status));
|
await interaction.update(this.builders.errorEmbed(findMessagesResponse.status));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reset(guildId) {
|
reset(interaction) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
dbfn.deleteGuildInfo(guildId).then(res => {
|
dbfn.deleteGuildInfo(interaction.guildId).then(res => {
|
||||||
|
functions.collectionBuilders.guildInfos(interaction.client);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -491,24 +560,31 @@ const functions = {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getInfo(guildId) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
dbfn.getGuildInfo(guildId).then(res => {
|
|
||||||
let guildInfo = res.data;
|
|
||||||
let guildInfoString = "";
|
|
||||||
guildInfoString += `Tree Message: https://discord.com/channels/${guildId}/${guildInfo.treeChannelId}/${guildInfo.treeMessageId}\n`;
|
|
||||||
guildInfoString += `Rank Message: https://discord.com/channels/${guildId}/${guildInfo.leaderboardChannelId}/${guildInfo.leaderboardMessageId}\n`;
|
|
||||||
resolve(`Here is your servers setup info:\n${guildInfoString}`);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
})
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getWaterTime(size) {
|
getWaterTime(size) {
|
||||||
return Math.floor(Math.pow(size * 0.07 + 5, 1.1)); // Seconds
|
return Math.floor(Math.pow(size * 0.07 + 5, 1.1)); // Seconds
|
||||||
},
|
},
|
||||||
|
parseWaterTime(seconds) {
|
||||||
|
// 60 secs in min
|
||||||
|
// 3600 secs in hr
|
||||||
|
// 86400 sec in day
|
||||||
|
|
||||||
|
let waterParts = {
|
||||||
|
value: seconds,
|
||||||
|
units: "secs"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (60 < seconds && seconds <= 3600) { // Minutes
|
||||||
|
waterParts.value = parseFloat(seconds / 60).toFixed(1);
|
||||||
|
waterParts.units = "mins";
|
||||||
|
} else if (3600 < seconds && seconds <= 86400) {
|
||||||
|
waterParts.value = parseFloat(seconds / 3600).toFixed(1);
|
||||||
|
waterParts.units = "hrs";
|
||||||
|
} else if (86400 < seconds) {
|
||||||
|
waterParts.value = parseFloat(seconds / 86400).toFixed(1);
|
||||||
|
waterParts.units = "days";
|
||||||
|
}
|
||||||
|
return `${waterParts.value} ${waterParts.units}`;
|
||||||
|
},
|
||||||
timeToHeight(beginHeight, destHeight) {
|
timeToHeight(beginHeight, destHeight) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let time = 0;
|
let time = 0;
|
||||||
@ -545,102 +621,51 @@ const functions = {
|
|||||||
}, ms);
|
}, ms);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async sendReminder(guildInfo, guild) {
|
async sendWaterReminder(guildInfo, message, channelId, guild) {
|
||||||
const { guildId, reminderChannelId, reminderMessage } = guildInfo;
|
const reminderChannel = await guild.channels.fetch(channelId);
|
||||||
const reminderChannel = await guild.channels.fetch(reminderChannelId);
|
const reminderEmbed = functions.builders.waterReminderEmbed(message, guildInfo);
|
||||||
const reminderEmbed = functions.builders.reminderEmbed(reminderMessage, guildInfo);
|
await reminderChannel.send(reminderEmbed).catch(err => {
|
||||||
await reminderChannel.send(reminderEmbed).then(async m => {
|
|
||||||
const setRemindedStatusReponse = await dbfn.setRemindedStatus(guildId, 1);
|
|
||||||
return 1;
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async setReminder(interaction, ms) {
|
async sendFruitReminder(guildInfo, message, channelId, guild) {
|
||||||
setTimeout(this.sendReminder(interaction), ms);
|
const reminderChannel = await guild.channels.fetch(channelId);
|
||||||
},
|
const reminderEmbed = functions.builders.fruitReminderEmbed(message, guildInfo);
|
||||||
async checkReady(client) { // Check if the guilds trees are ready to water
|
await reminderChannel.send(reminderEmbed).catch(err => {
|
||||||
// let time = new Date(Date.now());
|
|
||||||
// console.log("Ready check " + time.getSeconds());
|
|
||||||
try {
|
|
||||||
// Get the guildInfos for each guild that is opted in and waiting to send a reminder
|
|
||||||
const getOptedInGuildsResponse = await dbfn.getOptedInGuilds();
|
|
||||||
// getOptedInGuilds will return this if it gets an empty set from the database
|
|
||||||
if (getOptedInGuildsResponse.status != "No servers have opted in yet") {
|
|
||||||
// Get the Array of Guilds from the response
|
|
||||||
const guilds = getOptedInGuildsResponse.data;
|
|
||||||
// Iterate over the Array
|
|
||||||
for (let i = 0; i < guilds.length; i++) {
|
|
||||||
// console.log(`iter: ${i}`);
|
|
||||||
// Save the 'old' guild info that came from getOptedInGuilds
|
|
||||||
const oldGuildInfo = guilds[i];
|
|
||||||
// Get up-to-date guildInfo from the database, probably unnecessary and redundant
|
|
||||||
const getGuildInfoResponse = await dbfn.getGuildInfo(oldGuildInfo.guildId);
|
|
||||||
// Save the new guildInfo so we can reference its remindedStatus
|
|
||||||
const guildInfo = getGuildInfoResponse.data;
|
|
||||||
const { guildId, treeChannelId, treeMessageId, remindedStatus } = guildInfo;
|
|
||||||
// console.log(`${guildInfo.treeName}: ${remindedStatus}`);
|
|
||||||
// Double check the remindedStatus to prevent double pings
|
|
||||||
if (remindedStatus == 0) {
|
|
||||||
// Fetch the guild
|
|
||||||
const guild = await client.guilds.fetch(guildId);
|
|
||||||
// Fetch the tree channel
|
|
||||||
const treeChannel = await guild.channels.fetch(treeChannelId);
|
|
||||||
// Fetch the tree message
|
|
||||||
const treeMessage = await treeChannel.messages.fetch(treeMessageId);
|
|
||||||
// Get the description from the embed of the tree message
|
|
||||||
const description = treeMessage.embeds[0].description;
|
|
||||||
// Default to not being ready to water
|
|
||||||
let readyToWater = false;
|
|
||||||
// Obviously if the tree says it's Ready to be watered, it's ready
|
|
||||||
if (description.includes("Ready to be watered")) {
|
|
||||||
readyToWater = true;
|
|
||||||
// But sometimes the tree doesn't refresh the embed, in that case we'll do a secondary check using the
|
|
||||||
// timestamp included in the embed.
|
|
||||||
} else {
|
|
||||||
const beginWaterTimestamp = description.indexOf("<t:") + 3;
|
|
||||||
const endWaterTimestamp = description.indexOf(":>");
|
|
||||||
// Split the description starting at "<t:" and ending at ":>" to get just the numerical timestamp
|
|
||||||
const waterTimestamp = parseInt(description.slice(beginWaterTimestamp, endWaterTimestamp));
|
|
||||||
// The Discord timestamp is in seconds, not ms so we need to divide by 1000
|
|
||||||
const nowTimestamp = (Date.now() / 1000);
|
|
||||||
readyToWater = (nowTimestamp > waterTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readyToWater) {
|
|
||||||
// Send the reminder message
|
|
||||||
await this.sendReminder(guildInfo, guild);
|
|
||||||
guildInfo.remindedStatus = 1;
|
|
||||||
await this.refreshComparisonMessage(client, guildInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.sleep(5000);
|
|
||||||
this.checkReady(client);
|
|
||||||
} else {
|
|
||||||
// console.log(getOptedInGuildsResponse.status);
|
|
||||||
await this.sleep(5000);
|
|
||||||
this.checkReady(client);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
console.error(err);
|
||||||
await this.sleep(30000);
|
});
|
||||||
this.checkReady(client);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async refreshComparisonMessage(client, guildInfo) {
|
async setupCollectors(client) {
|
||||||
if (guildInfo.comparisonChannelId != "" && guildInfo.comparisonMessageId != "") {
|
let guildInfos = client.guildInfos;
|
||||||
|
guildInfos.set("collectors", []);
|
||||||
|
await guildInfos.forEach(async guildInfo => {
|
||||||
|
if ( guildInfo instanceof GuildInfo && guildInfo.watchChannelId != "" && guildInfo.notificationsEnabled) {
|
||||||
const guild = await client.guilds.fetch(guildInfo.guildId);
|
const guild = await client.guilds.fetch(guildInfo.guildId);
|
||||||
const comparisonChannel = await guild.channels.fetch(guildInfo.comparisonChannelId);
|
// console.log(guildInfo instanceof GuildInfo);
|
||||||
const comparisonMessage = await comparisonChannel.messages.fetch(guildInfo.comparisonMessageId);
|
const channel = await guild.channels.fetch(guildInfo.watchChannelId);
|
||||||
const embed = comparisonMessage.embeds[0];
|
const filter = message => {
|
||||||
const actionRow = this.builders.actionRows.comparisonActionRow(guildInfo);
|
return message.author.id != process.env.BOTID;
|
||||||
await comparisonMessage.edit({ components: [actionRow] });
|
}
|
||||||
|
const collector = channel.createMessageCollector({ filter });
|
||||||
|
collector.on('collect', message => {
|
||||||
|
if (message.content.toLowerCase().includes("water ping")) {
|
||||||
|
this.sendWaterReminder(guildInfo, guildInfo.waterMessage, guildInfo.reminderChannelId, guild);
|
||||||
|
return;
|
||||||
|
} else if (message.content.toLowerCase().includes("fruit ping")) {
|
||||||
|
this.sendFruitReminder(guildInfo, guildInfo.fruitMessage, guildInfo.reminderChannelId, guild);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
if (message.embeds == undefined) return;
|
||||||
async resetPing(interaction) {
|
if (message.embeds.length == 0) return;
|
||||||
await dbfn.setRemindedStatus(interaction.guildId, 0);
|
guildInfo = client.guildInfos.get(guild.id);
|
||||||
|
if (message.embeds[0].data.description.includes(strings.notifications.water)) {
|
||||||
|
this.sendWaterReminder(guildInfo, guildInfo.waterMessage, guildInfo.reminderChannelId, guild);
|
||||||
|
} else if (message.embeds[0].data.description.includes(strings.notifications.fruit)) {
|
||||||
|
this.sendFruitReminder(guildInfo, guildInfo.fruitMessage, guildInfo.reminderChannelId, guild);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
0
modules/testing.js
Executable file
0
modules/testing.js
Executable file
2
package.json
Normal file → Executable file
2
package.json
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "silvanus",
|
"name": "silvanus",
|
||||||
"version": "1.1.4",
|
"version": "1.2.1",
|
||||||
"description": "Grow A Tree Companion Bot",
|
"description": "Grow A Tree Companion Bot",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
0
slash-commands/.DS_Store
vendored
Normal file → Executable file
0
slash-commands/.DS_Store
vendored
Normal file → Executable file
0
slash-commands/commands.js
Normal file → Executable file
0
slash-commands/commands.js
Normal file → Executable file
46
slash-commands/compare.js
Normal file → Executable file
46
slash-commands/compare.js
Normal file → Executable file
@ -1,6 +1,7 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
const { SlashCommandBuilder, Guild } = require('discord.js');
|
||||||
const dbfn = require('../modules/dbfn.js');
|
const dbfn = require('../modules/dbfn.js');
|
||||||
const fn = require('../modules/functions.js');
|
const fn = require('../modules/functions.js');
|
||||||
|
const { GuildInfo } = require('../modules/CustomClasses.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
@ -10,42 +11,28 @@ module.exports = {
|
|||||||
try {
|
try {
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
// Get the guildInfo from the database
|
// Get the guildInfo from the database
|
||||||
dbfn.getGuildInfo(interaction.guildId).then(async getGuildInfoResponse => {
|
|
||||||
let guildInfo = getGuildInfoResponse.data;
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
// Find the most recent tree and leaderboard messages in their respective channels
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
||||||
if (findMessagesResponse.code == 1) {
|
if (findMessagesResponse.code == 1) {
|
||||||
guildInfo = findMessagesResponse.data;
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
// Parse the leaderboard message
|
// Parse the leaderboard message
|
||||||
await fn.rankings.parse(interaction, guildInfo);
|
await fn.rankings.parse(interaction, guildInfo);
|
||||||
// Build the string that shows the comparison // TODO Move the string building section to fn.builders?
|
// Build the string that shows the comparison // TODO Move the string building section to fn.builders?
|
||||||
const comparedRankings = await fn.rankings.compare(interaction, guildInfo);
|
const comparedRankings = await fn.rankings.compare(interaction, guildInfo);
|
||||||
|
|
||||||
const embed = fn.builders.comparisonEmbed(comparedRankings, guildInfo);
|
const embed = fn.builders.comparisonEmbed(comparedRankings, guildInfo);
|
||||||
await interaction.editReply(embed).then(async message => {
|
await interaction.editReply(embed).catch(e => console.error(e));
|
||||||
await dbfn.setComparisonMessage(message, interaction.guildId);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
await interaction.editReply(fn.builders.errorEmbed(findMessagesResponse.status));
|
await interaction.editReply(fn.builders.errorEmbed(findMessagesResponse.status));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
}).catch(async err => { // If we fail to fetch the guild's info from the database
|
|
||||||
// If the error is because the guild hasn't been setup yet, set it up
|
|
||||||
if (err === "There is no database entry for your guild yet. Try running /setup") {
|
|
||||||
// Create a basic guildInfo with blank data
|
// Create a basic guildInfo with blank data
|
||||||
let guildInfo = {
|
let guildInfo = new GuildInfo()
|
||||||
guildId: `${interaction.guildId}`,
|
.setId(interaction.guildId)
|
||||||
treeName: "",
|
.setTreeMessage("", interaction.channelId)
|
||||||
treeHeight: 0,
|
.setLeaderboardMessage("", interaction.channelId)
|
||||||
treeMessageId: "",
|
|
||||||
treeChannelId: `${interaction.channelId}`, // Use this interaction channel for the initial channel IDs
|
|
||||||
leaderboardMessageId: "",
|
|
||||||
leaderboardChannelId: `${interaction.channelId}`,
|
|
||||||
reminderMessage: "",
|
|
||||||
reminderChannelId: "",
|
|
||||||
remindedStatus: 0,
|
|
||||||
reminderOptIn: 0,
|
|
||||||
}
|
|
||||||
// Using the above guildInfo, try to find the Grow A Tree messages
|
// Using the above guildInfo, try to find the Grow A Tree messages
|
||||||
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
||||||
guildInfo = findMessagesResponse.data;
|
guildInfo = findMessagesResponse.data;
|
||||||
@ -53,18 +40,11 @@ module.exports = {
|
|||||||
// Build the string that shows the comparison // TODO Move the string building section to fn.builders?
|
// Build the string that shows the comparison // TODO Move the string building section to fn.builders?
|
||||||
const comparedRankings = await fn.rankings.compare(interaction, guildInfo);
|
const comparedRankings = await fn.rankings.compare(interaction, guildInfo);
|
||||||
const embed = fn.builders.comparisonEmbed(comparedRankings, guildInfo);
|
const embed = fn.builders.comparisonEmbed(comparedRankings, guildInfo);
|
||||||
await interaction.editReply(embed).then(async message => {
|
await interaction.editReply(embed).catch(e => console.error(e));
|
||||||
await dbfn.setComparisonMessage(message.id, interaction.guildId);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
await interaction.editReply(fn.builders.errorEmbed(findMessagesResponse.status));
|
await interaction.editReply(fn.builders.errorEmbed(findMessagesResponse.status));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
await interaction.editReply(fn.builders.errorEmbed("An unknown error occurred while running the compare command."));
|
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
interaction.editReply(fn.builders.errorEmbed(err)).catch(err => {
|
interaction.editReply(fn.builders.errorEmbed(err)).catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
0
slash-commands/help.js
Normal file → Executable file
0
slash-commands/help.js
Normal file → Executable file
152
slash-commands/notifications.js
Executable file
152
slash-commands/notifications.js
Executable file
@ -0,0 +1,152 @@
|
|||||||
|
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
|
||||||
|
const { GuildInfo } = require('../modules/CustomClasses.js');
|
||||||
|
const dbfn = require('../modules/dbfn.js');
|
||||||
|
const fn = require('../modules/functions.js');
|
||||||
|
const strings = require('../data/strings.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('notifications')
|
||||||
|
.setDescription('A notification relay for improved water and fruit notifications')
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('set')
|
||||||
|
.setDescription('Set up the notification relay for the first time')
|
||||||
|
.addChannelOption(o =>
|
||||||
|
o.setName('watchchannel')
|
||||||
|
.setDescription('The channel Grow A Tree sends your notifications in')
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addStringOption(o =>
|
||||||
|
o.setName('watermessage')
|
||||||
|
.setDescription('Message to send for water reminders')
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addChannelOption(o =>
|
||||||
|
o.setName('pingchannel')
|
||||||
|
.setDescription('The channel to send the water reminder in')
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addStringOption(o =>
|
||||||
|
o.setName('fruitmessage')
|
||||||
|
.setDescription("Message to send for fruit reminders")
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('update')
|
||||||
|
.setDescription('Update an already setup notification relay')
|
||||||
|
.addChannelOption(o =>
|
||||||
|
o.setName('watchchannel')
|
||||||
|
.setDescription('The channel Grow A Tree sends your notifications in')
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
.addStringOption(o =>
|
||||||
|
o.setName('watermessage')
|
||||||
|
.setDescription('Message to send for water reminders')
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
.addChannelOption(o =>
|
||||||
|
o.setName('pingchannel')
|
||||||
|
.setDescription('The channel to send the water reminder in')
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
.addStringOption(o =>
|
||||||
|
o.setName('fruitmessage')
|
||||||
|
.setDescription("Message to send for fruit reminders")
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('disable')
|
||||||
|
.setDescription('Disable the notification relay')
|
||||||
|
)
|
||||||
|
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles),
|
||||||
|
async execute(interaction) {
|
||||||
|
try {
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
const subcommand = interaction.options.getSubcommand();
|
||||||
|
// if (process.env.DEBUG) console.log(`${typeof subcommand}: ${subcommand}`);
|
||||||
|
switch (subcommand) {
|
||||||
|
case "set":
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
const watchChannel = interaction.options.getChannel('watchchannel');
|
||||||
|
const waterMessage = interaction.options.getString('watermessage');
|
||||||
|
const fruitMessage = interaction.options.getString('fruitmessage') ? interaction.options.getString('fruitmessage') : interaction.options.getString('watermessage');
|
||||||
|
const reminderChannel = interaction.options.getChannel('pingchannel');
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
guildInfo.setReminders(waterMessage, fruitMessage, reminderChannel.id, watchChannel.id, true);
|
||||||
|
let query = guildInfo.queryBuilder("setReminders");
|
||||||
|
await dbfn.setGuildInfo(query);
|
||||||
|
const replyParts = [
|
||||||
|
`I'll watch <#${watchChannel.id}> for Grow A Tree Notifications and relay them to <#${reminderChannel.id}>.`,
|
||||||
|
`Water Message: ${waterMessage}`
|
||||||
|
];
|
||||||
|
if (fruitMessage != "") replyParts.push(`Fruit Message: ${fruitMessage}`);
|
||||||
|
await interaction.editReply(replyParts.join("\n")).catch(e => console.error(e));
|
||||||
|
fn.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
} else {
|
||||||
|
const watchChannel = interaction.options.getChannel('watchchannel');
|
||||||
|
const waterMessage = interaction.options.getString('watermessage');
|
||||||
|
const fruitMessage = interaction.options.getString('fruitmessage') ? interaction.options.getString('fruitmessage') : interaction.options.getString('watermessage');
|
||||||
|
const reminderChannel = interaction.options.getChannel('pingchannel');
|
||||||
|
let guildInfo = new GuildInfo()
|
||||||
|
.setId(interaction.guildId)
|
||||||
|
.setReminders(waterMessage, fruitMessage, reminderChannel.id, watchChannel.id, true);
|
||||||
|
let query = guildInfo.queryBuilder("setReminders");
|
||||||
|
await dbfn.setGuildInfo(query);
|
||||||
|
const replyParts = [
|
||||||
|
`I'll watch <#${watchChannel.id}> for Grow A Tree Notifications and relay them to <#${reminderChannel.id}>.`,
|
||||||
|
`Water Message: ${waterMessage}`
|
||||||
|
];
|
||||||
|
if (fruitMessage != "") replyParts.push(`Fruit Message: ${fruitMessage}`);
|
||||||
|
await interaction.editReply(replyParts.join("\n")).catch(e => console.error(e));
|
||||||
|
fn.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "update":
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
const inWatchChannel = interaction.options.getChannel('watchchannel');
|
||||||
|
const inWaterMessage = interaction.options.getString('watermessage');
|
||||||
|
const inFruitMessage = interaction.options.getString('fruitmessage');
|
||||||
|
const inReminderChannel = interaction.options.getChannel('pingchannel');
|
||||||
|
|
||||||
|
const outWatchChannelId = inWatchChannel ? inWatchChannel.id : guildInfo.watchChannelId;
|
||||||
|
const outWaterMessage = inWaterMessage ? inWaterMessage : guildInfo.waterMessage;
|
||||||
|
const outFruitMessage = inFruitMessage ? inFruitMessage : guildInfo.fruitMessage;
|
||||||
|
const outReminderChannelId = inReminderChannel ? inReminderChannel.id : guildInfo.reminderChannelId;
|
||||||
|
|
||||||
|
guildInfo.setReminders(outWaterMessage, outFruitMessage, outReminderChannelId, outWatchChannelId, true);
|
||||||
|
let query = guildInfo.queryBuilder("setReminders");
|
||||||
|
await dbfn.setGuildInfo(query);
|
||||||
|
const replyParts = [
|
||||||
|
`I'll watch <#${outWatchChannelId}> for Grow A Tree Notifications and relay them to <#${outReminderChannelId}>.`,
|
||||||
|
`Water Message: ${outWaterMessage}`
|
||||||
|
];
|
||||||
|
if (outFruitMessage != "") replyParts.push(`Fruit Message: ${outFruitMessage}`);
|
||||||
|
await interaction.editReply(replyParts.join("\n")).catch(e => console.error(e));
|
||||||
|
fn.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed("There is no existing notification relay to update!")).catch(e => console.error(e));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
guildInfo.setReminders(undefined, undefined, undefined, undefined, false);
|
||||||
|
await dbfn.setGuildInfo(guildInfo.queryBuilder("setReminders")).catch(e => console.error(e));
|
||||||
|
await fn.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
await interaction.editReply(fn.builders.embed(strings.status.optout)).catch(e => console.error(e));
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed("A notification relay has not been set up yet!")).catch(e => console.error(e));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed("Invalid subcommand detected.")).catch(e => console.error(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error occurred while setting up a notification relay: " + err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
@ -1,20 +0,0 @@
|
|||||||
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
|
|
||||||
const dbfn = require('../modules/dbfn.js');
|
|
||||||
const fn = require('../modules/functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('optout')
|
|
||||||
.setDescription('Opt-out of automatic water reminders')
|
|
||||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles),
|
|
||||||
async execute(interaction) {
|
|
||||||
try {
|
|
||||||
await interaction.deferReply({ ephemeral: true });
|
|
||||||
const setReminderOptInResponse = await dbfn.setReminderOptIn(interaction.guildId, 0);
|
|
||||||
interaction.editReply(setReminderOptInResponse.status);
|
|
||||||
} catch(err) {
|
|
||||||
console.error(err);
|
|
||||||
await interaction.editReply(fn.builders.errorEmbed(err));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
|
||||||
const fn = require('../modules/functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('reset')
|
|
||||||
.setDescription('Reset all message assignments in your server'),
|
|
||||||
execute(interaction) {
|
|
||||||
interaction.deferReply({ ephemeral: true }).then(() => {
|
|
||||||
fn.reset(interaction.guildId).then(res => {
|
|
||||||
interaction.editReply(fn.builders.embed("Assignments Reset")).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
interaction.editReply("There was a problem deleting your guild information, contact @voidf1sh#0420 for help.").catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
18
slash-commands/rolemenu.js
Executable file
18
slash-commands/rolemenu.js
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
const { SlashCommandBuilder } = require('discord.js');
|
||||||
|
const fn = require('../modules/functions.js');
|
||||||
|
const strings = require('../data/strings.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('rolemenu')
|
||||||
|
.setDescription('Send a self-assignable role selection menu'),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.deferReply().catch(e => console.error(e));
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
await interaction.editReply(fn.builders.embeds.treeRoleMenu(guildInfo)).catch(e => console.error(e));
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed(strings.status.noRoleMenu)).catch(e => console.error(e));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
@ -1,31 +0,0 @@
|
|||||||
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
|
|
||||||
const dbfn = require('../modules/dbfn.js');
|
|
||||||
const fn = require('../modules/functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('setping')
|
|
||||||
.setDescription('Opt-in to automatic water reminders')
|
|
||||||
.addStringOption(o =>
|
|
||||||
o.setName('pingmsg')
|
|
||||||
.setDescription('The message to send for a water reminder')
|
|
||||||
.setRequired(true))
|
|
||||||
.addChannelOption(o =>
|
|
||||||
o.setName('pingchannel')
|
|
||||||
.setDescription('The channel to send the water reminder in')
|
|
||||||
.setRequired(true))
|
|
||||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles),
|
|
||||||
async execute(interaction) {
|
|
||||||
try {
|
|
||||||
await interaction.deferReply({ ephemeral: true });
|
|
||||||
const reminderMessage = interaction.options.getString('pingmsg');
|
|
||||||
const reminderChannel = interaction.options.getChannel('pingchannel');
|
|
||||||
const setPingRoleResponse = await dbfn.setReminderInfo(interaction.guildId, reminderMessage, reminderChannel.id);
|
|
||||||
await dbfn.setReminderOptIn(interaction.guildId, 1);
|
|
||||||
interaction.editReply(setPingRoleResponse.status);
|
|
||||||
} catch(err) {
|
|
||||||
console.error(err);
|
|
||||||
await interaction.editReply(fn.builders.errorEmbed(err));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,18 +0,0 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
|
||||||
const dbfn = require('../modules/dbfn.js');
|
|
||||||
const fn = require('../modules/functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('setping')
|
|
||||||
.setDescription('Run this command when you water your tree to have a reminder sent.'),
|
|
||||||
async execute(interaction) {
|
|
||||||
await interaction.deferReply({ ephemeral: true });
|
|
||||||
const getGuildInfoResponse = await dbfn.getGuildInfo(interaction.guildId);
|
|
||||||
const guildInfo = getGuildInfoResponse.data;
|
|
||||||
const reminderTimeS = fn.getWaterTime(guildInfo.treeHeight);
|
|
||||||
const reminderTimeMs = reminderTimeS * 1000;
|
|
||||||
fn.setReminder(interaction, reminderTimeMs, guildInfo.pingRoleId);
|
|
||||||
interaction.editReply("A reminder has been set.");
|
|
||||||
},
|
|
||||||
};
|
|
124
slash-commands/setup.js
Normal file → Executable file
124
slash-commands/setup.js
Normal file → Executable file
@ -1,37 +1,125 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
|
||||||
const fn = require('../modules/functions.js');
|
const fn = require('../modules/functions.js');
|
||||||
const strings = require('../data/strings.json');
|
const strings = require('../data/strings.json');
|
||||||
const dbfn = require('../modules/dbfn.js');
|
const dbfn = require('../modules/dbfn.js');
|
||||||
|
const { GuildInfo } = require('../modules/CustomClasses.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('setup')
|
.setName('setup')
|
||||||
.setDescription('Attempt automatic configuration of the bot.')
|
.setDescription('Attempt automatic configuration of the bot.')
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('compare')
|
||||||
|
.setDescription('Set up the channels to be used with /compare')
|
||||||
.addChannelOption(o =>
|
.addChannelOption(o =>
|
||||||
o.setName('treechannel')
|
o.setName('treechannel')
|
||||||
.setDescription('What channel is your tree in?')
|
.setDescription('What channel is your tree in?')
|
||||||
.setRequired(true))
|
.setRequired(true)
|
||||||
|
)
|
||||||
.addChannelOption(o =>
|
.addChannelOption(o =>
|
||||||
o.setName('leaderboardchannel')
|
o.setName('leaderboardchannel')
|
||||||
.setDescription('If your leaderboard isn\'t in the same channel, where is it?')
|
.setDescription('If your leaderboard isn\'t in the same channel, where is it?')
|
||||||
.setRequired(false)),
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('rolemenu')
|
||||||
|
.setDescription('Setup the roles to be used with /rolemenu')
|
||||||
|
.addRoleOption(o =>
|
||||||
|
o.setName('waterrole')
|
||||||
|
.setDescription('The role for water reminder pings')
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
.addRoleOption(o =>
|
||||||
|
o.setName('fruitrole')
|
||||||
|
.setDescription('The role for fruit alert pings')
|
||||||
|
.setRequired(false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('view')
|
||||||
|
.setDescription('View your server\'s configuration'))
|
||||||
|
.addSubcommand(sc =>
|
||||||
|
sc.setName('reset')
|
||||||
|
.setDescription('Remove all server configuration from the database')
|
||||||
|
.addBooleanOption(o =>
|
||||||
|
o.setName('confirm')
|
||||||
|
.setDescription('WARNING THIS IS IRREVERSIBLE')
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator),
|
||||||
async execute(interaction) {
|
async execute(interaction) {
|
||||||
await interaction.deferReply({ ephemeral: true });
|
await interaction.deferReply({ ephemeral: true });
|
||||||
/**/
|
const subcommand = interaction.options.getSubcommand();
|
||||||
let guildInfo = {
|
switch (subcommand) {
|
||||||
"guildId": interaction.guildId,
|
case "compare":
|
||||||
"treeName": "",
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
"treeHeight": 0,
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
"treeMessageId": "",
|
|
||||||
"treeChannelId": `${interaction.options.getChannel('treechannel').id }`,
|
|
||||||
"leaderboardMessageId": "",
|
|
||||||
"leaderboardChannelId": `${interaction.options.getChannel('leaderboardchannel').id || interaction.options.getChannel('treechannel').id }`,
|
|
||||||
"reminderMessage": "",
|
|
||||||
"reminderChannelId": "",
|
|
||||||
"remindedStatus": 0,
|
|
||||||
"reminderOptIn": 0,
|
|
||||||
};
|
|
||||||
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
||||||
interaction.editReply(findMessagesResponse.status);
|
await interaction.editReply(findMessagesResponse.status).catch(e => console.error(e));
|
||||||
|
} else {
|
||||||
|
let guildInfo = new GuildInfo()
|
||||||
|
.setId(interaction.guildId);
|
||||||
|
const findMessagesResponse = await fn.messages.find(interaction, guildInfo);
|
||||||
|
await interaction.editReply(findMessagesResponse.status).catch(e => console.error(e));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "rolemenu":
|
||||||
|
let waterRoleId = interaction.options.getRole('waterrole').id;
|
||||||
|
let fruitRoleId = interaction.options.getRole('fruitrole') ? interaction.options.getRole('fruitrole').id : undefined;
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
guildInfo.setRoles(waterRoleId, fruitRoleId);
|
||||||
|
await dbfn.setGuildInfo(guildInfo.queryBuilder("setRoles"));
|
||||||
|
await fn.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
await interaction.editReply(fn.builders.embeds.treeRoleMenu(guildInfo)).catch(e => console.error(e));
|
||||||
|
} else {
|
||||||
|
let guildInfo = new GuildInfo()
|
||||||
|
.setId(interaction.guildId);
|
||||||
|
guildInfo.setRoles(waterRoleId, fruitRoleId);
|
||||||
|
await dbfn.setGuildInfo(guildInfo.queryBuilder("setRoles"));
|
||||||
|
await fn.collectionBuilders.guildInfos(interaction.client);
|
||||||
|
await interaction.editReply(fn.builders.embeds.treeRoleMenu(guildInfo)).catch(e => console.error(e));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "view":
|
||||||
|
try {
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
await interaction.editReply(fn.builders.embed(guildInfo.generateSetupInfo()));
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed("Guild doesn't exist in database!"));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed("There was an error running the command."));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "reset":
|
||||||
|
if (interaction.client.guildInfos.has(interaction.guildId)) {
|
||||||
|
let guildInfo = interaction.client.guildInfos.get(interaction.guildId);
|
||||||
|
if (interaction.options.getBoolean('confirm')) {
|
||||||
|
fn.reset(interaction).then(res => {
|
||||||
|
interaction.editReply(fn.builders.embed(strings.status.reset)).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
interaction.editReply(strings.status.resetError).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await interaction.editReply(fn.builders.embed("You must select 'true' to confirm setup reset. No changes have been made.")).catch(e => console.error(e));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw "Guild doesn't exist in database!";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await interaction.editReply(fn.builders.errorEmbed(strings.error.invalidSubcommand)).catch(e => console.error(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
@ -1,21 +0,0 @@
|
|||||||
const { SlashCommandBuilder } = require('discord.js');
|
|
||||||
const fn = require('../modules/functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('setupinfo')
|
|
||||||
.setDescription('View information about how the bot is set up in your server'),
|
|
||||||
execute(interaction) {
|
|
||||||
interaction.deferReply({ephemeral: true}).then(() => {
|
|
||||||
fn.getInfo(interaction.guildId).then(res => {
|
|
||||||
const embed = fn.builders.embed(res);
|
|
||||||
interaction.editReply(embed);
|
|
||||||
}).catch(err => {
|
|
||||||
interaction.editReply(err);
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
0
slash-commands/template
Normal file → Executable file
0
slash-commands/template
Normal file → Executable file
22
slash-commands/timetoheight.js
Normal file → Executable file
22
slash-commands/timetoheight.js
Normal file → Executable file
@ -6,18 +6,22 @@ module.exports = {
|
|||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('timetoheight')
|
.setName('timetoheight')
|
||||||
.setDescription('Calculate how long it would take to reach a given height')
|
.setDescription('Calculate how long it would take to reach a given height')
|
||||||
.addStringOption(o =>
|
.addIntegerOption(o =>
|
||||||
o.setName('beginheight')
|
|
||||||
.setDescription('Begining tree height in feet, numbers ONLY')
|
|
||||||
.setRequired(true))
|
|
||||||
.addStringOption(o =>
|
|
||||||
o.setName('endheight')
|
o.setName('endheight')
|
||||||
.setDescription('Ending tree height in feet, numbers ONLY')
|
.setDescription('Ending tree height in feet')
|
||||||
.setRequired(true)),
|
.setRequired(true))
|
||||||
|
.addIntegerOption(o =>
|
||||||
|
o.setName('beginheight')
|
||||||
|
.setDescription('Beginning tree height in feet')
|
||||||
|
.setRequired(false)),
|
||||||
async execute(interaction) {
|
async execute(interaction) {
|
||||||
await interaction.deferReply({ ephemeral: true });
|
await interaction.deferReply({ ephemeral: true });
|
||||||
const beginHeight = interaction.options.getString('beginheight');
|
let beginHeight = interaction.options.getInteger('beginheight');
|
||||||
const endHeight = interaction.options.getString('endheight');
|
const endHeight = interaction.options.getInteger('endheight');
|
||||||
|
if (!beginHeight) {
|
||||||
|
const guildInfo = interaction.client.guildInfos.get(interaction.guild.id);
|
||||||
|
beginHeight = guildInfo.treeHeight;
|
||||||
|
}
|
||||||
fn.timeToHeight(beginHeight, endHeight).then(res => {
|
fn.timeToHeight(beginHeight, endHeight).then(res => {
|
||||||
interaction.editReply(`It will take a tree that is ${beginHeight}ft tall ${res} to reach ${endHeight}ft.`);
|
interaction.editReply(`It will take a tree that is ${beginHeight}ft tall ${res} to reach ${endHeight}ft.`);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
20
slash-commands/watertime.js
Normal file → Executable file
20
slash-commands/watertime.js
Normal file → Executable file
@ -6,13 +6,21 @@ module.exports = {
|
|||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('watertime')
|
.setName('watertime')
|
||||||
.setDescription('Calculate the watering time for a given tree height')
|
.setDescription('Calculate the watering time for a given tree height')
|
||||||
.addStringOption(o =>
|
.addIntegerOption(o =>
|
||||||
o.setName('height')
|
o.setName('height')
|
||||||
.setDescription('Tree height in feet, numbers ONLY')
|
.setDescription('Tree height')
|
||||||
.setRequired(true)),
|
.setRequired(true))
|
||||||
|
.addBooleanOption(o =>
|
||||||
|
o.setName('private')
|
||||||
|
.setDescription('Should the response be private? Default: true')
|
||||||
|
.setRequired(false)),
|
||||||
async execute(interaction) {
|
async execute(interaction) {
|
||||||
await interaction.deferReply();
|
const treeHeight = interaction.options.getInteger('height');
|
||||||
const treeHeight = interaction.options.getString('height');
|
const privateOpt = interaction.options.getBoolean('private');
|
||||||
await interaction.editReply(`A tree that is ${treeHeight}ft tall will have a watering time of ${fn.getWaterTime(treeHeight)} minutes.`);
|
const private = privateOpt != undefined ? privateOpt : true;
|
||||||
|
await interaction.deferReply( {ephemeral: private });
|
||||||
|
const waterSeconds = fn.getWaterTime(treeHeight);
|
||||||
|
const waterTime = fn.parseWaterTime(waterSeconds);
|
||||||
|
await interaction.editReply(`A tree that is ${treeHeight}ft tall will have a watering time of ${waterTime}.`);
|
||||||
},
|
},
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user