Compare commits

...

20 commits
main ... dev

Author SHA1 Message Date
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
10 changed files with 159 additions and 23 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

@ -155,24 +155,45 @@ 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, $password: String) {
// updateExtension(input: {extensionId: $ext, name: $name}) { updateExtension(input: {
// status, extensionId: $ext
// message name: $name
// } }) {
// }`; status,
message
}
}`;
// const variables = { const variables = {
// ext, ext,
// name, endName,
// }; };
// 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, 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) { 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) {

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

@ -94,6 +94,13 @@ 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"
} }
] ]
} }

View file

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

View file

@ -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}\`||`, 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,32 @@
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;
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 });
}
}

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"
} }