From bd2b17034de2e447a27309ac4d0142736592ab21 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Sun, 14 Jun 2026 12:20:16 -0600 Subject: [PATCH] Blegh --- index.js | 26 +++++++ interactions/chatCommand/getnumber.js | 9 ++- interactions/chatCommand/searchnumbers.js | 83 ++++++++++++----------- package-lock.json | 65 +++++++++++++++++- package.json | 3 +- 5 files changed, 142 insertions(+), 44 deletions(-) diff --git a/index.js b/index.js index 3c51b14..3982472 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,32 @@ const client = new Discord.Client({ const bvs = require("./bvs"); +const mariadb = require("mariadb"); +const pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + connectionLimit: 5 +}); + +global.db = { + pool, + query: async (query, params) => { + // Use a one time connection (or no connection at all) + let conn; + try { + conn = await pool.getConnection(); + const res = await conn.query(query, params); + return res; + } catch (error) { + console.error("Database query error:", error); + throw error; + } finally { + if (conn) conn.release(); + } + } +} const { REST, Routes } = require("discord.js"); const rest = new REST({ version: "10" }).setToken(process.env.DISCORD_TOKEN); diff --git a/interactions/chatCommand/getnumber.js b/interactions/chatCommand/getnumber.js index 6ff67bd..74b87b2 100644 --- a/interactions/chatCommand/getnumber.js +++ b/interactions/chatCommand/getnumber.js @@ -27,7 +27,14 @@ module.exports = (interaction, client, bvs) => { const didToPurchase = global.purchaseConfirmations[interaction.user.id]; delete global.purchaseConfirmations[interaction.user.id]; delete global.tempPurchasableDIDs[interaction.user.id]; - return interaction.reply({ content: `Purchasing DID \`${bvs.formatPhoneNumber(didToPurchase)}\`...`, ephemeral: true }) + interaction.deferReply({ ephemeral: true }).then(() => { + bvs.purchaseDID(didToPurchase, interaction.user.id).then(() => { + interaction.editReply({ content: `Successfully purchased DID \`${bvs.formatPhoneNumber(didToPurchase)}\`. It may take a few minutes for the purchase to fully process. If after 30 minutes the DID is not showing up in your account, please contact support.`, ephemeral: true }); + }).catch(error => { + console.error("Error purchasing DID:", error); + interaction.editReply({ content: `There was an error purchasing the DID. Please try again later.`, ephemeral: true }); + }); + }); // todo: impl actually buying did } else { delete global.purchaseConfirmations[interaction.user.id]; diff --git a/interactions/chatCommand/searchnumbers.js b/interactions/chatCommand/searchnumbers.js index 7396f3d..608c07e 100644 --- a/interactions/chatCommand/searchnumbers.js +++ b/interactions/chatCommand/searchnumbers.js @@ -9,47 +9,48 @@ module.exports = (interaction, client, bvs) => { if (!member.premiumSince) { return interaction.reply({ content: `You must be boosting the server to use this command.`, ephemeral: true }); } + interaction.deferReply({ ephemeral: true }).then(() => { + bvs.getPremiumDIDs().then(dids => { + const userDIDs = dids.filter(did => did.userId === interaction.user.id); + if (userDIDs.length === 0) { + const areaCode = interaction.options.getNumber('area_code'); + const officeCode = interaction.options.getNumber('office_code'); - bvs.getPremiumDIDs().then(dids => { - const userDIDs = dids.filter(did => did.userId === interaction.user.id); - if (userDIDs.length === 0) { - const areaCode = interaction.options.getNumber('area_code'); - const officeCode = interaction.options.getNumber('office_code'); - - // Clear purchase confirmation and temp purchasable DIDs for the user, since they're starting a new search. This prevents confusion where a user searches for DIDs, then tries to purchase one, but the purchasable DIDs from the previous search are still stored and they accidentally purchase a DID from the previous search results instead of the new ones. - if (global.purchaseConfirmations) { - delete global.purchaseConfirmations[interaction.user.id]; - } - if (global.tempPurchasableDIDs) { - delete global.tempPurchasableDIDs[interaction.user.id]; - } - - // Validate input - if (!/^\d{3}$/.test(areaCode)) { - return interaction.reply({ content: `Area code must be 3 digits.`, ephemeral: true }); - } - if (officeCode && !/^\d{3}$/.test(officeCode)) { - return interaction.reply({ content: `Office code must be 3 digits.`, ephemeral: true }); - } - bvs.searchPurchasableDIDs(`${areaCode}${officeCode || ""}`).then(dids => { - if (dids.length === 0) { - return interaction.reply({ content: `No results for search query. Try again.`, ephemeral: true }); + // Clear purchase confirmation and temp purchasable DIDs for the user, since they're starting a new search. This prevents confusion where a user searches for DIDs, then tries to purchase one, but the purchasable DIDs from the previous search are still stored and they accidentally purchase a DID from the previous search results instead of the new ones. + if (global.purchaseConfirmations) { + delete global.purchaseConfirmations[interaction.user.id]; } - // console.log(dids) - interaction.reply({ content: `Found the following DIDs\n\`\`\`\n${dids.map((did, index) => `${index + 1}. ${bvs.formatPhoneNumber(did.TN)}`).join("\n")}\n\`\`\`\nUse \`/getnumber \` to purchase one of these DIDs! (Choice is one of the numbers listed above by index, not phone number)`, ephemeral: true }); - // Store the DIDs in a global temp variable with the user id so the user can purchase by 1, 2, 3, etc. in the /getnumber command. This is a bit janky but it works for now. - global.tempPurchasableDIDs = global.tempPurchasableDIDs || {}; - global.tempPurchasableDIDs[interaction.user.id] = dids.map(did => did.TN); - // console.log(global.tempPurchasableDIDs) - }).catch(error => { - console.error("Error searching DIDs:", error); - interaction.reply({ content: `There was an error searching for DIDs. Please try again later.`, ephemeral: true }); - }); - } else { - interaction.reply({ content: `Your DID is \`${bvs.formatPhoneNumber(userDIDs[0].did)}\``, ephemeral: true }); - } - }).catch(error => { - console.error("Error fetching premium DIDs:", error); - interaction.reply({ content: `There was an error fetching your DID. Please try again later.`, ephemeral: true }); - }); + if (global.tempPurchasableDIDs) { + delete global.tempPurchasableDIDs[interaction.user.id]; + } + + // Validate input + if (!/^\d{3}$/.test(areaCode)) { + return interaction.editReply({ content: `Area code must be 3 digits.`, ephemeral: true }); + } + if (officeCode && !/^\d{3}$/.test(officeCode)) { + return interaction.editReply({ content: `Office code must be 3 digits.`, ephemeral: true }); + } + bvs.searchPurchasableDIDs(`${areaCode}${officeCode || ""}`).then(dids => { + if (dids.length === 0) { + return interaction.editReply({ content: `No results for search query. Try again.`, ephemeral: true }); + } + // console.log(dids) + interaction.editReply({ content: `Found the following DIDs\n\`\`\`\n${dids.map((did, index) => `${index + 1}. ${bvs.formatPhoneNumber(did.TN)}`).join("\n")}\n\`\`\`\nUse \`/getnumber \` to purchase one of these DIDs! (Choice is one of the numbers listed above by index, not phone number)`, ephemeral: true }); + // Store the DIDs in a global temp variable with the user id so the user can purchase by 1, 2, 3, etc. in the /getnumber command. This is a bit janky but it works for now. + global.tempPurchasableDIDs = global.tempPurchasableDIDs || {}; + global.tempPurchasableDIDs[interaction.user.id] = dids.map(did => did.TN); + // console.log(global.tempPurchasableDIDs) + }).catch(error => { + console.error("Error searching DIDs:", error); + interaction.editReply({ content: `There was an error searching for DIDs. Please try again later.`, ephemeral: true }); + }); + } else { + interaction.editReply({ content: `Your DID is \`${bvs.formatPhoneNumber(userDIDs[0].did)}\``, ephemeral: true }); + } + }).catch(error => { + console.error("Error fetching premium DIDs:", error); + interaction.editReply({ content: `There was an error fetching your DID. Please try again later.`, ephemeral: true }); + }); + }) } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 93947c1..4cf34ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "discord.js": "^14.26.4", - "dotenv": "^17.4.2" + "dotenv": "^17.4.2", + "mariadb": "^3.5.3" } }, "node_modules/@discordjs/builders": { @@ -186,6 +187,12 @@ "npm": ">=7.0.0" } }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "25.9.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", @@ -214,6 +221,15 @@ "npm": ">=7.0.0" } }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, "node_modules/discord-api-types": { "version": "0.38.48", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.48.tgz", @@ -268,6 +284,22 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/lodash": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", @@ -280,12 +312,43 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "license": "MIT" }, + "node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/magic-bytes.js": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.0.tgz", "integrity": "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==", "license": "MIT" }, + "node_modules/mariadb": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.5.3.tgz", + "integrity": "sha512-i053Kc0MgdUv/hu9mCyq67TYfPXFj3/MV8I7ZW5wvJNixIyXC0VztMPUjIVj/449nQo+BsxFD4Fdk/sA/uqKPQ==", + "license": "LGPL-2.1-or-later", + "dependencies": { + "@types/geojson": "^7946.0.16", + "@types/node": ">=20", + "denque": "^2.1.0", + "iconv-lite": "^0.7.2", + "lru-cache": "^11.5.0" + }, + "engines": { + "node": ">= 20.0.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", diff --git a/package.json b/package.json index e095c3f..6295b5b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "type": "commonjs", "dependencies": { "discord.js": "^14.26.4", - "dotenv": "^17.4.2" + "dotenv": "^17.4.2", + "mariadb": "^3.5.3" } }