silvanus/modules/functions.js

647 lines
26 KiB
JavaScript
Raw Normal View History

2023-01-18 00:35:24 +00:00
/* eslint-disable comma-dangle */
// dotenv for handling environment variables
const dotenv = require('dotenv');
dotenv.config();
const isDev = process.env.isDev;
const package = require('../package.json');
2023-01-18 00:35:24 +00:00
// filesystem
const fs = require('fs');
// Discord.js
const Discord = require('discord.js');
2023-01-19 01:10:05 +00:00
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord;
2023-01-18 00:35:24 +00:00
// Various imports from other files
2023-01-19 17:44:49 +00:00
const config = require('../data/config.json');
const strings = require('../data/strings.json');
2023-01-18 00:35:24 +00:00
const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js'));
const dbfn = require('./dbfn.js');
2023-01-26 04:11:49 +00:00
const { finished } = require('stream');
dbfn.createGuildTables().then(res => {
console.log(res.status);
}).catch(err => {
console.error(err);
});
2023-01-18 00:35:24 +00:00
const functions = {
// Functions for managing and creating Collections
collections: {
// Create the collection of slash commands
slashCommands(client) {
if (!client.slashCommands) client.slashCommands = new Discord.Collection();
client.slashCommands.clear();
for (const file of slashCommandFiles) {
2023-01-19 17:44:49 +00:00
const slashCommand = require(`../slash-commands/${file}`);
2023-01-18 00:35:24 +00:00
if (slashCommand.data != undefined) {
client.slashCommands.set(slashCommand.data.name, slashCommand);
}
}
if (isDev) console.log('Slash Commands Collection Built');
2023-01-19 01:10:05 +00:00
}
},
builders: {
2023-01-31 00:28:12 +00:00
actionRows: {
reminderActionRow() {
const deleteButton = new ButtonBuilder()
.setCustomId('deleteping')
.setEmoji('♻️')
.setStyle(ButtonStyle.Danger);
const actionRow = new ActionRowBuilder()
.addComponents(deleteButton);
return actionRow;
},
comparisonActionRow(guildInfo) {
2023-02-01 03:30:20 +00:00
// console.log(guildInfo);
2023-01-31 00:28:12 +00:00
// Create the button to go in the Action Row
const refreshButton = new ButtonBuilder()
.setCustomId('refresh')
.setEmoji('🔄')
.setStyle(ButtonStyle.Primary);
// Create the Action Row with the Button in it, to be sent with the Embed
let refreshActionRow = new ActionRowBuilder()
.addComponents(
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;
}
},
2023-01-27 23:14:01 +00:00
async refreshAction(guildId) {
2023-01-19 01:10:05 +00:00
// Create the button to go in the Action Row
const refreshButton = new ButtonBuilder()
.setCustomId('refresh')
.setLabel('Refresh')
.setStyle(ButtonStyle.Primary);
2023-01-27 23:14:01 +00:00
const resetPingButton = new ButtonBuilder()
.setCustomId('resetping')
.setLabel('Reset Ping')
.setStyle(ButtonStyle.Secondary);
2023-01-19 01:10:05 +00:00
// Create the Action Row with the Button in it, to be sent with the Embed
2023-01-27 23:14:01 +00:00
let refreshActionRow = new ActionRowBuilder()
2023-01-19 01:10:05 +00:00
.addComponents(
refreshButton
);
2023-01-27 23:14:01 +00:00
const getGuildInfoResponse = await dbfn.getGuildInfo(guildId);
const guildInfo = getGuildInfoResponse.data;
if (guildInfo.reminderMessage != "" && guildInfo.reminderChannelId != "") {
refreshActionRow.addComponents(resetPingButton);
}
2023-01-19 01:10:05 +00:00
return refreshActionRow;
2023-01-18 00:35:24 +00:00
},
2023-01-31 00:28:12 +00:00
comparisonEmbed(content, guildInfo) {
// Create the embed using the content passed to this function
const embed = new EmbedBuilder()
.setColor(strings.embeds.color)
2023-01-31 00:28:12 +00:00
.setTitle('Tallest Trees Comparison')
.setDescription(content)
2023-01-30 06:12:26 +00:00
.setFooter({ text: `v${package.version} - ${strings.embeds.footer}` });
2023-01-31 00:28:12 +00:00
const messageContents = { embeds: [embed], components: [this.actionRows.comparisonActionRow(guildInfo)] };
return messageContents;
},
2023-01-27 23:14:01 +00:00
reminderEmbed(content, guildInfo) {
// Create the embed using the content passed to this function
const embed = new EmbedBuilder()
.setColor(strings.embeds.color)
.setTitle('Water Reminder')
2023-01-30 06:12:26 +00:00
.setDescription(`[Click here to go to your Tree](https://discord.com/channels/${guildInfo.guildId}/${guildInfo.treeChannelId}/${guildInfo.treeMessageId})`)
2023-01-31 00:28:12 +00:00
.setFooter({ text: `Click ♻️ to delete this message` });
const messageContents = { content: content, embeds: [embed], components: [this.actionRows.reminderActionRow()] };
2023-01-27 23:14:01 +00:00
return messageContents;
},
2023-01-19 01:10:05 +00:00
helpEmbed(content, private) {
const embed = new EmbedBuilder()
.setColor(strings.embeds.color)
2023-01-24 02:36:44 +00:00
.setTitle(strings.help.title)
2023-01-19 01:10:05 +00:00
.setDescription(content)
.setFooter({ text: `v${package.version} - ${strings.embeds.footer}` });
2023-01-19 01:10:05 +00:00
const privateBool = private == 'true';
const messageContents = { embeds: [embed], ephemeral: privateBool };
return messageContents;
},
errorEmbed(content) {
const embed = new EmbedBuilder()
.setColor(0xFF0000)
.setTitle('Error!')
2023-01-24 00:37:51 +00:00
.setDescription("Error: " + content)
.setFooter({ text: `v${package.version} - ${strings.embeds.footer}` });
2023-01-19 01:10:05 +00:00
const messageContents = { embeds: [embed], ephemeral: true };
return messageContents;
2023-01-18 00:35:24 +00:00
},
2023-01-19 01:10:05 +00:00
embed(content) {
const embed = new EmbedBuilder()
.setColor(0x8888FF)
.setTitle('Information')
.setDescription(content)
.setFooter({ text: `v${package.version} - ${strings.embeds.footer}` });
2023-01-19 01:10:05 +00:00
const messageContents = { embeds: [embed], ephemeral: true };
return messageContents;
}
2023-01-18 00:35:24 +00:00
},
rankings: {
2023-01-30 06:12:26 +00:00
parse(interaction, guildInfo) {
return new Promise((resolve, reject) => {
if (guildInfo.guildId == "") {
reject(strings.error.noGuild);
return;
}
if (guildInfo.leaderboardMessageId != undefined) {
interaction.guild.channels.fetch(guildInfo.leaderboardChannelId).then(c => {
c.messages.fetch(guildInfo.leaderboardMessageId).then(leaderboardMessage => {
if ((leaderboardMessage.embeds.length == 0) || (leaderboardMessage.embeds[0].data.title != 'Tallest Trees')) {
reject("This doesn't appear to be a valid ``/top trees`` message.");
return;
}
let lines = leaderboardMessage.embeds[0].data.description.split('\n');
let leaderboard = {
"guildId": interaction.guildId,
"entries": []
};
for (let i = 0; i < 10; i++) {
// Breakdown each line separating it on each -
let breakdown = lines[i].split(' - ');
// Check if the first part, the ranking, has these emojis to detect first second and third place
if (breakdown[0].includes('🥇')) {
breakdown[0] = '``#1 ``'
} else if (breakdown[0].includes('🥈')) {
breakdown[0] = '``#2 ``'
} else if (breakdown[0].includes('🥉')) {
breakdown[0] = '``#3 ``'
}
2023-01-30 06:12:26 +00:00
// Clean off the excess and get just the number from the rank, make sure it's an int not string
let trimmedRank = parseInt(breakdown[0].slice(breakdown[0].indexOf('#') + 1, breakdown[0].lastIndexOf('``')));
2023-01-30 06:12:26 +00:00
// Clean off the excess and get just the tree name
let trimmedName = breakdown[1].slice(breakdown[1].indexOf('``') + 2);
trimmedName = trimmedName.slice(0, trimmedName.indexOf('``'));
// Clean off the excess and get just the tree height, make sure it's a 1 decimal float
let trimmedHeight = parseFloat(breakdown[2].slice(0, breakdown[2].indexOf('ft'))).toFixed(1);
let isMyTree = false;
let isMaybeMyTree = false;
if (breakdown[2].includes('📍')) isMyTree = true;
if (breakdown[1].includes(guildInfo.treeName)) maybeMyTree = true;
// "entries": [ { "treeHeight": 12, "treeRank": 34, "treeName": "name" }, ] }
leaderboard.entries.push({
treeRank: trimmedRank,
treeName: trimmedName,
treeHeight: trimmedHeight,
hasPin: isMyTree
});
2023-01-30 06:12:26 +00:00
}
dbfn.uploadLeaderboard(leaderboard).then(res => {
resolve(res.status);
}).catch(err => {
console.error(err);
reject(err);
return;
});
2023-01-30 06:12:26 +00:00
}).catch(err => {
reject(strings.status.missingLeaderboardMessage);
console.error(err);
return;
});
2023-01-30 06:12:26 +00:00
}).catch(err => {
reject(strings.status.missingLeaderboardChannel);
console.error(err);
return;
2023-01-30 06:12:26 +00:00
});
} else {
reject("The leaderboardMessageId is undefined somehow");
return;
2023-01-30 06:12:26 +00:00
}
});
2023-01-30 06:12:26 +00:00
},
2023-01-30 06:12:26 +00:00
async compare(interaction, guildInfo) {
2023-01-26 04:11:49 +00:00
try {
const getLeaderboardResponse = await dbfn.getLeaderboard(interaction.guildId);
const leaderboard = getLeaderboardResponse.data; // [ { treeName: "Name", treeHeight: 1234.5, treeRank: 67 }, {...}, {...} ]
2023-01-30 06:12:26 +00:00
2023-01-26 04:11:49 +00:00
// Prepare the beginning of the comparison message
let comparisonReplyString = `Here\'s how your tree compares: \nCurrent Tree Height: ${guildInfo.treeHeight}ft\n\n`;
// Iterate over the leaderboard entries, backwards
for (let i = leaderboard.length - 1; i >= 0; i--) {
const leaderboardEntry = leaderboard[i];
// Setup the status indicator, default to blank, we'll change it later
2023-01-28 01:57:40 +00:00
let statusIndicator = "";
if ((leaderboardEntry.treeHeight % 1).toFixed(1) > 0) statusIndicator += "``[💧]``";
2023-01-30 06:12:26 +00:00
2023-01-26 04:11:49 +00:00
// Get the data for this tree from 24 hours ago
2023-01-28 01:57:40 +00:00
// const get24hTreeResponse = await dbfn.get24hTree(interaction.guildId, leaderboardEntry.treeName);
// const dayAgoTree = get24hTreeResponse.data;
// const hist24hDifference = (leaderboardEntry.treeHeight - dayAgoTree.treeHeight).toFixed(1);
// statusIndicator += `+${hist24hDifference}ft|`
2023-01-26 04:11:49 +00:00
2023-01-27 02:30:41 +00:00
// Get the 24h watering time for this tree
2023-01-28 01:57:40 +00:00
// const totalWaterTime = await functions.timeToHeight(dayAgoTree.treeHeight, leaderboardEntry.treeHeight);
// statusIndicator += `${totalWaterTime}]\`\``;
2023-01-30 06:12:26 +00:00
2023-01-26 04:11:49 +00:00
// Determine if this tree is the guild's tree
if (leaderboardEntry.hasPin) {
2023-01-26 04:17:07 +00:00
comparisonReplyString += `#${leaderboardEntry.treeRank} - This is your tree`;
2023-01-26 04:11:49 +00:00
} else { // If it's another guild's tree
// Calculate the current height difference
const currentHeightDifference = guildInfo.treeHeight - leaderboardEntry.treeHeight;
2023-01-30 06:12:26 +00:00
2023-01-26 04:11:49 +00:00
if (currentHeightDifference > 0) { // Guild Tree is taller than the leaderboard tree
2023-01-26 04:14:40 +00:00
comparisonReplyString += `#${leaderboardEntry.treeRank} - ${currentHeightDifference.toFixed(1)}ft taller`;
2023-01-26 04:11:49 +00:00
} else {
2023-01-26 04:14:40 +00:00
comparisonReplyString += `#${leaderboardEntry.treeRank} - ${Math.abs(currentHeightDifference).toFixed(1)}ft shorter`;
2023-01-26 04:11:49 +00:00
}
}
2023-01-26 04:17:07 +00:00
// Build a string using the current leaderboard entry and the historic entry from 24 hours ago
2023-01-28 01:57:40 +00:00
comparisonReplyString += `${statusIndicator}\n`;
2023-01-27 23:14:01 +00:00
// if (process.env.isDev == 'true') comparisonReplyString += `Current Height: ${leaderboardEntry.treeHeight} 24h Ago Height: ${dayAgoTree.treeHeight}\n`;
2023-01-26 04:11:49 +00:00
}
return comparisonReplyString;
} catch (err) {
2023-01-30 06:12:26 +00:00
throw err;
2023-01-26 04:11:49 +00:00
}
}
},
tree: {
2023-01-30 06:12:26 +00:00
parse(interaction, guildInfo) {
let input;
return new Promise((resolve, reject) => {
2023-01-30 06:12:26 +00:00
if (guildInfo == undefined) {
reject(`The guild entry hasn't been created yet. [${interaction.guildId || interaction.commandGuildId}]`);
return;
}
if (guildInfo.treeMessageId != "Run /setup where your tree is.") {
interaction.guild.channels.fetch(guildInfo.treeChannelId).then(c => {
c.messages.fetch(guildInfo.treeMessageId).then(m => {
if ((m.embeds.length == 0) || !(m.embeds[0].data.description.includes('Your tree is'))) {
reject("This doesn't appear to be a valid ``/tree`` message.");
return;
}
input = m.embeds[0].data.description;
let treeName = m.embeds[0].data.title;
let lines = input.split('\n');
guildInfo.treeHeight = parseFloat(lines[0].slice(lines[0].indexOf('is') + 3, lines[0].indexOf('ft'))).toFixed(1);
guildInfo.treeName = treeName;
dbfn.setTreeInfo(guildInfo).then(res => {
resolve("The reference tree message has been saved/updated.");
});
}).catch(err => {
reject(strings.status.missingTreeMessage);
console.error(err);
return;
});
}).catch(err => {
reject(strings.status.missingTreeChannel);
console.error(err);
return;
2023-01-30 06:12:26 +00:00
});
} else {
console.error('treeMessageId undefined');
reject("There was an unknown error while setting the tree message.");
return;
}
});
}
},
messages: {
async find(interaction, guildInfo) {
try {
let response = { status: "Incomplete", data: undefined, code: 0 };
// If the tree channel ID and leaderboard channel ID are both set
if (guildInfo.treeChannelId != "" || guildInfo.leaderboardChannelId != "") {
// If one us unset, we'll set it to the current channel just to check
if (guildInfo.treeChannelId == "") {
guildInfo.treeChannelId = `${guildInfo.leaderboardChannelId}`;
} else if (guildInfo.leaderboardChannelId == "") {
guildInfo.leaderboardChannelId = `${guildInfo.treeChannelId}`;
}
2023-01-30 06:12:26 +00:00
let treeFound, leaderboardFound = false;
// If these values have already been set in the database, we don't want to report that they weren't found
// they'll still get updated later if applicable.
treeFound = (guildInfo.treeMessageId != "");
leaderboardFound = (guildInfo.leaderboardMessageId != "");
// If the Tree and Leaderboard messages are in the same channel
if (guildInfo.treeChannelId == guildInfo.leaderboardChannelId) {
// Fetch the tree channel so we can get the most recent messages
const treeChannel = await interaction.guild.channels.fetch(guildInfo.treeChannelId);
// Fetch the last 20 messages in the channel
const treeChannelMessageCollection = await treeChannel.messages.fetch({ limit: 20 });
// Create a basic array of [Message, Message, ...] from the Collection
const treeChannelMessages = Array.from(treeChannelMessageCollection.values());
// Iterate over the Messages in reverse order (newest messages first)
for (let i = treeChannelMessages.length - 1; i >= 0; i--) {
let treeChannelMessage = treeChannelMessages[i];
if (this.isTree(treeChannelMessage)) { // This is a tree message
// Set the tree message ID
guildInfo.treeMessageId = treeChannelMessage.id;
// Parse out the tree name
input = treeChannelMessage.embeds[0].data.description;
let treeName = treeChannelMessage.embeds[0].data.title;
// And tree height
let lines = input.split('\n');
guildInfo.treeHeight = parseFloat(lines[0].slice(lines[0].indexOf('is') + 3, lines[0].indexOf('ft'))).toFixed(1);
guildInfo.treeName = treeName;
2023-01-30 06:12:26 +00:00
// Upload the found messages to the database
await dbfn.setTreeInfo(guildInfo);
// Let the end of the function know we found a tree message and successfully uploaded it
treeFound = true;
} else if (this.isLeaderboard(treeChannelMessage)) { // This is a leaderboard message
// Set the leaderboard message ID
guildInfo.leaderboardMessageId = treeChannelMessage.id;
// Upload it to the database
await dbfn.setLeaderboardInfo(guildInfo);
// Let the end of the function know we found a leaderboard message and successfully uploaded it
leaderboardFound = true;
}
}
} else { // If the tree and leaderboard are in different channels
// Fetch the tree channel so we can get the most recent messages
const treeChannel = await interaction.guild.channels.fetch(guildInfo.treeChannelId);
// Fetch the last 20 messages in the tree channel
const treeChannelMessageCollection = await treeChannel.messages.fetch({ limit: 20 });
// Create an Array like [Message, Message, ...] from the Collection
const treeChannelMessages = Array.from(treeChannelMessageCollection.values());
// Iterate over the Array of Messages in reverse order (newest messages first)
for (let i = treeChannelMessages.length - 1; i >= 0; i--) {
let treeChannelMessage = treeChannelMessages[i];
if (this.isTree(treeChannelMessage)) { // This is a tree message
// Set the tree message ID
guildInfo.treeMessageId = treeChannelMessage.id;
// Parse out the tree name
input = treeChannelMessage.embeds[0].data.description;
let treeName = treeChannelMessage.embeds[0].data.title;
// And tree height
let lines = input.split('\n');
guildInfo.treeHeight = parseFloat(lines[0].slice(lines[0].indexOf('is') + 3, lines[0].indexOf('ft'))).toFixed(1);
guildInfo.treeName = treeName;
// Upload the found messages to the database
await dbfn.setTreeInfo(guildInfo);
// Let the end of the function know we found a tree message and successfully uploaded it
treeFound = true;
}
}
// Fetch the tree channel so we can get the most recent messages
const leaderboardChannel = await interaction.guild.channels.fetch(guildInfo.leaderboardChannelId);
// Fetch the last 20 messages in the leaderboard channel
const leaderboardChannelMessageCollection = await leaderboardChannel.messages.fetch({ limit: 20 });
// Create an Array like [Message, Message, ...] from the Collection
const leaderboardChannelMessages = Array.from(leaderboardChannelMessageCollection.values());
// Iterate over the Array of Messages in reverse order (newest messages first)
for (let i = leaderboardChannelMessages.length - 1; i >= 0; i--) {
let leaderboardChannelMessage = leaderboardChannelMessages[i];
if (this.isLeaderboard(leaderboardChannelMessage)) { // This is a leaderboard message
// Set the leaderboard message ID
guildInfo.leaderboardMessageId = leaderboardChannelMessage.id;
// Upload it to the database
await dbfn.setLeaderboardInfo(guildInfo);
// Let the end of the function know we've found a leaderboard
leaderboardFound = true;
}
}
}
2023-01-30 06:12:26 +00:00
// await dbfn.setGuildInfo(guildInfo);
// Bundle guildInfo into the response
const getGuildInfoResponse = await dbfn.getGuildInfo(guildInfo.guildId);
response.data = getGuildInfoResponse.data;
// Set the response status, this is only used as a response to /setup
if (treeFound && leaderboardFound) { // we found both the tree and leaderboard
response.status = strings.status.treeAndLeaderboard;
response.code = 1;
} else if (treeFound || leaderboardFound) { // Only found the tree
response.status = strings.status.missingMessage;
response.code = 2;
} else { // Didn't find any
response.status = strings.status.noneFound;
response.code = 3;
}
return response;
} else { // This should only ever occur if some weird database stuff happens
response.status = "It looks like this channel doesn't contain both your ``/tree`` and ``/top trees`` messages, please run ``/setup``";
return response;
}
} catch (err) {
throw "Problem checking messages: " + err;
}
},
isTree(message) {
if (message.embeds.length > 0) {
return message.embeds[0].data.description.includes("Your tree is");
}
},
isLeaderboard(message) {
if (message.embeds.length > 0) {
return message.embeds[0].data.title == "Tallest Trees";
}
}
},
2023-01-30 06:12:26 +00:00
async refresh(interaction) {
const getGuildInfoResponse = await dbfn.getGuildInfo(interaction.guildId);
let guildInfo = getGuildInfoResponse.data;
const findMessagesResponse = await this.messages.find(interaction, guildInfo);
if (findMessagesResponse.code == 1) {
guildInfo = findMessagesResponse.data;
// Parse the tree
await this.tree.parse(interaction, guildInfo);
// Parse the leaderboard
await this.rankings.parse(interaction, guildInfo);
// Build the string that shows the comparison // TODO Move the string building section to fn.builders?
const comparedRankings = await this.rankings.compare(interaction, guildInfo);
2023-01-31 00:28:12 +00:00
const embed = this.builders.comparisonEmbed(comparedRankings, guildInfo);
2023-02-01 03:30:20 +00:00
await interaction.update(embed).then(async interactionResponse => {
// console.log(interactionResponse.interaction.message);
await dbfn.setComparisonMessage(interactionResponse.interaction.message, interaction.guildId);
});
2023-01-30 06:12:26 +00:00
} else {
await interaction.update(this.builders.errorEmbed(findMessagesResponse.status));
}
},
reset(guildId) {
return new Promise((resolve, reject) => {
dbfn.deleteGuildInfo(guildId).then(res => {
resolve(res);
}).catch(err => {
console.error(err);
reject(err);
return;
});
});
},
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;
})
});
2023-01-23 23:14:57 +00:00
},
getWaterTime(size) {
2023-01-27 02:30:41 +00:00
return Math.floor(Math.pow(size * 0.07 + 5, 1.1)); // Seconds
},
2023-01-27 02:30:41 +00:00
timeToHeight(beginHeight, destHeight) {
return new Promise((resolve, reject) => {
2023-01-27 02:30:41 +00:00
let time = 0;
for (let i = beginHeight; i < destHeight; i++) {
const waterTime = parseFloat(functions.getWaterTime(i));
// console.log("Height: " + i + "Time: " + waterTime);
time += waterTime;
}
// 60 secs in min
// 3600 secs in hr
// 86400 sec in day
let units = " secs";
2023-01-30 06:12:26 +00:00
if (60 < time && time <= 3600) { // Minutes
2023-01-27 02:30:41 +00:00
time = parseFloat(time / 60).toFixed(1);
units = " mins";
2023-01-30 06:12:26 +00:00
} else if (3600 < time && time <= 86400) {
2023-01-27 02:30:41 +00:00
time = parseFloat(time / 3600).toFixed(1);
units = " hrs";
2023-01-30 06:12:26 +00:00
} else if (86400 < time) {
2023-01-27 02:30:41 +00:00
time = parseFloat(time / 86400).toFixed(1);
units = " days";
}
resolve(time + units);
});
},
2023-01-27 23:14:01 +00:00
sleep(ms) {
2023-02-01 03:30:20 +00:00
// console.log(`Begin Sleep: ${new Date(Date.now()).getSeconds()}`);
return new Promise(resolve => {
setTimeout(function () {
resolve();
// console.log(`End Sleep: ${new Date(Date.now()).getSeconds()}`);
}, ms);
});
2023-01-27 23:14:01 +00:00
},
async sendReminder(guildInfo, guild) {
const { guildId, reminderChannelId, reminderMessage } = guildInfo;
const reminderChannel = await guild.channels.fetch(reminderChannelId);
const reminderEmbed = functions.builders.reminderEmbed(reminderMessage, guildInfo);
2023-01-31 22:23:26 +00:00
await reminderChannel.send(reminderEmbed).then(async m => {
const setRemindedStatusReponse = await dbfn.setRemindedStatus(guildId, 1);
2023-01-31 00:28:12 +00:00
return 1;
2023-01-27 23:14:01 +00:00
}).catch(err => {
console.error(err);
});
},
async setReminder(interaction, ms) {
setTimeout(this.sendReminder(interaction), ms);
},
async checkReady(client) { // Check if the guilds trees are ready to water
2023-02-01 03:30:20 +00:00
// let time = new Date(Date.now());
// console.log("Ready check " + time.getSeconds());
2023-01-27 23:14:01 +00:00
try {
2023-01-31 22:23:26 +00:00
// Get the guildInfos for each guild that is opted in and waiting to send a reminder
2023-01-27 23:14:01 +00:00
const getOptedInGuildsResponse = await dbfn.getOptedInGuilds();
2023-01-31 22:23:26 +00:00
// getOptedInGuilds will return this if it gets an empty set from the database
2023-01-27 23:14:01 +00:00
if (getOptedInGuildsResponse.status != "No servers have opted in yet") {
2023-01-31 22:23:26 +00:00
// Get the Array of Guilds from the response
2023-01-27 23:14:01 +00:00
const guilds = getOptedInGuildsResponse.data;
2023-01-31 22:23:26 +00:00
// Iterate over the Array
2023-01-31 03:03:47 +00:00
for (let i = 0; i < guilds.length; i++) {
2023-01-31 22:23:26 +00:00
// console.log(`iter: ${i}`);
// Save the 'old' guild info that came from getOptedInGuilds
2023-01-31 03:03:47 +00:00
const oldGuildInfo = guilds[i];
2023-01-31 22:23:26 +00:00
// Get up-to-date guildInfo from the database, probably unnecessary and redundant
2023-01-31 02:38:12 +00:00
const getGuildInfoResponse = await dbfn.getGuildInfo(oldGuildInfo.guildId);
2023-01-31 22:23:26 +00:00
// Save the new guildInfo so we can reference its remindedStatus
2023-01-31 02:38:12 +00:00
const guildInfo = getGuildInfoResponse.data;
2023-01-27 23:14:01 +00:00
const { guildId, treeChannelId, treeMessageId, remindedStatus } = guildInfo;
2023-01-31 22:23:26 +00:00
// console.log(`${guildInfo.treeName}: ${remindedStatus}`);
// Double check the remindedStatus to prevent double pings
2023-01-27 23:14:01 +00:00
if (remindedStatus == 0) {
2023-01-31 22:23:26 +00:00
// Fetch the guild
2023-01-27 23:14:01 +00:00
const guild = await client.guilds.fetch(guildId);
2023-01-31 22:23:26 +00:00
// Fetch the tree channel
2023-01-27 23:14:01 +00:00
const treeChannel = await guild.channels.fetch(treeChannelId);
2023-01-31 22:23:26 +00:00
// Fetch the tree message
2023-01-27 23:14:01 +00:00
const treeMessage = await treeChannel.messages.fetch(treeMessageId);
2023-01-31 22:23:26 +00:00
// Get the description from the embed of the tree message
2023-01-31 02:38:12 +00:00
const description = treeMessage.embeds[0].description;
2023-01-31 22:23:26 +00:00
// Default to not being ready to water
2023-01-31 03:03:47 +00:00
let readyToWater = false;
2023-01-31 22:23:26 +00:00
// Obviously if the tree says it's Ready to be watered, it's ready
2023-01-31 03:03:47 +00:00
if (description.includes("Ready to be watered")) {
readyToWater = true;
2023-02-01 03:30:20 +00:00
// 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.
2023-01-31 03:03:47 +00:00
} else {
const beginWaterTimestamp = description.indexOf("<t:") + 3;
const endWaterTimestamp = description.indexOf(":>");
2023-01-31 22:23:26 +00:00
// Split the description starting at "<t:" and ending at ":>" to get just the numerical timestamp
2023-01-31 03:03:47 +00:00
const waterTimestamp = parseInt(description.slice(beginWaterTimestamp, endWaterTimestamp));
2023-01-31 22:23:26 +00:00
// The Discord timestamp is in seconds, not ms so we need to divide by 1000
2023-01-31 03:03:47 +00:00
const nowTimestamp = (Date.now() / 1000);
readyToWater = (nowTimestamp > waterTimestamp);
}
2023-01-27 23:14:01 +00:00
if (readyToWater) {
2023-01-31 22:23:26 +00:00
// Send the reminder message
2023-01-30 06:12:26 +00:00
await this.sendReminder(guildInfo, guild);
2023-02-01 03:30:20 +00:00
guildInfo.remindedStatus = 1;
await this.refreshComparisonMessage(client, guildInfo);
2023-01-27 23:14:01 +00:00
}
}
2023-01-31 03:03:47 +00:00
}
2023-02-01 03:30:20 +00:00
await this.sleep(5000);
this.checkReady(client);
2023-01-27 23:14:01 +00:00
} else {
// console.log(getOptedInGuildsResponse.status);
2023-02-01 03:30:20 +00:00
await this.sleep(5000);
this.checkReady(client);
2023-01-27 23:14:01 +00:00
}
2023-01-30 06:12:26 +00:00
} catch (err) {
2023-01-27 23:14:01 +00:00
console.error(err);
2023-02-01 03:30:20 +00:00
await this.sleep(30000);
this.checkReady(client);
}
},
async refreshComparisonMessage(client, guildInfo) {
if (guildInfo.comparisonChannelId != "" && guildInfo.comparisonMessageId != "") {
const guild = await client.guilds.fetch(guildInfo.guildId);
const comparisonChannel = await guild.channels.fetch(guildInfo.comparisonChannelId);
const comparisonMessage = await comparisonChannel.messages.fetch(guildInfo.comparisonMessageId);
const embed = comparisonMessage.embeds[0];
const actionRow = this.builders.actionRows.comparisonActionRow(guildInfo);
await comparisonMessage.edit({ components: [actionRow] });
2023-01-31 02:38:12 +00:00
return;
2023-01-27 23:14:01 +00:00
}
},
2023-01-31 00:28:12 +00:00
async resetPing(interaction) {
await dbfn.setRemindedStatus(interaction.guildId, 0);
2023-01-19 01:10:05 +00:00
}
2023-01-18 00:35:24 +00:00
};
module.exports = functions;