History command
This commit is contained in:
parent
21ad6a073e
commit
8bd91e6a16
208
src/structure/components/commands/moderation/History.js
Normal file
208
src/structure/components/commands/moderation/History.js
Normal 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;
|
Loading…
Reference in New Issue
Block a user