diff --git a/README.md b/README.md index 12ad72f..e2a7e1e 100644 --- a/README.md +++ b/README.md @@ -15,30 +15,33 @@ Add the bot to your server and make sure it has the proper permissions (`Send Me ## Database Structure -### Table: guildinfo +### Table: guild_info ``` -+-----------------+-------------+------+-----+---------+----------------+ -| Field | Type | Null | Key | Default | Extra | -+-----------------+-------------+------+-----+---------+----------------+ -| id | int(10) | NO | PRI | NULL | auto_increment | -| guild_id | varchar(50) | NO | | NULL | | -| tree_message_id | varchar(50) | NO | | NULL | | -| tree_channel_id | varchar(50) | NO | | NULL | | -| rank_message_id | varchar(50) | NO | | NULL | | -| rank_channel_id | varchar(50) | NO | | NULL | | -| tree_height | varchar(10) | NO | | NULL | | -+-----------------+-------------+------+-----+---------+----------------+ ++------------------------+-------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+-------------+------+-----+---------+----------------+ +| guild_id | varchar(50) | NO | PRI | NULL | auto_increment | +| tree_message_id | varchar(50) | NO | | | | +| tree_channel_id | varchar(50) | NO | | | | +| leaderboard_message_id | varchar(50) | NO | | | | +| leaderboard_channel_id | varchar(50) | NO | | | | +| tree_height | varchar(10) | NO | | 0 | | ++------------------------+-------------+------+-----+---------+----------------+ + ``` -### Table: treeinfo +### Table: leaderboard_info ``` -+-----------+--------------+------+-----+---------+----------------+ -| Field | Type | Null | Key | Default | Extra | -+-----------+--------------+------+-----+---------+----------------+ -| id | int(10) | NO | PRI | NULL | auto_increment | -| treename | varchar(100) | NO | | NULL | | -| treerank | int(10) | NO | | NULL | | -| timestamp | varchar(50) | NO | | NULL | | -+-----------+--------------+------+-----+---------+----------------+ ++-------------+--------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+--------------+------+-----+---------+----------------+ +| id | int(10) | NO | PRI | NULL | auto_increment | +| guild_id | varchar(50) | NO | | | | +| tree_name | varchar(100) | NO | | | | +| tree_rank | int(10) | NO | | | | +| tree_height | int(10) | NO | | 0 | | +| has_pin | tinyint(1) | NO | | 0 | | +| timestamp | varchar(50) | NO | | | | ++-------------+--------------+------+-----+---------+----------------+ ``` ## Changes to Implement diff --git a/modules/dbfn.js b/modules/dbfn.js new file mode 100644 index 0000000..7ed10a0 --- /dev/null +++ b/modules/dbfn.js @@ -0,0 +1,229 @@ +const dotenv = require('dotenv'); +dotenv.config(); +const debugMode = process.env.DEBUG || true; +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 +}); + +/* Table Structures +guild_info ++------------------------+-------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++------------------------+-------------+------+-----+---------+----------------+ +| guild_id | varchar(50) | NO | PRI | NULL | auto_increment | +| tree_name | varchar(100)| NO | | | | +| tree_height | varchar(10) | NO | | 0 | | +| tree_message_id | varchar(50) | NO | | | | +| tree_channel_id | varchar(50) | NO | | | | +| leaderboard_message_id | varchar(50) | NO | | | | +| leaderboard_channel_id | varchar(50) | NO | | | | ++------------------------+-------------+------+-----+---------+----------------+ +*/ +/* +leaderboard ++-------------+--------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-------------+--------------+------+-----+---------+----------------+ +| id | int(10) | NO | PRI | NULL | auto_increment | +| guild_id | varchar(50) | NO | | | | +| tree_name | varchar(100) | NO | | | | +| tree_rank | int(10) | NO | | | | +| tree_height | int(10) | NO | | 1 | | +| has_pin | tinyint(1) | NO | | 0 | | +| timestamp | varchar(50) | NO | | | | ++-------------+--------------+------+-----+---------+----------------+ +*/ + +db.connect((err) => { + if (err) throw `Error connecting to the database: ${err.message}`; +}); + +db.on('error', function(err) { + if(err.code === 'PROTOCOL_CONNECTION_LOST' || err.code == 'ECONNRESET') { + db.connect((err) => { + if (err) throw `Error connecting to the database: ${err.message}`; + }); + } else { + throw err; + } + }); + + +module.exports = { + createGuildTables(guildId) { + // 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); + return; + } + db.query(createLeaderboardTableQuery, (err) => { + if (err) { + reject("Error creating the leaderboard table: " + err.message); + console.error("Offending query: " + createLeaderboardTableQuery); + return; + } + resolve({ "status": "Successfully checked both tables.", "data": null }) + }); + }); + }); + }, + getGuildInfo(guildId) { + // Get a server's tree information from the database + const selectGuildInfoQuery = `SELECT tree_name, tree_height, tree_message_id, tree_channel_id, leaderboard_message_id, leaderboard_channel_id FROM guild_info WHERE guild_id = ${db.escape(guildId)}`; + // 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(selectGuildInfoQuery, (err, res) => { + if (err) { + console.error(err); + reject("Error fetching guild information: " + err.message); + return; + } + /*const guildInfo = { "guildId": "123", + "treeName": "name", + "treeHeight": 123, + "treeMessageId": "123", + "treeChannelId": "123", + "leaderboardMessageId": "123", + "leaderboardChannelId": "123" + };*/ + if (res.length == 0) { + reject("There is no database entry for your guild yet. Try running /setup"); + return; + } + row = res[0]; + const guildInfo = { "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 + }; + resolve({ "status": "Successfully fetched guild information", "data": guildInfo }) + }); + }); + }, + setGuildInfo(guildInfo) { + // Returns a Promise, resolve({ "status": "", "data": null }) + // guildInfo = { "guildId": "123", "treeName": "name", "treeHeight": 123, "treeMessageId": "123", "treeChannelId": "123", "leaderboardMessageId": "123", "leaderboardChannelId": "123"} + // Set a server's tree information in the database + 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) => { + db.query(insertGuildInfoQuery, (err, res) => { + if (err) { + console.error(err); + reject("Error setting the guild info: " + err.message); + return; + } + resolve({ "status": "Successfully set the guild information", "data": null }); + }); + }); + }, + setTreeInfo(guildInfo) { + // Returns a Promise, resolve({ "status": "", "data": null }) + // guildInfo = { "guildId": "123", "treeName": "name", "treeHeight": 123, "treeMessageId": "123", "treeChannelId": "123", "leaderboardMessageId": "123", "leaderboardChannelId": "123"} + // Set a server's tree information in the database) + const insertGuildInfoQuery = `INSERT INTO guild_info (guild_id, tree_name, tree_height, tree_message_id, tree_channel_id) VALUES (${db.escape(guildInfo.guildId)}, ${db.escape(guildInfo.treeName)}, ${db.escape(guildInfo.treeHeight)},${db.escape(guildInfo.treeMessageId)}, ${db.escape(guildInfo.treeChannelId)}) 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)}`; + // TODO run this query and return a promise, then resolve with { "status": , "data": null } + return new Promise((resolve, reject) => { + db.query(insertGuildInfoQuery, (err, res) => { + if (err) { + console.error(err); + reject("Error setting the guild info: " + err.message); + return; + } + resolve({ "status": "Successfully set the guild information", "data": null }); + }); + }); + }, + setLeaderboardInfo(guildInfo) { + // Returns a Promise, resolve({ "status": "", "data": null }) + // guildInfo = { "guildId": "123", "treeName": "name", "treeHeight": 123, "treeMessageId": "123", "treeChannelId": "123", "leaderboardMessageId": "123", "leaderboardChannelId": "123"} + // Set a server's tree information in the database + const insertGuildInfoQuery = `INSERT INTO guild_info (guild_id, leaderboard_message_id, leaderboard_channel_id) VALUES (${db.escape(guildInfo.guildId)}, ${db.escape(guildInfo.leaderboardMessageId)}, ${db.escape(guildInfo.leaderboardChannelId)}) ON DUPLICATE KEY UPDATE 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) => { + db.query(insertGuildInfoQuery, (err, res) => { + if (err) { + console.error(err); + reject("Error setting the guild info: " + err.message); + return; + } + resolve({ "status": "Successfully set the guild information", "data": null }); + }); + }); + }, + deleteGuildInfo(guildId) { + // Returns a Promise, resolve({ "status": "", "data": null }) + // guildInfo = { "guildId": "123", "treeName": "name", "treeHeight": 123, "treeMessageId": "123", "treeChannelId": "123", "leaderboardMessageId": "123", "leaderboardChannelId": "123"} + // Set a server's tree information in the database + const deleteGuildInfoQuery = `DELETE FROM guild_info WHERE guild_id = ${db.escape(guildId)}`; + // TODO run this query and return a promise, then resolve with { "status": , "data": null } + return new Promise((resolve, reject) => { + db.query(deleteGuildInfoQuery, (err, res) => { + if (err) { + console.error(err); + reject("Error deleting the guild info: " + err.message); + return; + } + resolve({ "status": "Successfully deleted the guild information", "data": null }); + }); + }); + }, + getLeaderboard(guildId) { + // Returns a Promise, resolve({ "status": "", "data": leaderboard }) + const selectLeaderboardQuery = `SELECT id, tree_name, tree_rank, tree_height, has_pin FROM leaderboard WHERE guild_id = ${db.escape(guildId)} ORDER BY id DESC LIMIT 10`; + // TODO run the query and return a promise then process the results. resolve with { "status": , "data": leaderboard } + return new Promise((resolve, reject) => { + db.query(selectLeaderboardQuery, (err, res) => { + if (err) { + console.error(err); + reject("Error fetching the most recent leaderboard: " + err.message); + return; + } + let leaderboard = []; + res.forEach(row => { + leaderboard.push({ + "treeName": row.tree_name, + "treeRank": row.tree_rank, + "treeHeight": row.tree_height, + "hasPin": row.has_pin + }); + }); + resolve({ "status": "Successfully fetched leaderboard.", "data": leaderboard }); + }); + }); + }, + uploadLeaderboard(leaderboard) { + // Returns a Promise, resolve({ "status": "", "data": res }) + // leaderboard = { "guildId": 1234, "entries": [ { "treeHeight": 12, "treeRank": 34, "treeName": "name", "hasPin": false }, {...}, {...} ] } + const insertLeaderboardQuery = "INSERT INTO `leaderboard` (guild_id, tree_name, tree_rank, tree_height, has_pin) VALUES ?"; + const leaderboardValues = []; + leaderboard.entries.forEach(ranking => { + leaderboardValues.push([leaderboard.guildId, ranking.treeName, ranking.treeRank, ranking.treeHeight, ranking.hasPin]); + }); + return new Promise((resolve, reject) => { + db.query(insertLeaderboardQuery, [leaderboardValues], (err, res) => { + if (err) { + reject("Error uploading the leaderboard: " + err.message); + console.error(err); + return; + } + resolve({ "status": "Successfully uploaded the leaderboard", "data": res }); + }); + }); + }, + db +}; \ No newline at end of file diff --git a/modules/functions.js b/modules/functions.js index 013eccc..887b136 100644 --- a/modules/functions.js +++ b/modules/functions.js @@ -13,9 +13,15 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord; // Various imports from other files const config = require('../data/config.json'); -let guildInfo = require('../data/guildInfo.json'); const strings = require('../data/strings.json'); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); +const dbfn = require('./dbfn.js'); + +dbfn.createGuildTables().then(res => { + console.log(res.status); +}).catch(err => { + console.error(err); +}); const functions = { // Functions for managing and creating Collections @@ -89,168 +95,208 @@ const functions = { rankings: { parse(interaction) { return new Promise ((resolve, reject) => { - if (guildInfo[interaction.guildId] == undefined) { - reject(strings.error.noGuild); - return; - } - if (guildInfo[interaction.guildId].rankMessageId != undefined) { - interaction.guild.channels.fetch(guildInfo[interaction.guildId].rankChannelId).then(c => { - c.messages.fetch(guildInfo[interaction.guildId].rankMessageId).then(rankMessage => { - if ((rankMessage.embeds.length == 0) || (rankMessage.embeds[0].data.title != 'Tallest Trees' )) { - reject("This doesn't appear to be a valid ``/top trees`` message."); - return; - } - let lines = rankMessage.embeds[0].data.description.split('\n'); - let rankings = []; - for (let i = 0; i < 10; i++) { - let breakdown = lines[i].split(' - '); - if (breakdown[0].includes('🥇')) { - breakdown[0] = '``#1 ``' - } else if (breakdown[0].includes('🥈')) { - breakdown[0] = '``#2 ``' - } else if (breakdown[0].includes('🥉')) { - breakdown[0] = '``#3 ``' + dbfn.getGuildInfo(interaction.guildId).then(res => { + const guildInfo = res.data; + 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 trimmedRank = breakdown[0].slice(breakdown[0].indexOf('#') + 1, breakdown[0].lastIndexOf('``')); - - let trimmedName = breakdown[1].slice(breakdown[1].indexOf('``') + 2); - trimmedName = trimmedName.slice(0, trimmedName.indexOf('``')); - - 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[interaction.guildId].treeName)) maybeMyTree = true; - - rankings.push({ - rank: trimmedRank, - name: trimmedName, - height: trimmedHeight, - myTree: isMyTree, - maybeMyTree: isMaybeMyTree + 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 ``' + } + + // 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('``'))); + + // 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 + }); + } + + dbfn.uploadLeaderboard(leaderboard).then(res => { + console.log(res.status); + resolve(res.status); + }).catch(err => { + console.error(err); + reject(err); + return; }); - } - - guildInfo[interaction.guildId].rankings = rankings; - fs.writeFileSync('./data/guildInfo.json', JSON.stringify(guildInfo)); - guildInfo = require('../data/guildInfo.json'); - resolve(rankings); + }); }); - }); - } else { - reject("The rankMessageId is undefined somehow"); - return; - } + } else { + reject("The leaderboardMessageId is undefined somehow"); + return; + } + }); }); }, compare(interaction) { - if (guildInfo[interaction.guildId] == undefined) { - return strings.error.noGuild; - } - let treeHeight = parseFloat(guildInfo[interaction.guildId].treeHeight).toFixed(1); - if ((guildInfo[interaction.guildId].rankings.length > 0) && (treeHeight > 0)) { - let replyString = 'Current Tree Height: ' + treeHeight + 'ft\n\n'; - guildInfo[interaction.guildId].rankings.forEach(treeRanking => { - let difference = parseFloat(treeRanking.height).toFixed(1) - treeHeight; - let decimal = (treeRanking.height % 1).toFixed(1); - let growthIndicator = ""; - if (decimal > 0) { - growthIndicator += "[+]"; - } - const absDifference = parseFloat(Math.abs(difference)).toFixed(1); - if (treeRanking.myTree) { - replyString += "This is your tree. "; - } else if (treeRanking.maybeMyTree) { - replyString += "This might be your tree. Same height, same name. "; - } else { - if (difference > 0) { - replyString += `#${treeRanking.rank} - ${absDifference}ft${growthIndicator} shorter `; - } else if (difference < 0) { - replyString += `#${treeRanking.rank} - ${absDifference}ft${growthIndicator} taller `; - } else if (difference == 0) { - replyString += `#${treeRanking.rank} - Same Height${growthIndicator} `; - } - } - replyString += `[${functions.getWaterTime(treeRanking.height)} mins]\n`; + return new Promise((resolve, reject) => { + dbfn.getGuildInfo(interaction.guildId).then(res => { + const guildInfo = res.data; + guildInfo.guildId = interaction.guildId; + + let treeHeight = parseFloat(guildInfo.treeHeight).toFixed(1); + dbfn.getLeaderboard(interaction.guildId).then(res => { + const leaderboard = res.data; + + let replyString = 'Current Tree Height: ' + treeHeight + 'ft\n\n'; + leaderboard.forEach(treeRanking => { + let difference = parseFloat(treeRanking.treeHeight).toFixed(1) - treeHeight; + let decimal = (treeRanking.treeHeight % 1).toFixed(1); + let growthIndicator = ""; + if (decimal > 0) { + growthIndicator += "[+]"; + } + const absDifference = parseFloat(Math.abs(difference)).toFixed(1); + if (treeRanking.hasPin) { + replyString += "This is your tree. "; + } else if ((treeRanking.treeHeight == treeHeight) && (treeRanking.treeName == guildInfo.treeName)) { + replyString += "This might be your tree. Same height, same name. "; + } else { + if (difference > 0) { + replyString += `#${treeRanking.treeRank} - ${absDifference}ft${growthIndicator} shorter `; + } else if (difference < 0) { + replyString += `#${treeRanking.treeRank} - ${absDifference}ft${growthIndicator} taller `; + } else if (difference == 0) { + replyString += `#${treeRanking.treeRank} - Same Height${growthIndicator} `; + } + } + replyString += `[${functions.getWaterTime(treeRanking.treeHeight)} mins]\n`; + }); + resolve('Here\'s how your tree compares: \n' + replyString); + }).catch(err => { + console.error(err); + }); + }).catch(err => { + reject(err); }); - return 'Here\'s how your tree compares: \n' + replyString; - } else { - console.error('Not configured correctly\n' + 'Guild ID: ' + interaction.guildId + '\nGuild Info: ' + JSON.stringify(guildInfo[interaction.guildId])); - return 'Not configured correctly'; - } + }); } }, tree: { parse(interaction) { let input; return new Promise((resolve, reject) => { - if (guildInfo[interaction.guildId] == undefined) { - reject(`The guild entry hasn't been created yet. [${interaction.guildId || interaction.commandGuildId}]`); + dbfn.getGuildInfo(interaction.guildId).then(res => { + const guildInfo = res.data; + guildInfo.guildId = interaction.guildId; + 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."); + }); + }); + }) + } else { + console.error('treeMessageId undefined'); + reject("There was an unknown error while setting the tree message."); + return; + } + }).catch(err => { + reject(err); + console.error(err); return; - } - if (guildInfo[interaction.guildId].treeMessageId != "") { - interaction.guild.channels.fetch(guildInfo[interaction.guildId].treeChannelId).then(c => { - c.messages.fetch(guildInfo[interaction.guildId].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[interaction.guildId].treeHeight = parseFloat(lines[0].slice(lines[0].indexOf('is') + 3, lines[0].indexOf('ft'))).toFixed(1); - guildInfo[interaction.guildId].treeName = treeName; - fs.writeFileSync('./data/guildInfo.json', JSON.stringify(guildInfo)); - guildInfo = require('../data/guildInfo.json'); - resolve("The reference tree message has been saved/updated."); - }); - }) - } else { - console.error('treeMessageId undefined'); - reject("There was an unknown error while setting the tree message."); - return; - } + }); }); } }, refresh(interaction) { functions.rankings.parse(interaction).then(r1 => { functions.tree.parse(interaction).then(r2 => { - const embed = functions.builders.comparisonEmbed(functions.rankings.compare(interaction), functions.builders.refreshAction()) - interaction.update(embed); + functions.rankings.compare(interaction).then(res => { + const embed = functions.builders.comparisonEmbed(res, functions.builders.refreshAction()) + interaction.update(embed); + }).catch(err => { + console.error(err); + }); }).catch(e => { + console.error(e); interaction.reply(functions.builders.errorEmbed(e)); }); }).catch(e => { + console.error(e); interaction.reply(functions.builders.errorEmbed(e)); }); }, reset(guildId) { - delete guildInfo[guildId]; - fs.writeFileSync('./data/guildInfo.json', JSON.stringify(guildInfo)); - guildInfo = require('../data/guildInfo.json'); - return; + return new Promise((resolve, reject) => { + dbfn.deleteGuildInfo(guildId).then(res => { + resolve(res); + }).catch(err => { + console.error(err); + reject(err); + return; + }); + }); }, getInfo(guildId) { - const thisGuildInfo = guildInfo[guildId]; - if (thisGuildInfo != undefined) { - let thisGuildInfoString = ""; - if (thisGuildInfo.treeMessageId != "") { - thisGuildInfoString += `Tree Message: https://discord.com/channels/${guildId}/${thisGuildInfo.treeChannelId}/${thisGuildInfo.treeMessageId}\n`; - - } - if (thisGuildInfo.rankMessageId != "") { - thisGuildInfoString += `Rank Message: https://discord.com/channels/${guildId}/${thisGuildInfo.rankChannelId}/${thisGuildInfo.rankMessageId}\n`; - } - if (thisGuildInfo.treeHeight != "") { - thisGuildInfoString += `Tree Height: ${thisGuildInfo.treeHeight}\n`; - } - return `Here is your servers setup info:\n${thisGuildInfoString}`; - } else { - return "Your guild hasn't been set up yet."; - } + 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) { return Math.floor((Math.pow(size * 0.07 + 5, 1.1) / 60)); diff --git a/package.json b/package.json index 36da471..6f36efc 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "homepage": "https://github.com/voidf1sh/silvanus#readme", "dependencies": { "discord.js": "^14.7.1", - "dotenv": "^16.0.3" + "dotenv": "^16.0.3", + "mysql": "^2.18.1" } } diff --git a/slash-commands/compare.js b/slash-commands/compare.js index cf0ba38..37864f8 100644 --- a/slash-commands/compare.js +++ b/slash-commands/compare.js @@ -6,7 +6,18 @@ module.exports = { .setName('compare') .setDescription('See how your tree compares to other trees!'), async execute(interaction) { - const embed = fn.builders.comparisonEmbed(fn.rankings.compare(interaction), fn.builders.refreshAction()); - interaction.reply(embed); + interaction.deferReply().then(() => { + fn.rankings.compare(interaction).then(res => { + const embed = fn.builders.comparisonEmbed(res, fn.builders.refreshAction()); + interaction.editReply(embed).catch(err => { + console.error(err); + }); + }).catch(err => { + interaction.editReply(fn.builders.errorEmbed(err)).catch(err => { + console.error(err); + }); + console.error(err); + }); + }) }, }; \ No newline at end of file diff --git a/slash-commands/reset.js b/slash-commands/reset.js index cecb3cd..7cd7985 100644 --- a/slash-commands/reset.js +++ b/slash-commands/reset.js @@ -6,7 +6,19 @@ module.exports = { .setName('reset') .setDescription('Reset all message assignments in your server'), execute(interaction) { - fn.reset(interaction.guildId); - interaction.reply(fn.builders.embed("Assignments Reset")); + 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); + }); }, }; \ No newline at end of file diff --git a/slash-commands/setup.js b/slash-commands/setup.js index 646fc79..1a95bed 100644 --- a/slash-commands/setup.js +++ b/slash-commands/setup.js @@ -1,7 +1,7 @@ const { SlashCommandBuilder } = require('discord.js'); const fn = require('../modules/functions.js'); -const guildInfo = require('../data/guildInfo.json'); const strings = require('../data/strings.json'); +const dbfn = require('../modules/dbfn.js'); module.exports = { data: new SlashCommandBuilder() @@ -9,41 +9,57 @@ module.exports = { .setDescription('Attempt automatic configuration of the bot.'), execute(interaction) { interaction.deferReply({ ephemeral: true }).then(function () { - if (guildInfo[interaction.guildId] == undefined) { - guildInfo[interaction.guildId] = { - "treeMessageId": "", - "treeChannelId": "", - "rankMessageId": "", - "rankChannelId": "", - "treeName": "", - "treeHeight": 0, - "rankings": [] - }; - } + /*const guildInfo = { "guildId": "123", + "treeName": "name", + "treeHeight": 123, + "treeMessageId": "123", + "treeChannelId": "123", + "leaderboardMessageId": "123", + "leaderboardChannelId": "123" + };*/ + const guildInfo = { "guildId": interaction.guildId, + "treeName": "name", + "treeHeight": 123, + "treeMessageId": "123", + "treeChannelId": "123", + "leaderboardMessageId": "123", + "leaderboardChannelId": "123" + }; interaction.channel.messages.fetch({ limit: 20 }).then(function (msgs) { let treeFound = false; - let rankFound = false; + let leaderboardFound = false; msgs.reverse().forEach(msg => { if (msg.embeds.length > 0) { if (msg.embeds[0].data.description.includes("Your tree is")) { treeFound = true; - guildInfo[interaction.guildId].treeChannelId = msg.channelId; - guildInfo[interaction.guildId].treeMessageId = msg.id; - fn.tree.parse(msg); + guildInfo.treeName = msg.embeds[0].title; + guildInfo.treeChannelId = msg.channelId; + guildInfo.treeMessageId = msg.id; } else if (msg.embeds[0].data.title == "Tallest Trees") { - rankFound = true; - guildInfo[interaction.guildId].rankChannelId = msg.channelId; - guildInfo[interaction.guildId].rankMessageId = msg.id; - fn.rankings.parse(msg); + leaderboardFound = true; + guildInfo.leaderboardChannelId = msg.channelId; + guildInfo.leaderboardMessageId = msg.id; } } }); - if (treeFound && !(rankFound)) { - interaction.editReply(fn.builders.embed(strings.status.treeNoLeaderboard)); - } else if (!(treeFound) && rankFound) { - interaction.editReply(fn.builders.embed(strings.status.leaderboardNoTree)); - } else if (treeFound && rankFound) { - interaction.editReply(fn.builders.embed(strings.status.treeAndLeaderboard)); + if (treeFound && !(leaderboardFound)) { + dbfn.setTreeInfo(guildInfo).then(res => { + interaction.editReply(fn.builders.embed(strings.status.treeNoLeaderboard)); + }).catch(err => { + console.error(err); + }); + } else if (!(treeFound) && leaderboardFound) { + dbfn.setLeaderboardInfo(guildInfo).then(res => { + interaction.editReply(fn.builders.embed(strings.status.leaderboardNoTree)); + }).catch(err => { + console.error(err); + }); + } else if (treeFound && leaderboardFound) { + dbfn.setGuildInfo(guildInfo).then(res => { + interaction.editReply(fn.builders.embed(strings.status.treeAndLeaderboard)); + }).catch(err => { + console.error(err); + }); } }); }); diff --git a/slash-commands/setupinfo.js b/slash-commands/setupinfo.js index b30871a..8597c94 100644 --- a/slash-commands/setupinfo.js +++ b/slash-commands/setupinfo.js @@ -6,7 +6,16 @@ module.exports = { .setName('setupinfo') .setDescription('View information about how the bot is set up in your server'), execute(interaction) { - const embed = fn.builders.embed(fn.getInfo(interaction.guildId)); - interaction.reply(embed); + 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); + }); }, }; \ No newline at end of file