forked from Galactic/galactic-bot
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