Migrate to database for long term storage
This commit is contained in:
		
							parent
							
								
									0539c94e79
								
							
						
					
					
						commit
						1cde2f6915
					
				
							
								
								
									
										39
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								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    |                | | ||||
| +-----------------+-------------+------+-----+---------+----------------+ | ||||
| +------------------------+-------------+------+-----+---------+----------------+ | ||||
| | 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    |                | | ||||
| +-----------+--------------+------+-----+---------+----------------+ | ||||
| | 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 | ||||
|  | ||||
							
								
								
									
										229
									
								
								modules/dbfn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								modules/dbfn.js
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| }; | ||||
| @ -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,21 +95,29 @@ const functions = { | ||||
| 	rankings: { | ||||
| 		parse(interaction) { | ||||
| 			return new Promise ((resolve, reject) => { | ||||
| 				if (guildInfo[interaction.guildId] == undefined) { | ||||
| 				dbfn.getGuildInfo(interaction.guildId).then(res => { | ||||
| 					const guildInfo = res.data; | ||||
| 					if (guildInfo.guildId == "") { | ||||
| 						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' )) { | ||||
| 					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 = rankMessage.embeds[0].data.description.split('\n'); | ||||
| 							let rankings = []; | ||||
| 								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('🥈')) { | ||||
| @ -112,87 +126,107 @@ const functions = { | ||||
| 										breakdown[0] = '``#3 ``' | ||||
| 									} | ||||
| 									 | ||||
| 								let trimmedRank = breakdown[0].slice(breakdown[0].indexOf('#') + 1, breakdown[0].lastIndexOf('``')); | ||||
| 									// 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[interaction.guildId].treeName)) maybeMyTree = true; | ||||
| 									if (breakdown[1].includes(guildInfo.treeName)) maybeMyTree = true; | ||||
| 
 | ||||
| 								rankings.push({ | ||||
| 									rank: trimmedRank, | ||||
| 									name: trimmedName, | ||||
| 									height: trimmedHeight, | ||||
| 									myTree: isMyTree, | ||||
| 									maybeMyTree: isMaybeMyTree | ||||
| 									// "entries": [ { "treeHeight": 12, "treeRank": 34, "treeName": "name" }, ] }
 | ||||
| 									 | ||||
| 									 | ||||
| 									leaderboard.entries.push({ | ||||
| 										treeRank: trimmedRank, | ||||
| 										treeName: trimmedName, | ||||
| 										treeHeight: trimmedHeight, | ||||
| 										hasPin: isMyTree | ||||
| 									}); | ||||
| 								} | ||||
| 			 | ||||
| 							guildInfo[interaction.guildId].rankings = rankings; | ||||
| 							fs.writeFileSync('./data/guildInfo.json', JSON.stringify(guildInfo)); | ||||
| 							guildInfo = require('../data/guildInfo.json'); | ||||
| 							resolve(rankings); | ||||
| 								dbfn.uploadLeaderboard(leaderboard).then(res => { | ||||
| 									console.log(res.status); | ||||
| 									resolve(res.status); | ||||
| 								}).catch(err => { | ||||
| 									console.error(err); | ||||
| 									reject(err); | ||||
| 									return; | ||||
| 								}); | ||||
| 							}); | ||||
| 						}); | ||||
| 					} else { | ||||
| 					reject("The rankMessageId is undefined somehow"); | ||||
| 						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)) { | ||||
| 			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'; | ||||
| 				guildInfo[interaction.guildId].rankings.forEach(treeRanking => { | ||||
| 					let difference = parseFloat(treeRanking.height).toFixed(1) - treeHeight; | ||||
| 					let decimal = (treeRanking.height % 1).toFixed(1); | ||||
| 						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.myTree) { | ||||
| 							if (treeRanking.hasPin) { | ||||
| 								replyString += "This is your tree. "; | ||||
| 					} else if (treeRanking.maybeMyTree) { | ||||
| 							} 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.rank} - ${absDifference}ft${growthIndicator} shorter `; | ||||
| 									replyString += `#${treeRanking.treeRank} - ${absDifference}ft${growthIndicator} shorter `; | ||||
| 								} else if (difference < 0) { | ||||
| 							replyString += `#${treeRanking.rank} - ${absDifference}ft${growthIndicator} taller `; | ||||
| 									replyString += `#${treeRanking.treeRank} - ${absDifference}ft${growthIndicator} taller `; | ||||
| 								} else if (difference == 0) { | ||||
| 							replyString += `#${treeRanking.rank} - Same Height${growthIndicator} `; | ||||
| 									replyString += `#${treeRanking.treeRank} - Same Height${growthIndicator} `; | ||||
| 								} | ||||
| 							} | ||||
| 					replyString += `[${functions.getWaterTime(treeRanking.height)} mins]\n`; | ||||
| 							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) { | ||||
| 				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[interaction.guildId].treeMessageId != "") { | ||||
| 					interaction.guild.channels.fetch(guildInfo[interaction.guildId].treeChannelId).then(c => { | ||||
| 						c.messages.fetch(guildInfo[interaction.guildId].treeMessageId).then(m => { | ||||
| 					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; | ||||
| @ -200,57 +234,69 @@ const functions = { | ||||
| 								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'); | ||||
| 								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; | ||||
| 				}); | ||||
| 			}); | ||||
| 		} | ||||
| 	}, | ||||
| 	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()) | ||||
| 				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 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)); | ||||
|  | ||||
| @ -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" | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| 			}); | ||||
| 		}) | ||||
| 	}, | ||||
| }; | ||||
| @ -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); | ||||
| 		}); | ||||
| 	}, | ||||
| }; | ||||
| @ -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)) { | ||||
| 				if (treeFound && !(leaderboardFound)) { | ||||
| 					dbfn.setTreeInfo(guildInfo).then(res => { | ||||
| 						interaction.editReply(fn.builders.embed(strings.status.treeNoLeaderboard)); | ||||
| 				} else if (!(treeFound) && rankFound) { | ||||
| 					}).catch(err => { | ||||
| 						console.error(err); | ||||
| 					}); | ||||
| 				} else if (!(treeFound) && leaderboardFound) { | ||||
| 					dbfn.setLeaderboardInfo(guildInfo).then(res => { | ||||
| 						interaction.editReply(fn.builders.embed(strings.status.leaderboardNoTree)); | ||||
| 				} else if (treeFound && rankFound) { | ||||
| 					}).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); | ||||
| 					}); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| @ -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); | ||||
| 		}); | ||||
| 	}, | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user