History command

This commit is contained in:
Erik 2022-04-29 20:05:42 +03:00
parent 21ad6a073e
commit 8bd91e6a16
Signed by untrusted user: Navy.gif
GPG Key ID: 811EC0CD80E7E5FB

View File

@ -0,0 +1,208 @@
const { stripIndents } = require("common-tags");
const { MessageAttachment } = require("discord.js");
const moment = require('moment');
const { Infractions, UploadLimit } = require("../../../../constants/Constants");
const { Util } = require("../../../../utilities");
const { SlashCommand } = require("../../../interfaces");
const Constants = {
PageSize: 5,
MaxCharacters: 256,
MaxCharactersVerbose: 128 //Displays more information in the field, decreases characters.
};
class HistoryCommand extends SlashCommand {
constructor(client) {
super(client, {
name: 'history',
description: 'List past infractions',
module: 'moderation',
memberPermissions: ['MANAGE_MESSAGES'],
guildOnly: true,
options: [{
name: ['before', 'after'],
type: 'DATE',
description: 'Filter by a date, must be in YYYY/MM/DD or YYYY-MM-DD format'
}, {
name: ['verbose', 'oldest', 'export', 'private'],
description: [
'Show more infromation about the listed infractions',
'Show oldest infraction first',
'Export the list of infractions',
'DM the command response'
],
type: 'BOOLEAN'
}, {
name: 'type',
description: 'Filter infractions by type',
choices: Infractions.map((inf) => {
return { name: inf.toLowerCase(), value: inf };
})
}, {
name: ['pagesize', 'page'],
description: ['Amount of infractions to list per page', 'Page to select'],
type: 'INTEGER',
minimum: 1
}, {
name: ['user', 'moderator'], //
description: ['User whose infractions to query, overrides channel if both are given', 'Query by moderator'],
type: 'USER'
}, {
name: 'channel',
description: 'Infractions done on channels, e.g. slowmode, lockdown',
type: 'TEXT_CHANNEL'
}]
});
}
async execute(invoker, opts) {
const { guild } = invoker;
const { user, moderator, channel, before, after, verbose, oldest,
export: exp, private: priv, type: infType, pagesize, page } = opts;
if (exp?.value) return this._exportLogs(invoker, priv?.value);
const query = {
guild: invoker.guild.id,
};
if (channel) query.target = channel.value.id;
if (user) query.target = user.value.id;
if (moderator) query.executor = moderator.value.id;
if (before || after) {
query.timestamp = {};
if (before) query.timestamp.$lt = before.value.valueOf();
if (after) query.timestamp.$gt = after.value.valueOf();
}
if (infType) query.type = infType.value;
const pageSize = pagesize ? pagesize.value : Constants.PageSize;
let _page = page ? page.value : 1;
const { infractions } = this.client.storageManager.mongodb;
const resultsAmt = await infractions.count(query);
if (!resultsAmt) return { emoji: 'failure', index: 'COMMAND_HISTORY_NORESULTS' };
const maxPage = Math.ceil(resultsAmt / pageSize);
if(_page > maxPage) _page = maxPage;
const results = await infractions.find(query, { projection: { _id: 0 } }, {
sort: { timestamp: oldest?.value ? 1 : -1 },
skip: (_page - 1) * pageSize,
limit: pageSize
});
const embed = {
author: {
name: 'Infraction History',
icon_url: invoker.guild.iconURL() //eslint-disable-line camelcase
},
fields: [],
footer: {
text: `• Page ${_page}/${maxPage} | ${resultsAmt} Results`
},
color: invoker.guild.me.roles.highest.color
};
let long = false;
const handleReason = (text) => {
const MaxCharacters = Constants[verbose?.value ? 'MaxCharactersVerbose' : 'MaxCharacters'];
text = Util.escapeMarkdown(text);
if (text.length > MaxCharacters) {
text = `${text.substring(0, MaxCharacters - 3)}...`;
long = true;
}
text = text.replace(/\\n/giu, ' ');
return text;
};
for (let i = 0; i < results.length; i++) {
const infraction = results[i];
let target = null;
if (infraction.targetType === 'USER') {
target = await this.client.resolver.resolveUser(infraction.target);
} else {
target = await guild.resolveChannel(infraction.target);
}
const executor = await this.client.resolver.resolveUser(infraction.executor);
let string = stripIndents`**Target:** ${Util.escapeMarkdown(target.tag || target.name)}${verbose?.value ? ` (${target.id})` : ''}
**Moderator:** ${executor ? `${Util.escapeMarkdown(executor.tag)}${verbose?.value ? ` (${infraction.executor})` : ''}` : infraction.executor}`;
if (infraction.data.roleIds) {
string += `\n${guild.format('INFRACTION_DESCRIPTIONROLES', {
plural: infraction.data.roleIds.length === 1 ? '' : 's',
roles: priv ? infraction.data.roleNames.join(', ') : infraction.data.roleIds.map((r) => `<@&${r}>`).join(' ')
})}`;
}
if (infraction.duration) string += `\n**Duration:** ${Util.duration(infraction.duration)}`;
if (infraction.points) string += `\n**Points:** ${infraction.points}`;
string += `\n**Reason:** \`${handleReason(infraction.reason)}\``;
if (i !== results.length - 1) string += `\n\u200b`; //Space out cases (as long as its not at the end)
embed.fields.push({
name: `__**${infraction.type} \`[case-${infraction.case}]\`** *(${moment(infraction.timestamp).fromNow()})*__`,
value: string
});
}
if (long) embed.footer.text += ` • To see the full reason, use the /case command.`;
const type = invoker.format('COMMAND_HISTORY_SUCCESSTYPE', { old: oldest?.value || false }, { code: true });
try {
return {
content: invoker.format('COMMAND_HISTORY_SUCCESS', {
targets: user || channel ? invoker.format('COMMAND_HISTORY_SUCCESSTARGETS', {
//plural: parsed.length === 1 ? '' : 's',
targets: `**${Util.escapeMarkdown(user?.value.tag || channel?.value.name)}**` //parsed.map((p) => `**${Util.escapeMarkdown(p.display)}**`).join(' ')
}) : '',
type
}),
emoji: 'success',
embed,
dm: Boolean(priv?.value)
};
} catch (e) {
return { index: 'COMMAND_HISTORY_FAILTOOLONG', emoji: 'failure' };
}
}
async _exportLogs(invoker, priv = false) {
const member = await invoker.memberWrapper();
if(!member.isAdmin()) return { emoji: 'failure', index: 'COMMAND_HISTORY_NO_EXPORT_PERMS' };
const logs = await this.client.storageManager.mongodb.infractions.find({ guild: invoker.guild.id }, { projection: { _id: 0 } });
const string = JSON.stringify(logs);
const attachment = new MessageAttachment(Buffer.from(string), `${invoker.guild.id}-moderation.json`);
const bytes = Buffer.byteLength(attachment.attachment);
const premium = priv ? '0' : invoker.guild.premiumTier;
if (bytes > UploadLimit[premium] * 1024 * 1024) {
return {
index: 'COMMAND_HISTORY_FAILEXPORT', params: {
amount: bytes,
max: UploadLimit[premium] * 1024 * 1024
}
};
}
return {
index: 'COMMAND_HISTORY_SUCCESSEXPORT',
files: [attachment],
emoji: 'success',
dm: priv
};
}
}
module.exports = HistoryCommand;