Compare commits

..

36 commits

Author SHA1 Message Date
Christopher Cookman 1a19ca954d Merge pull request 'Feature: Password Reset Functionality' (#4) from dev into main
Reviewed-on: #4
2025-11-21 22:33:23 -07:00
Christopher Cookman 3c0f3cd2a7 Another Fix 2025-11-21 22:30:11 -07:00
Christopher Cookman 37743b593b Another Fix 2025-11-21 22:27:46 -07:00
Christopher Cookman b92736997f Another Fix 2025-11-21 22:20:18 -07:00
Christopher Cookman 9a5b02f0f8 Another Fix 2025-11-21 22:19:27 -07:00
Christopher Cookman 823a501869 Another Fix 2025-11-21 21:51:20 -07:00
Christopher Cookman c49f043537 Another Fix 2025-11-21 21:50:13 -07:00
Christopher Cookman 218d9205c4 Another Fix 2025-11-18 12:20:56 -07:00
Christopher Cookman cdaf08b449 Another Fix 2025-11-18 12:19:39 -07:00
Christopher Cookman 55515da30d Another Fix 2025-11-18 12:18:06 -07:00
Christopher Cookman 96f0d8b8df Another Fix 2025-11-18 12:14:52 -07:00
Christopher Cookman 10f0c14734 Another Fix 2025-11-18 12:14:27 -07:00
Christopher Cookman 976bcf2672 Another Fix 2025-11-18 12:13:59 -07:00
Christopher Cookman e65297dcdf Another Fix 2025-11-18 12:11:29 -07:00
Christopher Cookman a0e96f50c2 Another Fix 2025-11-18 12:09:49 -07:00
Christopher Cookman a1728d8011 Another Fix 2025-11-18 12:08:57 -07:00
Christopher Cookman 0a38ac6035 Another Fix 2025-11-13 09:07:04 -07:00
Christopher Cookman 83de989e97 Another Fix 2025-11-13 09:05:57 -07:00
Christopher Cookman a954c845cf Another Fix 2025-11-13 09:05:17 -07:00
Christopher Cookman a0bb249ebc Another Fix 2025-11-13 09:04:51 -07:00
Christopher Cookman 50015218a6 Another Fix 2025-11-13 09:04:17 -07:00
Christopher Cookman 465fef3ca8 Another Fix 2025-11-13 09:03:49 -07:00
Christopher Cookman 156f121fcc Another Fix 2025-11-13 09:03:12 -07:00
Christopher Cookman 948a28f1d6 Another Fix 2025-11-13 09:02:54 -07:00
Christopher Cookman 2e1ed82538 Another Fix 2025-11-13 09:02:30 -07:00
Christopher Cookman 5a0c18e434 Another Fix 2025-11-13 09:02:06 -07:00
Christopher Cookman 95e1c66570 Another Fix 2025-11-13 09:01:41 -07:00
Christopher Cookman 5b56bcdb08 Another Fix 2025-11-13 08:58:57 -07:00
Christopher Cookman a36742d485 Another Fix 2025-11-13 08:57:58 -07:00
Christopher Cookman 2c265e4eb6 Fix 7 2025-11-13 08:56:24 -07:00
Christopher Cookman 1f0b14d326 Fix 6 2025-11-13 08:55:57 -07:00
Christopher Cookman 0abddc846b Fix 5 2025-11-13 08:54:32 -07:00
Christopher Cookman cdda6bb8bf Fix 4 2025-11-13 08:51:24 -07:00
Christopher Cookman 7c29db35e4 Fix 2 2025-11-13 08:49:47 -07:00
Christopher Cookman 15411c9744 Fix 1 2025-11-13 08:49:08 -07:00
Christopher Cookman d0040c6c1f Add reset logic and command, to test 2025-11-13 08:19:53 -07:00
12 changed files with 263 additions and 100 deletions

View file

@ -303,5 +303,10 @@ module.exports = [
"type": 1 "type": 1
} }
] ]
},
{
"name": "reset",
"description": "Reset or change your extension password", // Opens a modal to reset password
"type": 1
} }
] ]

View file

