diff --git a/src/structure/components/commands/moderation/Case.js b/src/structure/components/commands/moderation/Case.js new file mode 100644 index 0000000..824d342 --- /dev/null +++ b/src/structure/components/commands/moderation/Case.js @@ -0,0 +1,134 @@ +const { Util } = require("../../../../utilities"); +const { SlashCommand } = require("../../../interfaces"); +const { inspect } = require('util'); + +class CaseCommand extends SlashCommand { + + constructor(client) { + super(client, { + name: 'case', + description: 'View case details', + module: 'moderation', + options: [{ + name: 'id', + type: 'INTEGER', + description: 'Case ID', + minimum: 0 + }, { + name: ['export', 'verbose', 'changes'], // + type: 'BOOLEAN', + description: [ + 'Print out raw infraction data in JSON form', + 'Print out more detailed information about the case', + 'List changes to the case' + ], + depeondsOn: ['id'] + }], + guildOnly: true, + showUsage: true + }); + } + + async execute(invoker, opts) { + + const { id, verbose, export: exp, changes } = opts; + const { guild } = invoker; + + const infraction = await this.client.storageManager.mongodb.infractions.findOne({ + id: `${guild.id}:${id.value}` + }, { projection: { _id: 0 } }); + + if (!infraction) return { emoji: 'failure', index: 'COMMAND_CASE_NOTFOUND', params: { caseID: id.value } }; + if (exp) return `\`\`\`js\n${inspect(infraction)}\`\`\``; + if (changes.value) return { embed: await this._listChanges(invoker, infraction) }; + + const target = infraction.targetType === 'USER' ? await this.client.resolver.resolveUser(infraction.target) : await guild.resolveChannel(infraction.target); + const staff = await this.client.resolver.resolveUser(infraction.executor); + + let index = 'COMMAND_CASE_TEMPLATE', + caseTitleIndex = 'COMMAND_CASE_TITLE', + caseSlowmodeIndex = 'COMMAND_CASE_SLOWMODE', + caseLengthIndex = 'COMMAND_CASE_LENGTH', + targetUserIndex = 'COMMAND_CASE_TARGET_USER', + targetChannelIndex = 'COMMAND_CASE_TARGET_CHANNEL'; + if (verbose?.value) { + index += '_VERBOSE'; + caseTitleIndex += '_VERBOSE'; + caseSlowmodeIndex += '_VERBOSE'; + caseLengthIndex += '_VERBOSE'; + targetUserIndex += '_VERBOSE'; + targetChannelIndex += '_VERBOSE'; + } + + let description = invoker.format(index, { + uniqueID: infraction.id, + type: infraction.type, + date: ``, + unix: Math.floor(infraction.timestamp / 1000), + relativeTime: ``, + relativeTimeSeconds: Math.floor((Date.now() - infraction.timestamp) / 1000), + target: infraction.targetType === 'USER' ? invoker.format(targetUserIndex, { target: target.tag, targetID: target.id }) : invoker.format(targetChannelIndex, { target: target.name, targetID: target.id }), + staff: staff.tag, + staffID: staff.id, + nrChanges: infraction.changes?.length || 0, + changes: infraction.changes?.map((change) => change.type).join(', ') || 'N/A', + guild: guild.id, + channel: infraction.channel, + message: infraction.message + }); + + if (infraction.data.seconds) description += '\n' + invoker.format(caseSlowmodeIndex, { readable: Util.humanise(infraction.data.seconds), seconds: infraction.data.seconds }); + if (infraction.duration !== null) description += '\n' + invoker.format(caseLengthIndex, { time: Util.humanise(infraction.duration), inSeconds: infraction.duration }); + + if (guild._settings.modpoints.enabled) description += '\n' + invoker.format('COMMAND_CASE_MODPOINTS', { + points: infraction.points, + expires: infraction.expiration + }); + + description += '\n\n' + invoker.format('COMMAND_CASE_REASON', { reason: infraction.reason }); + + const embed = { + title: invoker.format(caseTitleIndex, { caseID: id.value }), + description, + color: 8662306 + }; + + return { embed }; + + } + + async _listChanges(invoker, infraction) { + + const embed = { + title: invoker.format('COMMAND_CASE_CHANGES_TITLE', { case: infraction.case }), + color: 8662306 + }; + + if (!infraction.changes || !infraction.changes.length) embed.description = invoker.format('COMMAND_CASE_CHANGES_NONE'); + else embed.fields = await Promise.all(infraction.changes.sort((a, b) => b.timestamp - a.timestamp).map(async (change) => { + + const staff = await this.client.resolver.resolveUser(change.staff); + const field = { + name: change.type, + value: invoker.format('COMMAND_CASE_CHANGE_BASE', { + staff: staff.tag, + date: new Date(change.timestamp * 1000).toUTCString(), + timeAgo: `` + }) + }; + + if (change.type === 'RESOLVE') field.value += '\n' + invoker.format('COMMAND_CASE_CHANGES_RESOLVE', { reason: change.reason || invoker.format('COMMAND_CASE_CHANGE_NOREASON') }); + if (change.type === 'REASON') field.value += '\n' + invoker.format('COMMAND_CASE_CHANGES_REASON', { reason: change.reason }); + if (change.type === 'DURATION') field.value += '\n' + invoker.format('COMMAND_CASE_CHANGES_DURATION', { duration: Util.humanise(change.duration) }); + + return field; + + })); + + return embed; + + } + +} + +module.exports = CaseCommand; \ No newline at end of file