import { hasManagerPermissions } from "@/utils/discord/permissions"; import type { Client, Message, Snowflake } from "discord.js"; type Pending = { channels: Set; timer: NodeJS.Timeout; }; const pendingReports = new Map(); const cooldowns = new Map(); async function getLogChannel(client: Client) { return client.channels.fetch("1478940790112915486"); } type AutomodResult = { delete: true } | null; type AutomodFunction = ( client: Client, message: Message, ) => Promise; export async function handleMessage(client: Client, message: Message) { if (message.author.bot || !message.guildId) return; const automodFunctions: AutomodFunction[] = [handleSpamLinks]; for (const func of automodFunctions) { const result = await func(client, message); if (result?.delete) { await message.delete().catch(() => null); break; } } } async function handleSpamLinks( client: Client, message: Message, ): Promise { if (message.author.bot || !message.guildId || !message.member) return null; if (await hasManagerPermissions(message.member)) return null; if (message.channelId === "1378529224192819250") return null; const { content } = message; const blacklisted = [ "discord.gg/", "discordapp.com/invite/", "discord.com/invite/", ]; if (!blacklisted.some((link) => content.includes(link))) return null; if (cooldowns.has(message.author.id)) { return { delete: true }; } const existing = pendingReports.get(message.author.id); if (!existing) { const content = [ `<@${message.author.id}>, your message contained an invite link and was deleted to prevent phishing attempts.`, "Keep in mind, we don't allow advertising other servers here.", ]; await message.reply(content.join(" ")); const logChannel = await getLogChannel(client); if (logChannel?.isSendable()) { await message.forward(logChannel); logChannel.send( `Deleted a message from <@${message.author.id}> in <#${message.channelId}> containing a potential phishing link.`, ); } const timer = setTimeout( () => flushReport(client, message.author.id), 30_000, ); pendingReports.set(message.author.id, { channels: new Set([message.channelId]), timer, }); return { delete: true }; } existing.channels.add(message.channelId); clearTimeout(existing.timer); existing.timer = setTimeout( () => flushReport(client, message.author.id), 30_000, ); return { delete: true }; } async function flushReport(client: Client, authorId: Snowflake) { const pending = pendingReports.get(authorId); if (!pending) return; pendingReports.delete(authorId); clearTimeout(pending.timer); const logChannel = await getLogChannel(client); if (!logChannel?.isSendable()) return; const channels = Array.from(pending.channels); const channelMentions = channels.map((c) => `<#${c}>`).join(", "); logChannel.send( `<@${authorId}> posted links in channels: ${channelMentions}`, ); const cooldownTimer = setTimeout( () => cooldowns.delete(authorId), 5 * 60 * 1000, ); cooldowns.set(authorId, cooldownTimer); }