@ -108,7 +108,6 @@ class FreepbxManager {
vmPassword: $vmPassword vmPassword: $vmPassword
email: "" email: ""
maxContacts: "100" maxContacts: "100"
umEnable: false
}) { }) {
status status
} }
@ -155,24 +154,47 @@ class FreepbxManager {
return await this.pbxCall(query); return await this.pbxCall(query);
} }
// async updateName(ext, name) { async updateExtName(ext, name) {
// const query = gql` const query = gql`
// mutation updateName($ext: ID!, $name: String!) { mutation updateExt($ext: ID!, $name: String) {
// updateExtension(input: {extensionId: $ext, name: $name}) { updateExtension(input: {
// status, name: $name
// message extensionId: $ext
// } }) {
// }`; status,
message
}
}`;
// const variables = { const variables = {
// ext, name,
// name, ext
// }; };
// return await this.pbxCall(query, variables); return await this.pbxCall(query, variables);
// } }
// TODO: Implement updateName method, Current implementation resets extension for some reason // TODO: Implement updateName method, Current implementation resets extension for some reason
async updateExtPassword(ext, oldName, password) {
const query = gql`
mutation updateExt($ext: ID!, $name: String, $password: String) {
updateExtension(input: {
name: $name
extensionId: $ext
extPassword: $password
}) {
status,
message
}
}`;
const variables = {
ext,
password,
name: oldName
};
return await this.pbxCall(query, variables);
}
async joinPageGroup(ext, pageGroup) { async joinPageGroup(ext, pageGroup) {
const [lookup] = await this.pool.query('SELECT * FROM paging_groups WHERE page_number = ? AND ext = ?', [pageGroup, ext]); const [lookup] = await this.pool.query('SELECT * FROM paging_groups WHERE page_number = ? AND ext = ?', [pageGroup, ext]);
if (lookup) { if (lookup) {
@ -208,7 +230,6 @@ class FreepbxManager {
} }
nextExt++; nextExt++;
} }
return nextExt; return nextExt;
} }
} }

View file

@ -138,6 +138,24 @@ client.on('interactionCreate', async interaction => {
});; });;
} }
break; 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;
}
} }
}); });

View file

@ -6,77 +6,9 @@ const Discord = require("discord.js")
module.exports = {}; 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) => { module.exports.execute = async (interaction) => {
interaction.channel.send({ interaction.channel.send({
embeds: [{ 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 }] }],
"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: [ components: [
{ {
type: 1, type: 1,
@ -94,9 +26,79 @@ module.exports.execute = async (interaction) => {
emoji: "", emoji: "",
style: Discord.ButtonStyle.Primary, style: Discord.ButtonStyle.Primary,
custom_id: "getExtensionInfo" custom_id: "getExtensionInfo"
},
{
type: Discord.ComponentType.Button,
label: "Reset Password",
emoji: "🔄",
style: Discord.ButtonStyle.Danger,
custom_id: "resetPassword"
} }
] ]
} }
] ]
}) })
// 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"
// }
// ]
// }
// ]
// })
} }

View file

@ -0,0 +1,3 @@
module.exports = {};
module.exports.execute = require("../common/resetPasswordDialog").execute;

View file

@ -14,7 +14,7 @@ module.exports.execute = async (interaction) => {
} }
await interaction.editReply({ content: `Finding available extension`, ephemeral: true }); await interaction.editReply({ content: `Finding available extension`, ephemeral: true });
fpbx.getNextAvailableExtension().then(async (nextExt) => { 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) => { fpbx.addExtension(nextExt, interaction.user.username).then(async (res) => {
if (res.addExtension.status != true) { if (res.addExtension.status != true) {
await interaction.editReply({ content: `Something went wrong :(`, ephemeral: 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 interaction.editReply({ content: `Extension ${nextExt} created! Getting info..`, ephemeral: true });
await fpbx.reload(); await fpbx.reload();
const extInfo = await fpbx.getExtension(nextExt); const extInfo = await fpbx.getExtension(nextExt);
await interaction.editReply({ embeds: [{ await interaction.editReply({
title: "Your Extension Info", embeds: [{
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}\`||`, title: "Your Extension Info",
color: 0x00ff00 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}\`||`,
}], ephemeral: true }) 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); if (process.env.EXTENSION_ROLE_ID) await interaction.member.roles.add(process.env.EXTENSION_ROLE_ID);
}).catch(async (error) => { }).catch(async (error) => {
log.error(error); log.error(error);

View file

@ -2,6 +2,7 @@ const pool = global.pool
const fpbx = global.fpbx const fpbx = global.fpbx
const client = global.client const client = global.client
const log = global.log const log = global.log
const Discord = require('discord.js');
module.exports = {}; module.exports = {};
@ -20,6 +21,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}\`||`, 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 color: 0x00ff00
} }
],
components: [
{
type: 1,
components: [
{
type: Discord.ComponentType.Button,
label: "Reset Password",
emoji: "🔄",
style: Discord.ButtonStyle.Danger,
custom_id: "resetPassword"
}
]
}
] ]
}); });

View file

@ -0,0 +1,41 @@
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;
}
interaction.showModal({
title: 'Reset Extension Password',
customId: 'resetPasswordModal',
label: 'Reset Extension Password',
components: [
{
type: 1, // Action Row
components: [
// {
// type: 18, // Label
// ,
// component:
// }
{
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
}
]
}
]
});
}

View file

@ -0,0 +1,3 @@
module.exports = {};
module.exports.execute = require("../common/resetPasswordDialog").execute;

View file

@ -0,0 +1,35 @@
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;
}
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');
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;
const chars = process.env.PASSWORD_CHARS || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
passwordToSet = Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
}
try {
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) {
log.error(error);
await interaction.editReply({ content: 'There was an error while resetting your extension password!', ephemeral: true });
}
}

View file

@ -0,0 +1,11 @@
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
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.

10
package-lock.json generated
View file

@ -704,15 +704,6 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" "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": { "node_modules/env-paths": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@ -851,6 +842,7 @@
"version": "15.8.0", "version": "15.8.0",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz", "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
"integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==", "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
"peer": true,
"engines": { "engines": {
"node": ">= 10.x" "node": ">= 10.x"
} }