189 lines
6.8 KiB
JavaScript
189 lines
6.8 KiB
JavaScript
const client = global.discord_client
|
|
const pool = global.db_pool;
|
|
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const { pipeline } = require('stream');
|
|
const { promisify } = require('util');
|
|
|
|
const streamPipeline = promisify(pipeline);
|
|
|
|
/**
|
|
* Downloads a file from a URL to a specified destination.
|
|
* @param {string} url - The URL to download the file from.
|
|
* @param {string} dest - The destination file path to save the file.
|
|
* @param {function} cb - Callback function called on completion or error.
|
|
*/
|
|
async function download(url, dest, cb) {
|
|
try {
|
|
const response = await fetch(url);
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
}
|
|
await streamPipeline(response.body, fs.createWriteStream(dest));
|
|
cb(null); // Signal success
|
|
} catch (error) {
|
|
cb(error); // Pass error to callback
|
|
}
|
|
}
|
|
|
|
const cancel = (user) => {
|
|
delete global.productUpdateData[user.id];
|
|
delete global.dmHandlers[user.id];
|
|
user.send('Product update cancelled.');
|
|
}
|
|
|
|
const execute = async (message) => {
|
|
const userData = global.productUpdateData[message.author.id];
|
|
switch (userData?.type) {
|
|
case "name": // Name
|
|
const newName = message.content.trim();
|
|
if (newName.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
await pool.query('UPDATE products SET name = ? WHERE id = ?', [newName, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('Product name updated!');
|
|
break;
|
|
case "description": // Description
|
|
const newDesc = message.content.trim();
|
|
if (newDesc.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
await pool.query('UPDATE products SET description = ? WHERE id = ?', [newDesc, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('Product description updated!');
|
|
break;
|
|
case "devProductId": // Dev Product ID
|
|
const newDevId = message.content.trim();
|
|
if (newDevId.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
if (!/^\d{1,15}$/.test(newDevId)) {
|
|
message.channel.send('Invalid Dev Product ID. It must be a number between 1 and 15 digits.');
|
|
return;
|
|
}
|
|
await pool.query('UPDATE products SET devProductID = ? WHERE id = ?', [newDevId, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('Dev Product ID updated!');
|
|
break;
|
|
case "imageId": // Image ID
|
|
const newImageId = message.content.trim();
|
|
if (newImageId.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
if (!/^\d{1,15}$/.test(newImageId)) {
|
|
message.channel.send('Invalid Image ID. It must be a number between 1 and 15 digits.');
|
|
return;
|
|
}
|
|
await pool.query('UPDATE products SET imageId = ? WHERE id = ?', [newImageId, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('Image ID updated!');
|
|
break;
|
|
case "file": // File
|
|
if (message.content.trim().toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
|
|
if (message.attachments.size > 0) {
|
|
const attachment = message.attachments.first();
|
|
const validExtensions = ['zip', 'rbxm', 'rbxmx'];
|
|
const fileExtension = attachment.name.split('.').pop().toLowerCase();
|
|
|
|
if (!validExtensions.includes(fileExtension)) {
|
|
message.channel.send('Invalid file type. Only zip, rbxm, and rbxmx files are allowed.');
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
const file = fs.createWriteStream(`./productFiles/${crypto.randomBytes(8).toString('hex')}`);
|
|
download(attachment.url, file.path, async (err) => {
|
|
if (err) {
|
|
message.channel.send('Failed to download the file.');
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
const fileType = attachment.name.split('.').pop();
|
|
await pool.query('UPDATE products SET file = ?, fileType = ? WHERE id = ?', [file.path.split('/').pop(), fileType, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('File updated successfully!');
|
|
});
|
|
} else {
|
|
message.channel.send('No file attached. Please upload the product file.');
|
|
}
|
|
break;
|
|
case "stock": // Stocking info
|
|
const newStock = parseInt(message.content.trim());
|
|
if (isNaN(newStock)) {
|
|
message.channel.send('Invalid stock quantity. It must be a number.');
|
|
return;
|
|
}
|
|
await pool.query('UPDATE products SET stock = ? WHERE id = ?', [newStock, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('Stock quantity updated!');
|
|
break;
|
|
case "category": // Category
|
|
const newCategory = message.content.trim();
|
|
if (newCategory.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
if (newCategory.toLowerCase() === '~none') {
|
|
newCategory = null;
|
|
}
|
|
await pool.query('UPDATE products SET category = ? WHERE id = ?', [newCategory, global.productUpdateData[message.author.id].id]);
|
|
message.channel.send('Category updated!');
|
|
break;
|
|
case "delete": // Delete
|
|
if (message.content.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
if (message.content.toLowerCase() !== 'confirm') {
|
|
message.channel.send('You must type `confirm` to delete the product, or `cancel` to exit.');
|
|
return;
|
|
}
|
|
// Proceed with deletion
|
|
const pid = userData.id;
|
|
message.channel.send('Deletion Confirmed. Starting deletion process...').then(async msg => {
|
|
let curMsg = msg.content;
|
|
// Delete fileAuth
|
|
curMsg = curMsg + '\nDeleting file authorizations...';
|
|
await msg.edit(curMsg);
|
|
await pool.query('DELETE FROM fileAuth WHERE product = ?', [pid]);
|
|
// Delete file
|
|
curMsg = curMsg + '\nDeleting product file...';
|
|
await msg.edit(curMsg);
|
|
const [product] = await pool.query('SELECT file FROM products WHERE id = ?', [pid]);
|
|
if (product) {
|
|
const safeFileId = path.basename(product.file);
|
|
const filePath = path.join(__dirname, '../productFiles', safeFileId); // Code we use in the CDN route
|
|
if (fs.existsSync(filePath)) {
|
|
fs.unlinkSync(filePath);
|
|
curMsg = curMsg + `\nDeleted file: ${safeFileId}`;
|
|
await msg.edit(curMsg);
|
|
} else {
|
|
curMsg = curMsg + `\nFile not found (skipping): ${safeFileId}`;
|
|
await msg.edit(curMsg);
|
|
}
|
|
}
|
|
// Delete purchases
|
|
curMsg = curMsg + '\nDeleting purchases...';
|
|
await msg.edit(curMsg);
|
|
await pool.query('DELETE FROM purchases WHERE productId = ?', [pid]);
|
|
// Delete product
|
|
curMsg = curMsg + '\nDeleting product...';
|
|
await msg.edit(curMsg);
|
|
await pool.query('DELETE FROM products WHERE id = ?', [pid]);
|
|
curMsg = curMsg + '\nProduct deletion complete.';
|
|
await msg.edit(curMsg);
|
|
});
|
|
break;
|
|
default:
|
|
message.channel.send('Invalid type. Somehow?');
|
|
cancel(message.author);
|
|
break;
|
|
}
|
|
delete global.productUpdateData[message.author.id];
|
|
delete global.dmHandlers[message.author.id];
|
|
}
|
|
module.exports = execute |