const { ChannelType } = require('discord.js'); const { errorEmbed, infoEmbed, successEmbed, createEmbed } = require('../utils/embeds'); const { logCommand } = require('../systems/logger'); const { startDropSession, hasSession, getPrompt, handleDropMessage, canDrop } = require('../systems/drops'); const { startMassDropSession, hasMassSession, getMassPrompt, handleMassDropMessage } = require('../systems/massdrop'); const { stmts } = require('../database'); const { Colors } = require('../config'); // Import command handlers const setup = require('../commands/setup'); const createRoles = require('../commands/createRoles'); const createChannels = require('../commands/createChannels'); const backupLayout = require('../commands/backupLayout'); const shutdown = require('../commands/shutdown'); const ticketStats = require('../commands/ticketStats'); const permissionAudit = require('../commands/permissionAudit'); const postRules = require('../commands/postRules'); const postDisclaimer = require('../commands/postDisclaimer'); const applyUpdates = require('../commands/applyUpdates'); const fixPings = require('../commands/fixPings'); const clearDrops = require('../commands/clearDrops'); const fixDownloads = require('../commands/fixDownloads'); const coOwnerRole = require('../commands/coOwnerRole'); const editDrop = require('../commands/editDrop'); const deleteDrop = require('../commands/deleteDrop'); const OWNER_ID = process.env.OWNER_ID; // Owner-only command registry const commands = { 'setup server': setup, 'create roles': createRoles, 'create channels': createChannels, 'backup layout': backupLayout, 'shutdown bot': shutdown, 'ticket stats': ticketStats, 'permission audit': permissionAudit, 'post rules': postRules, 'post disclaimer': postDisclaimer, 'apply updates': applyUpdates, 'fix pings': fixPings, }; module.exports = { name: 'messageCreate', async execute(client, message) { if (message.author.bot) return; if (message.channel.type !== ChannelType.DM) return; const userId = message.author.id; const content = message.content.trim().toLowerCase(); // ── Handle active drop session (owner OR whitelisted) ── if (hasSession(userId)) { try { const handled = await handleDropMessage(message); if (handled) return; } catch (err) { console.error('[Drop Error]', err); await message.reply({ content: `❌ Drop error: ${err.message}` }).catch(() => { }); return; } } // ── Handle active mass drop session ── if (hasMassSession(userId)) { try { const handled = await handleMassDropMessage(message); if (handled) return; } catch (err) { console.error('[Mass Drop Error]', err); await message.reply({ content: `❌ Mass Drop error: ${err.message}` }).catch(() => { }); return; } } // ── Whitelisted user: only allow "drop" ── if (userId !== OWNER_ID) { if (content === 'drop' || content === 'linkdrop') { const check = await canDrop(userId); if (!check.allowed) { if (check.reason === 'not_whitelisted') { return; // Silently ignore non-whitelisted users } // Rate limited return message.reply({ embeds: [createEmbed({ title: '⏳ Drop Cooldown', description: `You've used all **${check.limit} drops** in the last 24 hours.\n\n> Resets in **${check.resetIn}**`, color: Colors.WARNING, })], }); } const session = startDropSession(userId); await message.reply({ ...getPrompt(session), content: `📦 **Drop ${check.limit - check.remaining + 1}/${check.limit} for today**`, }); return; } return; // Whitelisted users can only use "drop" or "linkdrop" } // ── Owner-only commands below ────────────────────────── // Drop (no rate limit for owner) if (content === 'drop' || content === 'linkdrop') { await logCommand(client, content); const session = startDropSession(userId); await message.reply(getPrompt(session)); return; } // Mass Drop (no rate limit for owner) if (content === 'massdrop') { await logCommand(client, 'massdrop'); const session = startMassDropSession(userId); await message.reply(getMassPrompt(session)); return; } // Whitelist management if (content.startsWith('whitelist ') && !content.startsWith('whitelist <')) { const args = content.split(' ').slice(1); const targetId = args[0]?.trim(); const limit = parseInt(args[1]) || 3; if (!targetId || !/^\d{17,20}$/.test(targetId)) { return message.reply({ embeds: [errorEmbed('Invalid ID', 'Usage: `whitelist [limit]`\nExample: `whitelist 123456789 5`')] }); } await stmts.addWhitelist(targetId, limit, userId); const user = await client.users.fetch(targetId).catch(() => null); const name = user ? `**${user.tag}**` : `ID \`${targetId}\``; return message.reply({ embeds: [successEmbed('✅ Whitelisted', `${name} can now use \`drop\` (**${limit}** per day)`)] }); } if (content.startsWith('unwhitelist ')) { const targetId = content.split(' ')[1]?.trim(); if (!targetId) return message.reply({ embeds: [errorEmbed('Invalid ID', 'Usage: `unwhitelist `')] }); await stmts.removeWhitelist(targetId); return message.reply({ embeds: [successEmbed('✅ Removed', `User \`${targetId}\` removed from whitelist`)] }); } // Clear Drops if (content.startsWith('clear ')) { const args = content.split(' ').slice(1); return clearDrops.execute(client, message, args); } // Fix Downloads (migrate old Link buttons to interactive buttons) if (content.startsWith('fix downloads')) { const args = content.split(' ').slice(2); return fixDownloads.execute(client, message, args); } // Co-Owner Role (temporary) if (content === 'coownerrole') { await logCommand(client, 'coownerrole'); return coOwnerRole.execute(client, message); } // Web Administration Commands if (content.startsWith('editdrop ')) { const args = content.split(' ').slice(1); return editDrop.execute(client, message, args); } if (content.startsWith('deletedrop ')) { const args = content.split(' ').slice(1); return deleteDrop.execute(client, message, args); } if (content === 'whitelist') { const all = await stmts.getAllWhitelist(); if (all.length === 0) { return message.reply({ embeds: [infoEmbed('Whitelist', 'No users whitelisted.\n\nUse `whitelist ` to add.')] }); } const lines = []; for (const w of all) { const user = await client.users.fetch(w.user_id).catch(() => null); const name = user ? user.tag : 'Unknown'; const drops = await stmts.getDropCount24h(w.user_id); lines.push(`• **${name}** (\`${w.user_id}\`) — ${drops.count}/${w.max_drops} drops today`); } return message.reply({ embeds: [infoEmbed('📋 Whitelist', lines.join('\n'))] }); } // Show help if (content === 'help') { const allCommands = [...Object.keys(commands), 'drop', 'massdrop', 'linkdrop', 'whitelist', 'whitelist [limit]', 'unwhitelist ', 'clear ']; const embed = infoEmbed('WSB Commands', [ 'All commands are **DM-only** and **Owner-only**.\n', ...allCommands.map(cmd => `\`${cmd}\``), ].join('\n')); return message.reply({ embeds: [embed] }); } // Find matching command const handler = commands[content]; if (!handler) { if (content.startsWith('setup') || content.startsWith('create') || content.startsWith('backup') || content.startsWith('shutdown') || content.startsWith('ticket') || content.startsWith('permission') || content.startsWith('post') || content.startsWith('drop') || content.startsWith('mass') || content.startsWith('link') || content.startsWith('apply') || content.startsWith('fix') || content.startsWith('clear')) { return message.reply({ embeds: [errorEmbed('Unknown Command', `Did you mean one of these?\n${[...Object.keys(commands), 'drop', 'massdrop', 'linkdrop', 'clear '].map(c => `\`${c}\``).join('\n')}`)] }); } return; } try { await logCommand(client, content); await handler.execute(client, message); } catch (err) { console.error(`[Command Error] ${content}:`, err); await message.reply({ embeds: [errorEmbed('Error', `Command failed: \`${err.message}\``)] }).catch(() => { }); } }, };