135 lines
5.2 KiB
JavaScript
135 lines
5.2 KiB
JavaScript
const client = global.discord_client
|
|
const pool = global.db_pool;
|
|
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
|
|
|
|
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.productCreationData[user.id];
|
|
delete global.dmHandlers[user.id];
|
|
user.send('Product creation cancelled.');
|
|
}
|
|
|
|
const execute = async (message) => {
|
|
switch (global.productCreationData[message.author.id].step) {
|
|
case 1: // Description
|
|
const description = message.content.trim();
|
|
if (description.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
global.productCreationData[message.author.id].description = description;
|
|
global.productCreationData[message.author.id].step = 2;
|
|
message.channel.send('Description set. Please provide the dev product ID. Say `cancel` to cancel creation.');
|
|
break;
|
|
case 2: // Dev product ID
|
|
const devProductId = message.content.trim();
|
|
|
|
if (devProductId.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
if (!/^\d{1,15}$/.test(devProductId)) {
|
|
message.channel.send('Invalid Dev Product ID. It must be a number between 1 and 15 digits.');
|
|
return;
|
|
}
|
|
global.productCreationData[message.author.id].devProductId = devProductId;
|
|
global.productCreationData[message.author.id].step = 3;
|
|
message.channel.send('Dev product ID set. Please provide the decal ID. Say `skip` to not set one, or `cancel` to cancel creation.');
|
|
break;
|
|
case 3: // Image ID
|
|
const imageId = message.content.trim();
|
|
if (imageId.toLowerCase() === 'cancel') {
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
|
|
if (imageId.toLowerCase() === "skip") {
|
|
global.productCreationData[message.author.id].imageId = null;
|
|
global.productCreationData[message.author.id].step = 4;
|
|
message.channel.send('Image ID skipped. Please upload the product file. Say `cancel` to cancel creation.');
|
|
return;
|
|
}
|
|
if (!/^\d{1,15}$/.test(newImageId)) {
|
|
message.channel.send('Invalid Image ID. It must be a number between 1 and 15 digits.');
|
|
return;
|
|
}
|
|
global.productCreationData[message.author.id].imageId = imageId;
|
|
global.productCreationData[message.author.id].step = 4;
|
|
message.channel.send('Image ID set. Please upload the product file.');
|
|
break;
|
|
case 4: // 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')}`);
|
|
const prodId = crypto.randomUUID();
|
|
download(attachment.url, file.path, (err) => {
|
|
if (err) {
|
|
message.channel.send('Failed to download the file.');
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
global.productCreationData[message.author.id].filePath = file.path.split('/').pop();
|
|
let fileType = attachment.name.split('.').pop();
|
|
global.productCreationData[message.author.id].step = 5;
|
|
message.channel.send('File uploaded successfully. Product creation complete.');
|
|
pool.query(`INSERT INTO products (id, name, description, devProductId, decalId, file, fileType, hubId) VALUES (?, ?, ?, ?, ?, ?, ?, ?);`, [prodId, global.productCreationData[message.author.id].name, global.productCreationData[message.author.id].description, global.productCreationData[message.author.id].devProductId, global.productCreationData[message.author.id].imageId, global.productCreationData[message.author.id].filePath, fileType, global.productCreationData[message.author.id].hub], (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
message.channel.send('An error occurred while creating the product.');
|
|
cancel(message.author);
|
|
return;
|
|
}
|
|
message.author.send('Product created successfully.');
|
|
delete global.productCreationData[message.author.id];
|
|
delete global.dmHandlers[message.author.id];
|
|
});
|
|
});
|
|
} else {
|
|
message.channel.send('No file attached. Please upload the product file.');
|
|
}
|
|
break;
|
|
default:
|
|
message.channel.send('Invalid step.');
|
|
cancel(message.author);
|
|
break;
|
|
}
|
|
}
|
|
module.exports = execute |