import Command from "../../struct/Command"; import { client } from "../.."; import Infraction from "../../struct/antispam/Infraction"; import InfractionType from "../../struct/antispam/InfractionType"; import { isModerator, NO_MANAGER_MSG, parseUserOrId, uploadFile } from "../util"; import Day from 'dayjs'; import RelativeTime from 'dayjs/plugin/relativeTime'; import Xlsx from 'xlsx'; import { fetchUsername } from "../modules/mod_logs"; import MessageCommandContext from "../../struct/MessageCommandContext"; Day.extend(RelativeTime); export default { name: 'warns', aliases: [ 'warnings', 'infractions', 'infraction' ], description: 'Show all user infractions', syntax: '/warns; /warns @username ["export-csv"]; /warns rm [ID]', category: 'moderation', run: async (message: MessageCommandContext, args: string[]) => { if (!await isModerator(message.member!, message.serverContext)) return message.reply(NO_MANAGER_MSG); let collection = client.db.get('infractions'); let infractions: Array = await collection.find({ server: message.serverContext._id, }); let userInfractions: Map = new Map(); infractions.forEach(i => { if (!userInfractions.get(i.user)) userInfractions.set(i.user, [ i ]); else userInfractions.set(i.user, [ i, ...userInfractions.get(i.user)! ]); }); if (!args[0]) { // Show top most warned users let msg = `## Most warned users in ${message.serverContext.name}\n\u200b\n`; for (let inf of Array.from(userInfractions.values()).sort((a, b) => b.length - a.length).slice(0, 9)) { inf = inf.sort((a, b) => b.date - a.date); msg += `**${await fetchUsername(inf[0].user)}** (${inf[0].user}): **${inf.length}** infractions\n`; msg += `\u200b \u200b \u200b \u200b \u200b ↳ Most recent infraction: ${getInfEmoji(inf[0])}\`${inf[0].reason}\` ` + `${inf[0].type == InfractionType.Manual ? `(${await fetchUsername(inf[0].createdBy ?? '')})` : ''}\n`; }; message.reply(msg.substring(0, 1999)); } else { switch(args[0]?.toLowerCase()) { case 'delete': case 'remove': case 'rm': case 'del': let id = args[1]; if (!id) return message.reply('No infraction ID provided.'); let inf: Infraction|null = await client.db.get('infractions').findOneAndDelete({ _id: { $eq: id.toUpperCase() }, server: message.serverContext._id }); if (!inf) return message.reply('I can\'t find that ID.'); message.reply(`## Infraction deleted\n` + `ID: \`${inf._id}\`\n` + `Reason: ${getInfEmoji(inf)}\`${inf.reason}\` ` + `(${inf.type == InfractionType.Manual ? await fetchUsername(inf.createdBy ?? '') : 'System'})\n` + `Created ${Day(inf.date).fromNow()}`); break; default: let user = await parseUserOrId(args[0]); if (!user?._id) return message.reply('I can\'t find this user.'); let infs = userInfractions.get(user._id); if (!infs) return message.reply(`There are no infractions stored for \`${await fetchUsername(user._id)}\`.`); else { let msg = `## ${infs.length} infractions stored for ${await fetchUsername(user._id)}\n\u200b\n`; let attachSpreadsheet = false; for (const i in infs) { let inf = infs[i]; let toAdd = ''; toAdd += `#${Number(i)+1}: ${getInfEmoji(inf)} \`${inf.reason}\` (${inf.type == InfractionType.Manual ? await fetchUsername(inf.createdBy!) : 'System'})\n`; toAdd += `\u200b \u200b \u200b \u200b \u200b ↳ ${Day(inf.date).fromNow()} (Infraction ID: \`${inf._id}\`)\n`; if ((msg + toAdd).length > 1900 || Number(i) > 5) { msg += `\u200b\n[${infs.length - Number(i) + 1} more, check attached file]`; attachSpreadsheet = true; break; } else msg += toAdd; } if (args[1]?.toLowerCase() == 'export-csv' || args[1]?.toLowerCase() == 'csv' || args[1]?.toLowerCase() == 'export') attachSpreadsheet = true; if (attachSpreadsheet) { try { let csv_data = [ [`Warns for ${await fetchUsername(user._id)} (${user._id}) - ${Day().toString()}`], [], ['Date', 'Reason', 'Created By', 'Type', 'Action Type', 'ID'], ]; for (const inf of infs) { csv_data.push([ Day(inf.date).toString(), inf.reason, inf.type == InfractionType.Manual ? `${await fetchUsername(inf.createdBy!)} (${inf.createdBy})` : 'SYSTEM', inf.type == InfractionType.Automatic ? 'Automatic' : 'Manual', inf.actionType || 'warn', inf._id, ]); } let sheet = Xlsx.utils.aoa_to_sheet(csv_data); let csv = Xlsx.utils.sheet_to_csv(sheet); message.reply({ content: msg, attachments: [ await uploadFile(csv, `${user._id}.csv`) ] }); } catch(e) { console.error(e); message.reply(msg); } } else message.reply(msg); } break; } } } } as Command; function getInfEmoji(inf: Infraction) { switch(inf.actionType) { case 'kick': return ':mans_shoe: '; case 'ban': return ':hammer: '; default: return ''; } }