From d0040c6c1fb04ed3c2ebb3e4ecbfdfb2f6c53d34 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:19:53 -0700 Subject: [PATCH 01/35] Add reset logic and command, to test --- commands.js | 5 ++ freepbx.js | 49 +++++++++++++------ index.js | 18 +++++++ interactionHandlers/commands/button.js | 7 +++ interactionHandlers/commands/reset.js | 3 ++ interactionHandlers/common/getExtInfo.js | 14 ++++++ .../common/resetPasswordDialog.js | 36 ++++++++++++++ .../components/resetPassword.js | 3 ++ .../modals/resetPasswordModal.js | 29 +++++++++++ package-lock.json | 10 +--- 10 files changed, 151 insertions(+), 23 deletions(-) create mode 100644 interactionHandlers/commands/reset.js create mode 100644 interactionHandlers/common/resetPasswordDialog.js create mode 100644 interactionHandlers/components/resetPassword.js create mode 100644 interactionHandlers/modals/resetPasswordModal.js diff --git a/commands.js b/commands.js index 605780f..60b0c99 100644 --- a/commands.js +++ b/commands.js @@ -303,5 +303,10 @@ module.exports = [ "type": 1 } ] + }, + { + "name": "reset", + "description": "Reset or change your extension password", // Opens a modal to reset password + "type": 1 } ] \ No newline at end of file diff --git a/freepbx.js b/freepbx.js index 4d79374..b4232bf 100644 --- a/freepbx.js +++ b/freepbx.js @@ -155,24 +155,45 @@ class FreepbxManager { return await this.pbxCall(query); } - // async updateName(ext, name) { - // const query = gql` - // mutation updateName($ext: ID!, $name: String!) { - // updateExtension(input: {extensionId: $ext, name: $name}) { - // status, - // message - // } - // }`; + async updateExtName(ext, name) { + const query = gql` + mutation updateExt($ext: ID!, $name: String, $password: String) { + updateExtension(input: { + extensionId: $ext + name: $name + }) { + status, + message + } + }`; - // const variables = { - // ext, - // name, - // }; + const variables = { + ext, + endName, + }; - // return await this.pbxCall(query, variables); - // } + return await this.pbxCall(query, variables); + } // TODO: Implement updateName method, Current implementation resets extension for some reason + async updateExtPassword(ext, password) { + const query = gql` + mutation updateExt($ext: ID!, $name: String, $password: String) { + updateExtension(input: { + extensionId: $ext + extPassword: $password + }) { + status, + message + } + }`; + const variables = { + ext, + password, + }; + return await this.pbxCall(query, variables); + } + async joinPageGroup(ext, pageGroup) { const [lookup] = await this.pool.query('SELECT * FROM paging_groups WHERE page_number = ? AND ext = ?', [pageGroup, ext]); if (lookup) { diff --git a/index.js b/index.js index 933d9ba..9cbfd22 100644 --- a/index.js +++ b/index.js @@ -138,6 +138,24 @@ client.on('interactionCreate', async interaction => { });; } break; + case Discord.InteractionType.ModalSubmit: + const modal = require(`./interactionHandlers/modals/${interaction.customId}`); + + if (!modal) return; + + try { + await modal.execute(interaction); + } catch (error) { + log.error(error); + await interaction.reply({ content: 'There was an error while executing this modal!', ephemeral: true }).catch((error) => { + log.error(`Failed to inform user of error: ${error}`); + }); + } + break; + default: { + log.warn(`Unknown interaction type received: ${interaction.type}`); + return; + } } }); diff --git a/interactionHandlers/commands/button.js b/interactionHandlers/commands/button.js index e8ff8f9..2d31949 100644 --- a/interactionHandlers/commands/button.js +++ b/interactionHandlers/commands/button.js @@ -94,6 +94,13 @@ module.exports.execute = async (interaction) => { emoji: "â„šī¸", style: Discord.ButtonStyle.Primary, custom_id: "getExtensionInfo" + }, + { + type: Discord.ComponentType.Button, + label: "Reset Password", + emoji: "🔄", + style: Discord.ButtonStyle.Danger, + custom_id: "resetPassword" } ] } diff --git a/interactionHandlers/commands/reset.js b/interactionHandlers/commands/reset.js new file mode 100644 index 0000000..7745feb --- /dev/null +++ b/interactionHandlers/commands/reset.js @@ -0,0 +1,3 @@ +module.exports = {}; + +module.exports.execute = require("../common/resetPasswordDialog").execute; \ No newline at end of file diff --git a/interactionHandlers/common/getExtInfo.js b/interactionHandlers/common/getExtInfo.js index c66f3af..f7c5604 100644 --- a/interactionHandlers/common/getExtInfo.js +++ b/interactionHandlers/common/getExtInfo.js @@ -20,6 +20,20 @@ module.exports.execute = async (interaction) => { description: `**PBX Address:** \`${process.env.PBX_HOSTNAME}\`\n**Extension/Username:** \`${extInfo.fetchExtension.user.extension}\`\n**Name:** \`${extInfo.fetchExtension.user.name}\`\n**Password:** ||\`${extInfo.fetchExtension.user.extPassword}\`||`, color: 0x00ff00 } + ], + components: [ + { + type: 1, + components: [ + { + type: Discord.ComponentType.Button, + label: "Reset Password", + emoji: "🔄", + style: Discord.ButtonStyle.Danger, + custom_id: "resetPassword" + } + ] + } ] }); diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js new file mode 100644 index 0000000..4ff327f --- /dev/null +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -0,0 +1,36 @@ +const pool = global.pool +const fpbx = global.fpbx +const client = global.client +const log = global.log + +module.exports = {}; + +module.exports.execute = async (interaction) => { + const [lookup] = await pool.query('SELECT * FROM discord_users WHERE discordId = ?', [interaction.user.id]); + if (!lookup) { + await interaction.reply({ content: `We're sorry, It doesn't look like you have an extension!`, ephemeral: true }); + return; + } + await interaction.deferReply({ ephemeral: true }); + interaction.showModal({ + title: 'Reset Extension Password', + customId: 'resetPasswordModal', + components: [ + { + type: 18, // Label + label: "Please enter a new password for your extension. Leave blank to generate a random one.", + compoents: [ + { + type: 4, // Text Input + id: 'newPassword', + style: 1, + min_length: 6, + max_length: 64, + placeholder: 'New Password', + required: false + } + ] + } + ] + }); +} \ No newline at end of file diff --git a/interactionHandlers/components/resetPassword.js b/interactionHandlers/components/resetPassword.js new file mode 100644 index 0000000..7745feb --- /dev/null +++ b/interactionHandlers/components/resetPassword.js @@ -0,0 +1,3 @@ +module.exports = {}; + +module.exports.execute = require("../common/resetPasswordDialog").execute; \ No newline at end of file diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js new file mode 100644 index 0000000..f709341 --- /dev/null +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -0,0 +1,29 @@ +const pool = global.pool +const fpbx = global.fpbx +const client = global.client +const log = global.log +module.exports = {}; + +module.exports.execute = async (interaction) => { + const [lookup] = await pool.query('SELECT * FROM discord_users WHERE discordId = ?', [interaction.user.id]); + if (!lookup) { + await interaction.reply({ content: `We're sorry, It doesn't look like you have an extension!`, ephemeral: true }); + return; + } + await interaction.deferReply({ ephemeral: true }); + const newPassword = interaction.fields.getTextInputValue('newPassword'); + let passwordToSet = newPassword; + if (!newPassword || newPassword.trim() === '') { + // Generate password based on process.env.PASSWORD_LENGTH and process.env.PASSWORD_CHARS or default to 32 alphanumeric with caps + const length = parseInt(process.env.PASSWORD_LENGTH) || 32; + const chars = process.env.PASSWORD_CHARS || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + passwordToSet = Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join(''); + } + try { + await fpbx.updateExtPassword(lookup.extension, passwordToSet); + await interaction.editReply({ content: `Your extension password has been reset successfully! Your new password is: ||\`${passwordToSet}\`||`, ephemeral: true }); + } catch (error) { + log.error(error); + await interaction.editReply({ content: 'There was an error while resetting your extension password!', ephemeral: true }); + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a7afd78..d828b7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -704,15 +704,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -851,6 +842,7 @@ "version": "15.8.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz", "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==", + "peer": true, "engines": { "node": ">= 10.x" } From 15411c974477caf32d60a9ae774db512fccdc359 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:49:08 -0700 Subject: [PATCH 02/35] Fix 1 --- interactionHandlers/common/resetPasswordDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 4ff327f..02a3f85 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -11,7 +11,6 @@ module.exports.execute = async (interaction) => { await interaction.reply({ content: `We're sorry, It doesn't look like you have an extension!`, ephemeral: true }); return; } - await interaction.deferReply({ ephemeral: true }); interaction.showModal({ title: 'Reset Extension Password', customId: 'resetPasswordModal', From 7c29db35e4f206c7caa7581d1fa4a0243da6fbed Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:49:47 -0700 Subject: [PATCH 03/35] Fix 2 --- interactionHandlers/common/resetPasswordDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 02a3f85..73fff50 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -17,7 +17,7 @@ module.exports.execute = async (interaction) => { components: [ { type: 18, // Label - label: "Please enter a new password for your extension. Leave blank to generate a random one.", + label: "New Password. Leave blank to generate a random one.", compoents: [ { type: 4, // Text Input From cdda6bb8bfeafe599354e4b4bd4ac96901b2c975 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:51:24 -0700 Subject: [PATCH 04/35] Fix 4 --- interactionHandlers/common/resetPasswordDialog.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 73fff50..17731e7 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -14,10 +14,11 @@ module.exports.execute = async (interaction) => { interaction.showModal({ title: 'Reset Extension Password', customId: 'resetPasswordModal', + label: 'Reset Extension Password', components: [ { type: 18, // Label - label: "New Password. Leave blank to generate a random one.", + label: "New Password. Leave blank for random.", compoents: [ { type: 4, // Text Input From 0abddc846b94d6015e14631678ba5bd4f3983dc1 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:54:32 -0700 Subject: [PATCH 05/35] Fix 5 --- interactionHandlers/common/resetPasswordDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 17731e7..37c5dfb 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -19,7 +19,7 @@ module.exports.execute = async (interaction) => { { type: 18, // Label label: "New Password. Leave blank for random.", - compoents: [ + components: [ { type: 4, // Text Input id: 'newPassword', From 1f0b14d326f867daa4ab8ad776b11d6280dc879b Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:55:57 -0700 Subject: [PATCH 06/35] Fix 6 --- .../common/resetPasswordDialog.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 37c5dfb..de71556 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -19,17 +19,15 @@ module.exports.execute = async (interaction) => { { type: 18, // Label label: "New Password. Leave blank for random.", - components: [ - { - type: 4, // Text Input - id: 'newPassword', - style: 1, - min_length: 6, - max_length: 64, - placeholder: 'New Password', - required: false - } - ] + component: { + type: 4, // Text Input + id: 'newPassword', + style: 1, + min_length: 6, + max_length: 64, + placeholder: 'New Password', + required: false + } } ] }); From 2c265e4eb666f87d67ec802bb1b30a5d56ccd8c9 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:56:24 -0700 Subject: [PATCH 07/35] Fix 7 --- interactionHandlers/common/resetPasswordDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index de71556..5f7e0e3 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -21,7 +21,7 @@ module.exports.execute = async (interaction) => { label: "New Password. Leave blank for random.", component: { type: 4, // Text Input - id: 'newPassword', + customId: 'newPassword', style: 1, min_length: 6, max_length: 64, From a36742d485cdb78bea6772cfb66da2ee47a2bb4f Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:57:58 -0700 Subject: [PATCH 08/35] Another Fix --- interactionHandlers/modals/resetPasswordModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index f709341..61d3b60 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -11,7 +11,7 @@ module.exports.execute = async (interaction) => { return; } await interaction.deferReply({ ephemeral: true }); - const newPassword = interaction.fields.getTextInputValue('newPassword'); + console.log(JSON.stringify(interaction, null, 2)); let passwordToSet = newPassword; if (!newPassword || newPassword.trim() === '') { // Generate password based on process.env.PASSWORD_LENGTH and process.env.PASSWORD_CHARS or default to 32 alphanumeric with caps From 5b56bcdb084d32bbced13e5fa9eb8b69bfa5ac95 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 08:58:57 -0700 Subject: [PATCH 09/35] Another Fix --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 9cbfd22..f749b64 100644 --- a/index.js +++ b/index.js @@ -139,6 +139,7 @@ client.on('interactionCreate', async interaction => { } break; case Discord.InteractionType.ModalSubmit: + console.log(JSON.stringify(interaction, null, 2)); const modal = require(`./interactionHandlers/modals/${interaction.customId}`); if (!modal) return; From 95e1c66570dc4a89782f1a5689b9b5ea3c644884 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:01:41 -0700 Subject: [PATCH 10/35] Another Fix --- interactionHandlers/common/resetPasswordDialog.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 5f7e0e3..b277cb9 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -17,6 +17,9 @@ module.exports.execute = async (interaction) => { label: 'Reset Extension Password', components: [ { + type: 1, // Action Row + components: [ + { type: 18, // Label label: "New Password. Leave blank for random.", component: { @@ -29,6 +32,8 @@ module.exports.execute = async (interaction) => { required: false } } + ] + } ] }); } \ No newline at end of file From 5a0c18e43437b90e3e00c93cc8dafdac613af40b Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:02:06 -0700 Subject: [PATCH 11/35] Another Fix --- .../common/resetPasswordDialog.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index b277cb9..63cf6d9 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -20,18 +20,18 @@ module.exports.execute = async (interaction) => { type: 1, // Action Row components: [ { - type: 18, // Label - label: "New Password. Leave blank for random.", - component: { - type: 4, // Text Input - customId: 'newPassword', - style: 1, - min_length: 6, - max_length: 64, - placeholder: 'New Password', - required: false - } - } + type: 18, // Label + label: "New Password. Leave blank for random.", + components: [ { + type: 4, // Text Input + customId: 'newPassword', + style: 1, + min_length: 6, + max_length: 64, + placeholder: 'New Password', + required: false + } ] + } ] } ] From 2e1ed82538fbee2f21f13a39237bfbb91d2323b2 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:02:30 -0700 Subject: [PATCH 12/35] Another Fix --- interactionHandlers/common/resetPasswordDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 63cf6d9..7676bf7 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -22,7 +22,7 @@ module.exports.execute = async (interaction) => { { type: 18, // Label label: "New Password. Leave blank for random.", - components: [ { + component: { type: 4, // Text Input customId: 'newPassword', style: 1, @@ -30,7 +30,7 @@ module.exports.execute = async (interaction) => { max_length: 64, placeholder: 'New Password', required: false - } ] + } } ] } From 948a28f1d6553f8bf258d1012e946fbae8bfac3e Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:02:54 -0700 Subject: [PATCH 13/35] Another Fix --- interactionHandlers/common/resetPasswordDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 7676bf7..310cbe7 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -17,7 +17,7 @@ module.exports.execute = async (interaction) => { label: 'Reset Extension Password', components: [ { - type: 1, // Action Row + type: 4, // Action Row components: [ { type: 18, // Label From 156f121fcc7d43089b4bb224e7239d4dce91c868 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:03:12 -0700 Subject: [PATCH 14/35] Another Fix --- interactionHandlers/common/resetPasswordDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 310cbe7..7676bf7 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -17,7 +17,7 @@ module.exports.execute = async (interaction) => { label: 'Reset Extension Password', components: [ { - type: 4, // Action Row + type: 1, // Action Row components: [ { type: 18, // Label From 465fef3ca8d58e810330c532ddab231da2232c0d Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:03:49 -0700 Subject: [PATCH 15/35] Another Fix --- interactionHandlers/common/resetPasswordDialog.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index 7676bf7..a19e473 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -19,10 +19,12 @@ module.exports.execute = async (interaction) => { { type: 1, // Action Row components: [ + // { + // type: 18, // Label + // label: "New Password. Leave blank for random.", + // component: + // } { - type: 18, // Label - label: "New Password. Leave blank for random.", - component: { type: 4, // Text Input customId: 'newPassword', style: 1, @@ -31,7 +33,6 @@ module.exports.execute = async (interaction) => { placeholder: 'New Password', required: false } - } ] } ] From 50015218a68964c6c57bde6b2dc03fa3ea801068 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:04:17 -0700 Subject: [PATCH 16/35] Another Fix --- .../common/resetPasswordDialog.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/interactionHandlers/common/resetPasswordDialog.js b/interactionHandlers/common/resetPasswordDialog.js index a19e473..f67d9a8 100644 --- a/interactionHandlers/common/resetPasswordDialog.js +++ b/interactionHandlers/common/resetPasswordDialog.js @@ -21,18 +21,19 @@ module.exports.execute = async (interaction) => { components: [ // { // type: 18, // Label - // label: "New Password. Leave blank for random.", + // , // component: // } { - type: 4, // Text Input - customId: 'newPassword', - style: 1, - min_length: 6, - max_length: 64, - placeholder: 'New Password', - required: false - } + type: 4, // Text Input + customId: 'newPassword', + label: "New Password. Leave blank for random.", + style: 1, + min_length: 6, + max_length: 64, + placeholder: 'New Password', + required: false + } ] } ] From a0bb249ebcfc406bb27607130cf58fddde1a0c40 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:04:51 -0700 Subject: [PATCH 17/35] Another Fix --- index.js | 4 +++- interactionHandlers/modals/resetPasswordModal.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index f749b64..01b1176 100644 --- a/index.js +++ b/index.js @@ -139,7 +139,9 @@ client.on('interactionCreate', async interaction => { } break; case Discord.InteractionType.ModalSubmit: - console.log(JSON.stringify(interaction, null, 2)); + console.log(JSON.stringify(interaction, null, 2, (key, value) => + typeof value === 'bigint' ? value.toString() : value + )); const modal = require(`./interactionHandlers/modals/${interaction.customId}`); if (!modal) return; diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index 61d3b60..9877de9 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -11,7 +11,7 @@ module.exports.execute = async (interaction) => { return; } await interaction.deferReply({ ephemeral: true }); - console.log(JSON.stringify(interaction, null, 2)); + // console.log(JSON.stringify(interaction, null, 2)); let passwordToSet = newPassword; if (!newPassword || newPassword.trim() === '') { // Generate password based on process.env.PASSWORD_LENGTH and process.env.PASSWORD_CHARS or default to 32 alphanumeric with caps From a954c845cf83a794009e2875e5719de874bed931 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:05:17 -0700 Subject: [PATCH 18/35] Another Fix --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 01b1176..931ac50 100644 --- a/index.js +++ b/index.js @@ -140,7 +140,7 @@ client.on('interactionCreate', async interaction => { break; case Discord.InteractionType.ModalSubmit: console.log(JSON.stringify(interaction, null, 2, (key, value) => - typeof value === 'bigint' ? value.toString() : value + typeof value === 'BigInt' ? value.toString() : value )); const modal = require(`./interactionHandlers/modals/${interaction.customId}`); From 83de989e978f62d2f5208607bc6602e31a5c7bc1 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:05:57 -0700 Subject: [PATCH 19/35] Another Fix --- index.js | 3 --- interactionHandlers/modals/resetPasswordModal.js | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/index.js b/index.js index 931ac50..9cbfd22 100644 --- a/index.js +++ b/index.js @@ -139,9 +139,6 @@ client.on('interactionCreate', async interaction => { } break; case Discord.InteractionType.ModalSubmit: - console.log(JSON.stringify(interaction, null, 2, (key, value) => - typeof value === 'BigInt' ? value.toString() : value - )); const modal = require(`./interactionHandlers/modals/${interaction.customId}`); if (!modal) return; diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index 9877de9..e85954a 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -12,6 +12,7 @@ module.exports.execute = async (interaction) => { } await interaction.deferReply({ ephemeral: true }); // console.log(JSON.stringify(interaction, null, 2)); + const newPassword = interaction.fields.getTextInputValue('newPassword'); let passwordToSet = newPassword; if (!newPassword || newPassword.trim() === '') { // Generate password based on process.env.PASSWORD_LENGTH and process.env.PASSWORD_CHARS or default to 32 alphanumeric with caps From 0a38ac60358594118eda04090e4bab4c4b83cf75 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Thu, 13 Nov 2025 09:07:04 -0700 Subject: [PATCH 20/35] Another Fix --- interactionHandlers/modals/resetPasswordModal.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index e85954a..7a33eab 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -10,6 +10,8 @@ module.exports.execute = async (interaction) => { await interaction.reply({ content: `We're sorry, It doesn't look like you have an extension!`, ephemeral: true }); return; } + const extData = await fpbx.getExtension(lookup.extension); // Verify extension exists + console.log(extData) await interaction.deferReply({ ephemeral: true }); // console.log(JSON.stringify(interaction, null, 2)); const newPassword = interaction.fields.getTextInputValue('newPassword'); From a1728d80111916d825dacfd9be332fb17f07ec07 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:08:57 -0700 Subject: [PATCH 21/35] Another Fix --- freepbx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freepbx.js b/freepbx.js index b4232bf..ca4a7a4 100644 --- a/freepbx.js +++ b/freepbx.js @@ -182,6 +182,7 @@ class FreepbxManager { updateExtension(input: { extensionId: $ext extPassword: $password + name: $name }) { status, message @@ -229,7 +230,6 @@ class FreepbxManager { } nextExt++; } - return nextExt; } } From a0e96f50c236936347193663444ecb4c9ec4540b Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:09:49 -0700 Subject: [PATCH 22/35] Another Fix --- interactionHandlers/common/getExtInfo.js | 1 + 1 file changed, 1 insertion(+) diff --git a/interactionHandlers/common/getExtInfo.js b/interactionHandlers/common/getExtInfo.js index f7c5604..8420ccc 100644 --- a/interactionHandlers/common/getExtInfo.js +++ b/interactionHandlers/common/getExtInfo.js @@ -2,6 +2,7 @@ const pool = global.pool const fpbx = global.fpbx const client = global.client const log = global.log +const Discord = require('discord.js'); module.exports = {}; From e65297dcdf345bbb90c6ed74bb6b3a5e1e58f7af Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:11:29 -0700 Subject: [PATCH 23/35] Another Fix --- interactionHandlers/modals/resetPasswordModal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index 7a33eab..3a4ac1a 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -23,7 +23,8 @@ module.exports.execute = async (interaction) => { passwordToSet = Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join(''); } try { - await fpbx.updateExtPassword(lookup.extension, passwordToSet); + const updated = await fpbx.updateExtPassword(lookup.extension, passwordToSet); + console.log(updated) await interaction.editReply({ content: `Your extension password has been reset successfully! Your new password is: ||\`${passwordToSet}\`||`, ephemeral: true }); } catch (error) { log.error(error); From 976bcf2672552a9a4a2e9d21f330d43a3dcec5a1 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:13:59 -0700 Subject: [PATCH 24/35] Another Fix --- interactionHandlers/modals/resetPasswordModal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index 3a4ac1a..835d05d 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -23,7 +23,8 @@ module.exports.execute = async (interaction) => { passwordToSet = Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join(''); } try { - const updated = await fpbx.updateExtPassword(lookup.extension, passwordToSet); + //const updated = await fpbx.updateExtPassword(lookup.extension, passwordToSet); + const updated = await fpbx.updateExtName(lookup.extension, passwordToSet); console.log(updated) await interaction.editReply({ content: `Your extension password has been reset successfully! Your new password is: ||\`${passwordToSet}\`||`, ephemeral: true }); } catch (error) { From 10f0c147344f89ea596e0e738ff487eedeba231b Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:14:27 -0700 Subject: [PATCH 25/35] Another Fix --- freepbx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freepbx.js b/freepbx.js index ca4a7a4..38bdabd 100644 --- a/freepbx.js +++ b/freepbx.js @@ -169,7 +169,7 @@ class FreepbxManager { const variables = { ext, - endName, + name, }; return await this.pbxCall(query, variables); From 96f0d8b8dfcd823c60b9d2ea8bf25a883cd67dbf Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:14:52 -0700 Subject: [PATCH 26/35] Another Fix --- freepbx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freepbx.js b/freepbx.js index 38bdabd..b11da03 100644 --- a/freepbx.js +++ b/freepbx.js @@ -157,7 +157,7 @@ class FreepbxManager { async updateExtName(ext, name) { const query = gql` - mutation updateExt($ext: ID!, $name: String, $password: String) { + mutation updateExt($ext: ID!, $name: String) { updateExtension(input: { extensionId: $ext name: $name From 55515da30d186f7df07f8ca5050f66ac2a0e587c Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:18:06 -0700 Subject: [PATCH 27/35] Another Fix --- freepbx.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freepbx.js b/freepbx.js index b11da03..6186179 100644 --- a/freepbx.js +++ b/freepbx.js @@ -159,8 +159,8 @@ class FreepbxManager { const query = gql` mutation updateExt($ext: ID!, $name: String) { updateExtension(input: { - extensionId: $ext name: $name + extensionId: $ext }) { status, message @@ -180,9 +180,9 @@ class FreepbxManager { const query = gql` mutation updateExt($ext: ID!, $name: String, $password: String) { updateExtension(input: { + name: $name extensionId: $ext extPassword: $password - name: $name }) { status, message From cdaf08b449760ea268afee63f4d6db12b5b89bb8 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:19:39 -0700 Subject: [PATCH 28/35] Another Fix --- freepbx.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freepbx.js b/freepbx.js index 6186179..73cf5d9 100644 --- a/freepbx.js +++ b/freepbx.js @@ -168,8 +168,8 @@ class FreepbxManager { }`; const variables = { - ext, name, + ext }; return await this.pbxCall(query, variables); @@ -180,7 +180,7 @@ class FreepbxManager { const query = gql` mutation updateExt($ext: ID!, $name: String, $password: String) { updateExtension(input: { - name: $name + name: test extensionId: $ext extPassword: $password }) { @@ -190,7 +190,7 @@ class FreepbxManager { }`; const variables = { ext, - password, + password }; return await this.pbxCall(query, variables); } From 218d9205c44693ebcf7ce79c0835b29e61cb84ee Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 18 Nov 2025 12:20:56 -0700 Subject: [PATCH 29/35] Another Fix --- freepbx.js | 7 ++++--- interactionHandlers/modals/resetPasswordModal.js | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/freepbx.js b/freepbx.js index 73cf5d9..1dd6c2d 100644 --- a/freepbx.js +++ b/freepbx.js @@ -176,11 +176,11 @@ class FreepbxManager { } // TODO: Implement updateName method, Current implementation resets extension for some reason - async updateExtPassword(ext, password) { + async updateExtPassword(ext, oldName, password) { const query = gql` mutation updateExt($ext: ID!, $name: String, $password: String) { updateExtension(input: { - name: test + name: $name extensionId: $ext extPassword: $password }) { @@ -190,7 +190,8 @@ class FreepbxManager { }`; const variables = { ext, - password + password, + name: oldName }; return await this.pbxCall(query, variables); } diff --git a/interactionHandlers/modals/resetPasswordModal.js b/interactionHandlers/modals/resetPasswordModal.js index 835d05d..7e6ea1d 100644 --- a/interactionHandlers/modals/resetPasswordModal.js +++ b/interactionHandlers/modals/resetPasswordModal.js @@ -16,6 +16,7 @@ module.exports.execute = async (interaction) => { // console.log(JSON.stringify(interaction, null, 2)); const newPassword = interaction.fields.getTextInputValue('newPassword'); let passwordToSet = newPassword; + let oldName = extData.fetchExtension.user.name; if (!newPassword || newPassword.trim() === '') { // Generate password based on process.env.PASSWORD_LENGTH and process.env.PASSWORD_CHARS or default to 32 alphanumeric with caps const length = parseInt(process.env.PASSWORD_LENGTH) || 32; @@ -23,8 +24,8 @@ module.exports.execute = async (interaction) => { passwordToSet = Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join(''); } try { - //const updated = await fpbx.updateExtPassword(lookup.extension, passwordToSet); - const updated = await fpbx.updateExtName(lookup.extension, passwordToSet); + const updated = await fpbx.updateExtPassword(lookup.extension, oldName, passwordToSet); + //const updated = await fpbx.updateExtName(lookup.extension, passwordToSet); console.log(updated) await interaction.editReply({ content: `Your extension password has been reset successfully! Your new password is: ||\`${passwordToSet}\`||`, ephemeral: true }); } catch (error) { From c49f043537d4b712ba8ebb7419b45c013f1d4540 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Fri, 21 Nov 2025 21:50:13 -0700 Subject: [PATCH 30/35] Another Fix --- freepbx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freepbx.js b/freepbx.js index 1dd6c2d..2caf0e7 100644 --- a/freepbx.js +++ b/freepbx.js @@ -108,7 +108,7 @@ class FreepbxManager { vmPassword: $vmPassword email: "" maxContacts: "100" - umEnable: false + umEnable: true }) { status } From 823a501869aca326380d5545e3b3a0711027e7c3 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Fri, 21 Nov 2025 21:51:20 -0700 Subject: [PATCH 31/35] Another Fix --- freepbx.js | 1 - 1 file changed, 1 deletion(-) diff --git a/freepbx.js b/freepbx.js index 2caf0e7..229760c 100644 --- a/freepbx.js +++ b/freepbx.js @@ -108,7 +108,6 @@ class FreepbxManager { vmPassword: $vmPassword email: "" maxContacts: "100" - umEnable: true }) { status } From 9a5b02f0f88c333ba0b53fe7f9c18c4e2c98a175 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Fri, 21 Nov 2025 22:19:27 -0700 Subject: [PATCH 32/35] Another Fix --- freepbx.js | 1 + 1 file changed, 1 insertion(+) diff --git a/freepbx.js b/freepbx.js index 229760c..1dd6c2d 100644 --- a/freepbx.js +++ b/freepbx.js @@ -108,6 +108,7 @@ class FreepbxManager { vmPassword: $vmPassword email: "" maxContacts: "100" + umEnable: false }) { status } From b92736997fc161bdff2a7495d19debb1eebd49ad Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Fri, 21 Nov 2025 22:20:18 -0700 Subject: [PATCH 33/35] Another Fix --- freepbx.js | 1 - 1 file changed, 1 deletion(-) diff --git a/freepbx.js b/freepbx.js index 1dd6c2d..229760c 100644 --- a/freepbx.js +++ b/freepbx.js @@ -108,7 +108,6 @@ class FreepbxManager { vmPassword: $vmPassword email: "" maxContacts: "100" - umEnable: false }) { status } From 37743b593b4811a23835ba15390b2015b49c68b0 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Fri, 21 Nov 2025 22:27:46 -0700 Subject: [PATCH 34/35] Another Fix --- interactionHandlers/commands/button.js | 97 ++++++++++++++++--------- interactionHandlers/common/createExt.js | 29 ++++++-- migrations/003_fuck_freepbx_gql.sql | 10 +++ 3 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 migrations/003_fuck_freepbx_gql.sql diff --git a/interactionHandlers/commands/button.js b/interactionHandlers/commands/button.js index 2d31949..bc9b171 100644 --- a/interactionHandlers/commands/button.js +++ b/interactionHandlers/commands/button.js @@ -44,39 +44,7 @@ module.exports = {}; module.exports.execute = async (interaction) => { interaction.channel.send({ - embeds: [{ - "title": "The LiteNet Community PBX", - "description": "The LiteNet Community PBX is hosted through, and is sponsored by Snakecraft Hosting!\nOffering affordable game hosting, Discord bot hosting, and VPS services since 2020.\nGet started at https://go.litenet.tel/sch-affiliate\nCheck them out on [Discord](https://discord.gg/nZFQTaZWqT)\n\n-# The link above is an affiliate link. We will receive credits from any purchase made via this link.\n-# Snakecraft Hosting has no administrative control over, nor has access to private information stored on LiteNet. Snakecraft Hosting provides hosting for LiteNet free of charge. Specific details regarding their affiliate program can be found [here](https://my.snakecrafthosting.com/index.php?rp=/knowledgebase/4/Affiliate-Program-FAQs.html)", - "color": 7955428, - "fields": [ - { - "name": "What's this?", - "value": "The community PBX is a public, free to use [FreePBX](https://freepbx.org) based phone system that any server member is welcome to get a number on!\nEveryone on the system has their own 4 digit number, that can be used to call between other members on the system.\nThe PBX runs on a Snakecraft Hosting VPS graciously provided to us at no cost!" - }, - { - "name": "What can it do?", - "value": "The LiteNet phone system offers many features, including but not limited to the following:\n- Free inbound/outbound calling via +1 (610) LITENET (548-3638)\n- Private Voicemail\n- Intercom/Paging\n- Conference Rooms\n- Direct dial access to [AstroCom](https://astrocom.tel)\n- [Full extension status page](https://pbx.litenet.tel/status)\n- And more!" - }, - { - "name": "Privacy Policy", - "value": "LiteNet respects the privacy of all members, and as such, only very few select staff members have access to the system files directly. Voicemails are not tracked nor listened to under any circumstances. Call logs are kept and only reviewed during investigations into violations of community guidelines, or possible illegal activity. Call recordings may be kept at the request of any individual member, and will NOT be reviewed unless prior permission was given from said member.\nAll user data may be deleted by request, or by simply running the `/delete` command.\n\nIf you believe your privacy has been violated in any way, please don't hesistate to reach out to any of our staff members!" - }, - { - "name": "Can it do `X`?", - "value": "Any specific questions are welcome to be asked in our <#1102782499756724239> chat!\nIf you have a suggestion for something we should add to the PBX or Discord server, feel free to leave it in <#1148099609428762634>!" - } - ], - "footer": { - "text": "Made with <3 by Chris Chrome & The LiteNet Team â€ĸ Sponsored by Snakecraft Hosting", - "icon_url": "https://f.chrischro.me/assets/Snakecraft-Social-Media-purple-v2-smaller.png" - }, - "image": { - "url": "https://f.chrischro.me/assets/litenet-full.png" - }, - "thumbnail": { - "url": "https://f.chrischro.me/assets/Snakecraft-Social-Media-purple-v2-smaller-rounder.png" - } - }], + embeds: [{ "title": "The LiteNet Community PBX", "description": "The LiteNet Community PBX is hosted through, and is sponsored by RackGenius!\nOffering affordable game hosting, Discord bot hosting, and VPS services since 2020.\nGet started at https://go.litenet.tel/affiliate\nCheck them out on [Discord](https://discord.gg/nZFQTaZWqT)\n\n-# The link above is an affiliate link. We will receive credits from any purchase made via this link.\n-# RackGenius has no administrative control over, nor has access to private information stored on LiteNet. RackGenius provides hosting for LiteNet free of charge. Specific details regarding their affiliate program can be found [here](https://my.rackgenius.com/index.php?rp=/knowledgebase/4/Affiliate-Program-FAQs.html)", "footer": { "text": "Made with <3 by Chris Chrome & The LiteNet Team â€ĸ Sponsored by RackGenius", "iconURL": "https://dingus.chrischro.me/raw/bfafda4c-9a2f-4f1e-8e78-fec2df7836f3.png" }, "timestamp": "2025-05-26T04:26:03.819Z", "thumbnail": { "url": "https://dingus.chrischro.me/raw/bfafda4c-9a2f-4f1e-8e78-fec2df7836f3.png" }, "image": { "url": "https://dingus.chrischro.me/raw/54d12d28-6a88-46b8-a95e-dc8c1f346cd6.png" }, "fields": [{ "name": "What's this?", "value": "The community PBX is a public, free to use [FreePBX](https://freepbx.org) based phone system that any server member is welcome to get a number on!\nEveryone on the system has their own 4 digit number, that can be used to call between other members on the system.\nThe PBX runs on a RackGenius VPS graciously provided to us at no cost!", "inline": false }, { "name": "What can it do?", "value": "The LiteNet phone system offers many features, including but not limited to the following:\n- Free inbound/outbound calling via +1 (610) LITENET (548-3638)\n- Private Voicemail\n- Intercom/Paging\n- Conference Rooms\n- Direct dial access to [AstroCom](https://astrocom.tel)\n- [Full extension status page](https://pbx.litenet.tel/status)\n- And more!", "inline": false }, { "name": "Privacy Policy", "value": "LiteNet respects the privacy of all members, and as such, only very few select staff members have access to the system files directly. Voicemails are not tracked nor listened to under any circumstances. Call logs are kept and only reviewed during investigations into violations of community guidelines, or possible illegal activity. Call recordings may be kept at the request of any individual member, and will NOT be reviewed unless prior permission was given from said member.\nAll user data may be deleted by request, or by simply running the `/delete` command.\n\nIf you believe your privacy has been violated in any way, please don't hesistate to reach out to any of our staff members!", "inline": false }, { "name": "Call Recording Notice", "value": "Due to repeated issues with prank and spam calling in the past via the PSTN, all inbound and outbound calls are recorded. Recordings are retained for seven (7) days from the end of the call. If you have any questions, please reach out via a support ticket!", "inline": false }, { "name": "Can it do `X`?", "value": "Any specific questions are welcome to be asked in our <#1102782499756724239> chat!\nIf you have a suggestion for something we should add to the PBX or Discord server, feel free to leave it in <#1148099609428762634>!", "inline": false }] }], components: [ { type: 1, @@ -106,4 +74,67 @@ module.exports.execute = async (interaction) => { } ] }) + // interaction.channel.send({ // Old embed before sponsorship change + // embeds: [{ + // "title": "The LiteNet Community PBX", + // "description": "The LiteNet Community PBX is hosted through, and is sponsored by Snakecraft Hosting!\nOffering affordable game hosting, Discord bot hosting, and VPS services since 2020.\nGet started at https://go.litenet.tel/sch-affiliate\nCheck them out on [Discord](https://discord.gg/nZFQTaZWqT)\n\n-# The link above is an affiliate link. We will receive credits from any purchase made via this link.\n-# Snakecraft Hosting has no administrative control over, nor has access to private information stored on LiteNet. Snakecraft Hosting provides hosting for LiteNet free of charge. Specific details regarding their affiliate program can be found [here](https://my.snakecrafthosting.com/index.php?rp=/knowledgebase/4/Affiliate-Program-FAQs.html)", + // "color": 7955428, + // "fields": [ + // { + // "name": "What's this?", + // "value": "The community PBX is a public, free to use [FreePBX](https://freepbx.org) based phone system that any server member is welcome to get a number on!\nEveryone on the system has their own 4 digit number, that can be used to call between other members on the system.\nThe PBX runs on a Snakecraft Hosting VPS graciously provided to us at no cost!" + // }, + // { + // "name": "What can it do?", + // "value": "The LiteNet phone system offers many features, including but not limited to the following:\n- Free inbound/outbound calling via +1 (610) LITENET (548-3638)\n- Private Voicemail\n- Intercom/Paging\n- Conference Rooms\n- Direct dial access to [AstroCom](https://astrocom.tel)\n- [Full extension status page](https://pbx.litenet.tel/status)\n- And more!" + // }, + // { + // "name": "Privacy Policy", + // "value": "LiteNet respects the privacy of all members, and as such, only very few select staff members have access to the system files directly. Voicemails are not tracked nor listened to under any circumstances. Call logs are kept and only reviewed during investigations into violations of community guidelines, or possible illegal activity. Call recordings may be kept at the request of any individual member, and will NOT be reviewed unless prior permission was given from said member.\nAll user data may be deleted by request, or by simply running the `/delete` command.\n\nIf you believe your privacy has been violated in any way, please don't hesistate to reach out to any of our staff members!" + // }, + // { + // "name": "Can it do `X`?", + // "value": "Any specific questions are welcome to be asked in our <#1102782499756724239> chat!\nIf you have a suggestion for something we should add to the PBX or Discord server, feel free to leave it in <#1148099609428762634>!" + // } + // ], + // "footer": { + // "text": "Made with <3 by Chris Chrome & The LiteNet Team â€ĸ Sponsored by Snakecraft Hosting", + // "icon_url": "https://f.chrischro.me/assets/Snakecraft-Social-Media-purple-v2-smaller.png" + // }, + // "image": { + // "url": "https://f.chrischro.me/assets/litenet-full.png" + // }, + // "thumbnail": { + // "url": "https://f.chrischro.me/assets/Snakecraft-Social-Media-purple-v2-smaller-rounder.png" + // } + // }], + // components: [ + // { + // type: 1, + // components: [ + // { + // type: Discord.ComponentType.Button, + // label: "Get an Extension", + // emoji: "✅", + // style: Discord.ButtonStyle.Success, + // custom_id: "newExtension" + // }, + // { + // type: Discord.ComponentType.Button, + // label: "Get your extension info", + // emoji: "â„šī¸", + // style: Discord.ButtonStyle.Primary, + // custom_id: "getExtensionInfo" + // }, + // { + // type: Discord.ComponentType.Button, + // label: "Reset Password", + // emoji: "🔄", + // style: Discord.ButtonStyle.Danger, + // custom_id: "resetPassword" + // } + // ] + // } + // ] + // }) } \ No newline at end of file diff --git a/interactionHandlers/common/createExt.js b/interactionHandlers/common/createExt.js index 99df27b..969fa71 100644 --- a/interactionHandlers/common/createExt.js +++ b/interactionHandlers/common/createExt.js @@ -14,7 +14,7 @@ module.exports.execute = async (interaction) => { } await interaction.editReply({ content: `Finding available extension`, ephemeral: true }); fpbx.getNextAvailableExtension().then(async (nextExt) => { - await interaction.editReply({ content: `Found ${nextExt}. Creating..`, ephemeral: true }); + await interaction.editReply({ content: `Found ${nextExt}. Creating..`, ephemeral: true }); fpbx.addExtension(nextExt, interaction.user.username).then(async (res) => { if (res.addExtension.status != true) { await interaction.editReply({ content: `Something went wrong :(`, ephemeral: true }); @@ -24,11 +24,28 @@ module.exports.execute = async (interaction) => { await interaction.editReply({ content: `Extension ${nextExt} created! Getting info..`, ephemeral: true }); await fpbx.reload(); const extInfo = await fpbx.getExtension(nextExt); - await interaction.editReply({ embeds: [{ - title: "Your Extension Info", - description: `**PBX Address:** \`${process.env.PBX_HOSTNAME}\`\n**Extension:** \`${extInfo.fetchExtension.user.extension}\`\n**Name:** \`${extInfo.fetchExtension.user.name}\`\n**Password:** ||\`${extInfo.fetchExtension.user.extPassword}\`||`, - color: 0x00ff00 - }], ephemeral: true }) + await interaction.editReply({ + embeds: [{ + title: "Your Extension Info", + description: `**PBX Address:** \`${process.env.PBX_HOSTNAME}\`\n**Extension:** \`${extInfo.fetchExtension.user.extension}\`\n**Name:** \`${extInfo.fetchExtension.user.name}\`\n**Password:** ||\`${extInfo.fetchExtension.user.extPassword}\`||`, + color: 0x00ff00 + }], + components: [ + { + type: 1, + components: [ + { + type: Discord.ComponentType.Button, + label: "Reset Password", + emoji: "🔄", + style: Discord.ButtonStyle.Danger, + custom_id: "resetPassword" + } + ] + } + ], + ephemeral: true + }) if (process.env.EXTENSION_ROLE_ID) await interaction.member.roles.add(process.env.EXTENSION_ROLE_ID); }).catch(async (error) => { log.error(error); diff --git a/migrations/003_fuck_freepbx_gql.sql b/migrations/003_fuck_freepbx_gql.sql new file mode 100644 index 0000000..7f855bc --- /dev/null +++ b/migrations/003_fuck_freepbx_gql.sql @@ -0,0 +1,10 @@ +INSERT INTO userman_users (username, auth) +SELECT du.extension, '1' +FROM discord_users du +LEFT JOIN userman_users uu + ON uu.username = du.extension +WHERE uu.username IS NULL; + +-- Some context for those wondering why this is here. +-- FreePBX's GraphQL API, for some reason, REQUIRES a userman user to exist for each extension before it'll allow you to update the name or password via GraphQL. +-- Fuck FreePBX GQL. \ No newline at end of file From 3c0f3cd2a74588f56abea22468f4bfa58d9f9335 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Fri, 21 Nov 2025 22:30:11 -0700 Subject: [PATCH 35/35] Another Fix --- interactionHandlers/commands/button.js | 36 -------------------------- migrations/003_fuck_freepbx_gql.sql | 5 ++-- 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/interactionHandlers/commands/button.js b/interactionHandlers/commands/button.js index bc9b171..1de4475 100644 --- a/interactionHandlers/commands/button.js +++ b/interactionHandlers/commands/button.js @@ -6,42 +6,6 @@ const Discord = require("discord.js") module.exports = {}; -/* Holding for upcoming sponsorship embed -{ - "title": "The LiteNet Community PBX", - "description": "The LiteNet Community PBX is hosted through, and is sponsored by Snakecraft Hosting!\nOffering affordable game hosting, Discord bot hosting, and VPS services since 2020.\nGet started at https://go.litenet.tel/sch-affiliate\nCheck them out on [Discord](https://discord.gg/nZFQTaZWqT)\n\n-# The link above is an affiliate link. We will receive credits from any purchase made via this link.\n-# Snakecraft Hosting has no administrative control over, nor has access to private information stored on LiteNet. Snakecraft Hosting provides hosting for LiteNet free of charge. Specific details regarding their affiliate program can be found [here](https://my.snakecrafthosting.com/index.php?rp=/knowledgebase/4/Affiliate-Program-FAQs.html)", - "color": 7955428, - "fields": [ - { - "name": "What's this?", - "value": "The community PBX is a public, free to use [FreePBX](https://freepbx.org) based phone system that any server member is welcome to get a number on!\nEveryone on the system has their own 4 digit number, that can be used to call between other members on the system.\nThe PBX runs on a Snakecraft Hosting VPS graciously provided to us at no cost!" - }, - { - "name": "What can it do?", - "value": "The LiteNet phone system offers many features, including but not limited to the following:\n- Free inbound/outbound calling via +1 (610) LITENET (548-3638)\n- Private Voicemail\n- Intercom/Paging\n- Conference Rooms\n- Direct dial access to [AstroCom](https://astrocom.tel)\n- [Full extension status page](https://pbx.litenet.tel/status)\n- And more!" - }, - { - "name": "Privacy Policy", - "value": "LiteNet respects the privacy of all members, and as such, only very few select staff members have access to the system files directly. Voicemails are not tracked nor listened to under any circumstances. Call logs are kept and only reviewed during investigations into violations of community guidelines, or possible illegal activity. Call recordings may be kept at the request of any individual member, and will NOT be reviewed unless prior permission was given from said member.\nAll user data may be deleted by request, or by simply running the `/delete` command.\n\nIf you believe your privacy has been violated in any way, please don't hesistate to reach out to any of our staff members!" - }, - { - "name": "Can it do `X`?", - "value": "Any specific questions are welcome to be asked in our <#1102782499756724239> chat!\nIf you have a suggestion for something we should add to the PBX or Discord server, feel free to leave it in <#1148099609428762634>!" - } - ], - "footer": { - "text": "Made with <3 by Chris Chrome & The LiteNet Team â€ĸ Sponsored by Snakecraft Hosting", - "icon_url": "https://f.chrischro.me/assets/Snakecraft-Social-Media-purple-v2-smaller.png" - }, - "image": { - "url": "https://f.chrischro.me/assets/litenet-full.png" - }, - "thumbnail": { - "url": "https://f.chrischro.me/assets/Snakecraft-Social-Media-purple-v2-smaller-rounder.png" - } - } -*/ - module.exports.execute = async (interaction) => { interaction.channel.send({ embeds: [{ "title": "The LiteNet Community PBX", "description": "The LiteNet Community PBX is hosted through, and is sponsored by RackGenius!\nOffering affordable game hosting, Discord bot hosting, and VPS services since 2020.\nGet started at https://go.litenet.tel/affiliate\nCheck them out on [Discord](https://discord.gg/nZFQTaZWqT)\n\n-# The link above is an affiliate link. We will receive credits from any purchase made via this link.\n-# RackGenius has no administrative control over, nor has access to private information stored on LiteNet. RackGenius provides hosting for LiteNet free of charge. Specific details regarding their affiliate program can be found [here](https://my.rackgenius.com/index.php?rp=/knowledgebase/4/Affiliate-Program-FAQs.html)", "footer": { "text": "Made with <3 by Chris Chrome & The LiteNet Team â€ĸ Sponsored by RackGenius", "iconURL": "https://dingus.chrischro.me/raw/bfafda4c-9a2f-4f1e-8e78-fec2df7836f3.png" }, "timestamp": "2025-05-26T04:26:03.819Z", "thumbnail": { "url": "https://dingus.chrischro.me/raw/bfafda4c-9a2f-4f1e-8e78-fec2df7836f3.png" }, "image": { "url": "https://dingus.chrischro.me/raw/54d12d28-6a88-46b8-a95e-dc8c1f346cd6.png" }, "fields": [{ "name": "What's this?", "value": "The community PBX is a public, free to use [FreePBX](https://freepbx.org) based phone system that any server member is welcome to get a number on!\nEveryone on the system has their own 4 digit number, that can be used to call between other members on the system.\nThe PBX runs on a RackGenius VPS graciously provided to us at no cost!", "inline": false }, { "name": "What can it do?", "value": "The LiteNet phone system offers many features, including but not limited to the following:\n- Free inbound/outbound calling via +1 (610) LITENET (548-3638)\n- Private Voicemail\n- Intercom/Paging\n- Conference Rooms\n- Direct dial access to [AstroCom](https://astrocom.tel)\n- [Full extension status page](https://pbx.litenet.tel/status)\n- And more!", "inline": false }, { "name": "Privacy Policy", "value": "LiteNet respects the privacy of all members, and as such, only very few select staff members have access to the system files directly. Voicemails are not tracked nor listened to under any circumstances. Call logs are kept and only reviewed during investigations into violations of community guidelines, or possible illegal activity. Call recordings may be kept at the request of any individual member, and will NOT be reviewed unless prior permission was given from said member.\nAll user data may be deleted by request, or by simply running the `/delete` command.\n\nIf you believe your privacy has been violated in any way, please don't hesistate to reach out to any of our staff members!", "inline": false }, { "name": "Call Recording Notice", "value": "Due to repeated issues with prank and spam calling in the past via the PSTN, all inbound and outbound calls are recorded. Recordings are retained for seven (7) days from the end of the call. If you have any questions, please reach out via a support ticket!", "inline": false }, { "name": "Can it do `X`?", "value": "Any specific questions are welcome to be asked in our <#1102782499756724239> chat!\nIf you have a suggestion for something we should add to the PBX or Discord server, feel free to leave it in <#1148099609428762634>!", "inline": false }] }], diff --git a/migrations/003_fuck_freepbx_gql.sql b/migrations/003_fuck_freepbx_gql.sql index 7f855bc..e07e6fd 100644 --- a/migrations/003_fuck_freepbx_gql.sql +++ b/migrations/003_fuck_freepbx_gql.sql @@ -1,5 +1,6 @@ -INSERT INTO userman_users (username, auth) -SELECT du.extension, '1' +INSERT INTO userman_users (username, auth, description) + +SELECT du.extension, '1', 'FPBX GQL Fix. Thanks Sangoma.' FROM discord_users du LEFT JOIN userman_users uu ON uu.username = du.extension