/[sudobot]/branches/4.x/src/commands/moderation/HistoryCommand.ts
ViewVC logotype

Contents of /branches/4.x/src/commands/moderation/HistoryCommand.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months, 1 week ago) by rakinar2
File MIME type: application/typescript
File size: 7681 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 /**
2 * This file is part of SudoBot.
3 *
4 * Copyright (C) 2021-2022 OSN Inc.
5 *
6 * SudoBot is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * SudoBot is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 import { CommandInteraction, ContextMenuInteraction, Message, Permissions, User } from 'discord.js';
21 import BaseCommand from '../../utils/structures/BaseCommand';
22 import DiscordClient from '../../client/Client';
23 import CommandOptions from '../../types/CommandOptions';
24 import InteractionOptions from '../../types/InteractionOptions';
25 import MessageEmbed from '../../client/MessageEmbed';
26 import getUser from '../../utils/getUser';
27 import Punishment, { IPunishment } from '../../models/Punishment';
28 import PunishmentType from '../../types/PunishmentType';
29 import Pagination from '../../utils/Pagination';
30 import { format, formatDistanceToNowStrict } from 'date-fns';
31
32 export const convert = (type: PunishmentType) => {
33 switch (type) {
34 case PunishmentType.BAN:
35 return 'Ban';
36 case PunishmentType.SOFTBAN:
37 return 'Soft Ban';
38 case PunishmentType.TEMPBAN:
39 return 'Temporary Ban';
40 case PunishmentType.SHOT:
41 return 'Shot';
42 case PunishmentType.MUTE:
43 return 'Mute';
44 case PunishmentType.HARDMUTE:
45 return 'Hardmute';
46 case PunishmentType.KICK:
47 return 'Kick';
48 case PunishmentType.WARNING:
49 return 'Warning';
50 case PunishmentType.UNBAN:
51 return 'Unban';
52 case PunishmentType.UNMUTE:
53 return 'Unmute';
54 case PunishmentType.BEAN:
55 return 'Bean';
56 default:
57 return "Unknown";
58 }
59 };
60
61 export default class HistoryCommand extends BaseCommand {
62 supportsInteractions: boolean = true;
63 supportsContextMenu = true;
64 permissions = [Permissions.FLAGS.MANAGE_MESSAGES];
65
66 constructor() {
67 super('history', 'moderation', ['Moderation History']);
68 }
69
70 verboseOutput(data: IPunishment[]) {
71 let str = '';
72
73 for (const row of data) {
74 str += `**Case ID**: \`${row.numericId}\`\n`;
75 str += `**Type**: ${convert(row.type as PunishmentType)}\n`;
76 str += `**Reason**: ${row.reason ? (row.reason.trim() === '' ? '*No reason provided*' : `\`\`\`${row.reason}\`\`\``) : '*No reason provided*'}\n`;
77
78 str += `**Action Executor**: ${row.mod_tag} (<@${row.mod_id}>)\n`;
79 str += `**Date**: ${format(row.createdAt, "dd MMMM yyyy 'at' h:mm a")} (${formatDistanceToNowStrict(row.createdAt, { addSuffix: true })})\n`;
80
81 if (row.meta) {
82 const json = typeof row.meta === 'string' ? JSON.parse(row.meta) : row.meta;
83
84 if (Object.keys(json).length > 0) {
85 str += "Additional Attributes:\n```\n";
86
87 for (const key in json) {
88 str += `${key}: ${json[key]}\n`;
89 }
90
91 str += '\n```\n';
92 }
93 }
94
95 str += '\n';
96 }
97
98 return str;
99 }
100
101 shortOutput(data: IPunishment[]) {
102 let str = '';
103
104 for (const row of data) {
105 str += `\`${row.numericId}\` | \`${convert(row.type as PunishmentType)}\` | <@${row.user_id}> | Moderated by <@${row.mod_id}> | ${formatDistanceToNowStrict(row.createdAt, { addSuffix: true })}\n`;
106 }
107
108 return str;
109 }
110
111 async run(client: DiscordClient, msg: Message | CommandInteraction | ContextMenuInteraction, options: CommandOptions | InteractionOptions) {
112 if (!options.isInteraction && typeof options.args[0] === 'undefined') {
113 await msg.reply({
114 embeds: [
115 new MessageEmbed()
116 .setColor('#f14a60')
117 .setDescription(`This command requires at least one argument.`)
118 ]
119 });
120
121 return;
122 }
123
124 if (msg instanceof CommandInteraction || msg instanceof ContextMenuInteraction) {
125 await msg.deferReply({ ephemeral: true });
126 }
127
128 let user: User | null | undefined;
129 let verbose = options.isInteraction ? (options.options.getBoolean('verbose') ?? true) : (!options.args.includes('--no-verbose') && !options.args.includes('-s'));
130
131 if (options.isInteraction) {
132 user = await <User> options.options.getUser('user');
133 }
134 else {
135 try {
136 user = await getUser(client, msg as Message, options);
137
138 if (!user)
139 throw new Error();
140 }
141 catch (e) {
142 console.log(e);
143
144 await this.deferReply(msg, {
145 embeds: [
146 new MessageEmbed()
147 .setColor('#f14a60')
148 .setDescription(`Invalid user given.`)
149 ]
150 });
151
152 return;
153 }
154 }
155
156 const { verboseOutput, shortOutput } = this;
157
158 const paginator = new Pagination<IPunishment>(null, {
159 channel_id: msg.channel!.id,
160 guild_id: msg.guild!.id,
161 limit: 5,
162 timeout: 120_000,
163 user_id: msg.member!.user.id,
164 async maxData() {
165 return await Punishment.find({
166 guild_id: msg.guild!.id,
167 user_id: user!.id,
168 type: {
169 $nin: [
170 PunishmentType.BEAN,
171 PunishmentType.SHOT,
172 ]
173 }
174 }).count();
175 },
176 async fetchData({ limit, offset }) {
177 const data = await Punishment.find({
178 guild_id: msg.guild!.id,
179 user_id: user!.id,
180 type: {
181 $nin: [
182 PunishmentType.BEAN,
183 PunishmentType.SHOT,
184 ]
185 }
186 }).skip(offset).limit(limit).sort({ createdAt: -1 });
187
188 return data;
189 },
190 embedBuilder({ data, currentPage, maxPages }) {
191 const str = verbose ? verboseOutput(data) : shortOutput(data);
192
193 return new MessageEmbed({
194 author: {
195 name: user!.tag,
196 iconURL: user!.displayAvatarURL()
197 },
198 title: 'Moderation History',
199 description: str === '' ? 'No history.' : str,
200 timestamp: new Date(),
201 footer: { text: `Page ${currentPage} of ${maxPages === 0 ? 1 : maxPages}` }
202 });
203 },
204 });
205
206 let reply = <Message> await this.deferReply(msg, await paginator.getMessageOptions(1));
207
208 if (msg instanceof CommandInteraction) {
209 reply = <Message> await msg.fetchReply();
210 }
211
212 paginator.start(reply).catch(console.error);
213 }
214 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26