galactic-bot/structure/client/components/commands/moderation/History.js

264 lines
9.6 KiB
JavaScript
Raw Normal View History

2020-08-09 21:53:09 +02:00
const { Command } = require('../../../../interfaces/');
const { MessageAttachment } = require('discord.js');
2020-08-09 21:53:09 +02:00
const { stripIndents } = require('common-tags');
const moment = require('moment');
const { UploadLimit } = require('../../../../../util/Constants.js');
2020-08-09 21:53:09 +02:00
const { Util } = require('../../../../../util/');
const { InfractionResolves, InfractionProperCase } = require('../../../../../util/Constants.js');
2020-08-09 21:53:09 +02:00
const Constants = {
PageSize: 5,
MaxCharacters: 256,
MaxCharactersVerbose: 128 //Displays more information in the field, decreases characters.
};
2020-08-09 21:53:09 +02:00
class HistoryCommand extends Command {
constructor(client) {
super(client, {
name: 'history',
module: 'moderation',
usage: "[user..|channel..]",
aliases: [
'moderation'
],
memberPermissions: ['MANAGE_MESSAGES'],
guildOnly: true,
arguments: [
{
name: 'before', //Search for moderation actions before x
usage: '<date>',
type: 'DATE',
types: ['FLAG'],
required: true
},
{
name: 'after', //Search for moderation actions after x
usage: '<date>',
type: 'DATE',
types: ['FLAG'],
required: true
},
{
name: 'oldest',
aliases: ['old'],
type: 'BOOLEAN',
types: ['FLAG'],
default: true
},
{
name: 'type',
aliases: ['types'],
type: 'STRING',
types: ['FLAG'],
infinite: true,
required: true
},
{
name: 'pagesize',
type: 'INTEGER',
types: ['FLAG'],
required: true,
default: 10,
min: 1,
max: 10
},
{
name: 'verbose', //Shows IDs for users/channels.
type: 'BOOLEAN',
types: ['FLAG'],
default: true
},
2020-08-09 21:53:09 +02:00
{
name: 'export', //Export moderation actions in a JSON.
type: 'BOOLEAN',
types: ['FLAG'],
default: true
},
{
name: 'private', //Send moderation history in DMs.
type: 'BOOLEAN',
types: ['FLAG'],
default: true
} //filter, exclude, verbose (NO PAGESIZE)
],
throttling: {
usages: 2,
duration: 10
2020-08-09 21:53:09 +02:00
}
});
this.client = client;
}
async execute(message, { params, args }) {
2021-05-10 22:33:20 +02:00
const priv = Boolean(args.private);
if(args.export) return this._exportLogs(message, priv);
2020-08-09 21:53:09 +02:00
const query = {
guild: message.guild.id
};
const { parsed, parameters } = await this.client.resolver.infinite(params, [
this.client.resolver.resolveMember.bind(this.client.resolver),
this.client.resolver.resolveUser.bind(this.client.resolver),
this.client.resolver.resolveChannel.bind(this.client.resolver)
], true, message.guild, (c) => c.type === 'text');
if(parsed.length > 0) query.target = { $in: parsed.map((p) => p.id) }; //Add resolved ids to the query.
if(args.before || args.after) {
query.timestamp = {};
if(args.before) query.timestamp.$lt = args.before.value.valueOf(); //Add before timestamps to the query.
if(args.after) query.timestamp.$gt = args.after.value.valueOf(); //Add after timestamps to the query.
}
if(args.type) {
const filter = [];
for(const value of args.type.value) {
for(const [ type, matches ] of Object.entries(InfractionResolves)) {
if(matches.includes(value.toLowerCase())) {
filter.push(type);
}
}
}
query.type = { $in: filter };
}
const pageSize = args.pagesize ? args.pagesize.value : Constants.PageSize;
2020-08-09 21:53:09 +02:00
let page = 1;
if(parameters.length > 0) {
const number = parseInt(parameters[0]);
if(!Number.isNaN(number) && number > 1) {
page = number;
}
}
const collectionSize = await this.client.storageManager.mongodb.infractions.count(query);
if(collectionSize === 0) {
return message.respond(message.format('C_HISTORY_NORESULTS'), {
emoji: 'failure'
});
}
const maxPage = Math.ceil(collectionSize/pageSize);
if(page > maxPage) page = maxPage;
const infractions = await this.client.storageManager.mongodb.db.collection('infractions').find(query)
.sort({ timestamp: args.oldest ? 1 : -1 })
.skip((page-1)*pageSize).limit(pageSize)
.toArray();
2020-08-09 21:53:09 +02:00
const embed = {
author: {
name: 'Infraction History',
2020-08-09 21:53:09 +02:00
icon_url: message.guild.iconURL() //eslint-disable-line camelcase
},
fields: [],
footer: {
text: `• Page ${page}/${maxPage} | ${collectionSize} Results`
2021-05-05 16:47:11 +02:00
},
color: 8662306
};
let long = false;
const handleReason = (text) => {
const MaxCharacters = Constants[args.verbose ? 'MaxCharactersVerbose' : 'MaxCharacters'];
text = Util.escapeMarkdown(text);
if(text.length > MaxCharacters) {
text = `${text.substring(0, MaxCharacters-3)}...`;
long = true;
2020-08-09 21:53:09 +02:00
}
text = text.replace(/\\n/giu, ' ');
return text;
2020-08-09 21:53:09 +02:00
};
for(let i = 0; i<infractions.length; i++) {
const infraction = infractions[i];
2020-08-09 21:53:09 +02:00
let target = null;
2021-05-10 22:33:20 +02:00
if(infraction.targetType === 'USER') {
2020-08-09 21:53:09 +02:00
target = await this.client.resolver.resolveUser(infraction.target);
} else {
target = await this.client.resolver.resolveChannel(infraction.target, true, message.guild);
}
2021-05-10 22:33:20 +02:00
const executor = await this.client.resolver.resolveUser(infraction.executor);
let string = stripIndents`**Target:** ${Util.escapeMarkdown(target.display)}${args.verbose ? ` (${target.id})` : ''}
**Moderator:** ${executor ? `${Util.escapeMarkdown(executor.tag)}${args.verbose ? ` (${infraction.executor})` : ''}` : infraction.executor}`;
2021-05-10 22:33:20 +02:00
if(infraction.data.roleIds) {
string += `\n${message.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 !== infractions.length-1) string += `\n\u200b`; //Space out cases (as long as its not at the end)
2020-08-09 21:53:09 +02:00
embed.fields.push({
name: `__**${infraction.type} \`[case-${infraction.case}]\`** *(${moment(infraction.timestamp).fromNow()})*__`,
value: string
2020-08-09 21:53:09 +02:00
});
2020-08-09 21:53:09 +02:00
}
if(long) embed.footer.text += ` • To see the full reason, use the ${message.guild.prefix}case command.`;
const type = message.format('C_HISTORY_SUCCESSTYPE', { old: Boolean(args.oldest) }, true);
2021-05-10 22:33:20 +02:00
try {
message.respond(message.format('C_HISTORY_SUCCESS', {
targets: parsed.length > 0 ? message.format('C_HISTORY_SUCCESSTARGETS', {
plural: parsed.length === 1 ? '' : 's',
targets: parsed.map((p) => `**${Util.escapeMarkdown(p.display)}**`).join(' ')
}) : '',
type
}), {
emoji: 'success',
embed,
dm: Boolean(args.private)
});
} catch(e) { //eslint-disable-line no-unused-vars
message.respond(message.format('C_HISTORY_FAILTOOLONG'), {
emoji: 'failure'
});
}
}
async _exportLogs(message, priv = false) {
const logs = await this.client.storageManager.mongodb.infractions.find({ guild: message.guild.id });
const string = JSON.stringify(logs);
const attachment = new MessageAttachment(Buffer.from(string), `${message.guild.id}-moderation.json`);
const bytes = Buffer.byteLength(attachment.attachment);
const premium = priv ? '0' : message.guild.premiumTier;
if(bytes > UploadLimit[premium]*1024*1024) {
message.respond(message.format('C_HISTORY_FAILEXPORT', {
amount: bytes,
max: UploadLimit[premium]*1024*1024
}));
}
message.respond(message.format('C_HISTORY_SUCCESSEXPORT'), {
files: [ attachment ],
emoji: 'success',
dm: priv
});
2020-08-09 21:53:09 +02:00
}
}
module.exports = HistoryCommand;