upgrade /warn
This commit is contained in:
parent
1a55308047
commit
3f0a1cbd01
2 changed files with 138 additions and 27 deletions
|
@ -1,11 +1,13 @@
|
||||||
import SimpleCommand from "../../struct/commands/SimpleCommand";
|
import SimpleCommand from "../../struct/commands/SimpleCommand";
|
||||||
import { isModerator, NO_MANAGER_MSG, parseUserOrId, storeInfraction } from "../util";
|
import { dedupeArray, embed, EmbedColor, isModerator, NO_MANAGER_MSG, parseUserOrId, sanitizeMessageContent, storeInfraction } from "../util";
|
||||||
import Infraction from "../../struct/antispam/Infraction";
|
import Infraction from "../../struct/antispam/Infraction";
|
||||||
import { ulid } from "ulid";
|
import { ulid } from "ulid";
|
||||||
import InfractionType from "../../struct/antispam/InfractionType";
|
import InfractionType from "../../struct/antispam/InfractionType";
|
||||||
import { fetchUsername, logModAction } from "../modules/mod_logs";
|
import { fetchUsername, logModAction } from "../modules/mod_logs";
|
||||||
import MessageCommandContext from "../../struct/MessageCommandContext";
|
import MessageCommandContext from "../../struct/MessageCommandContext";
|
||||||
import CommandCategory from "../../struct/commands/CommandCategory";
|
import CommandCategory from "../../struct/commands/CommandCategory";
|
||||||
|
import { SendableEmbed } from "revolt-api";
|
||||||
|
import { User } from "@janderedev/revolt.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'warn',
|
name: 'warn',
|
||||||
|
@ -15,36 +17,114 @@ export default {
|
||||||
category: CommandCategory.Moderation,
|
category: CommandCategory.Moderation,
|
||||||
run: async (message: MessageCommandContext, args: string[]) => {
|
run: async (message: MessageCommandContext, args: string[]) => {
|
||||||
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
|
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
|
||||||
let user = await parseUserOrId(args.shift() ?? '');
|
|
||||||
if (!user) return message.reply('I can\'t find that user.');
|
|
||||||
if ((user as any)?.bot != null) return message.reply('You cannot warn bots.');
|
|
||||||
|
|
||||||
let reason: string = args.join(' ')
|
const userInput = args.shift();
|
||||||
|
if (!userInput) return message.reply({ embeds: [
|
||||||
|
embed(
|
||||||
|
`Please specify one or more users by replying to their message while running this command or ` +
|
||||||
|
`by specifying a comma-separated list of usernames.`,
|
||||||
|
'No target user specified',
|
||||||
|
EmbedColor.SoftError,
|
||||||
|
),
|
||||||
|
] });
|
||||||
|
|
||||||
|
let reason = args.join(' ')
|
||||||
?.replace(new RegExp('`', 'g'), '\'')
|
?.replace(new RegExp('`', 'g'), '\'')
|
||||||
?.replace(new RegExp('\n', 'g'), ' ')
|
?.replace(new RegExp('\n', 'g'), ' ');
|
||||||
|| 'No reason provided.';
|
|
||||||
if (reason.length > 200) return message.reply('Warn reason may not be longer than 200 characters.');
|
|
||||||
|
|
||||||
let infraction = {
|
if (reason.length > 200) return message.reply({
|
||||||
_id: ulid(),
|
embeds: [ embed('Warn reason may not be longer than 200 characters.', null, EmbedColor.SoftError) ]
|
||||||
createdBy: message.author_id,
|
});
|
||||||
user: user._id,
|
|
||||||
reason: reason,
|
|
||||||
server: message.serverContext._id,
|
|
||||||
type: InfractionType.Manual,
|
|
||||||
date: Date.now(),
|
|
||||||
} as Infraction;
|
|
||||||
|
|
||||||
let { userWarnCount } = await storeInfraction(infraction);
|
const embeds: SendableEmbed[] = [];
|
||||||
|
const handledUsers: string[] = [];
|
||||||
|
const targetUsers: User|{ _id: string }[] = [];
|
||||||
|
|
||||||
await Promise.all([
|
const targetInput = dedupeArray(
|
||||||
message.reply(`### User warned`
|
// Replied messages
|
||||||
+ `${message.serverContext._id != message.channel?.server_id ? ` in **${message.serverContext.name}**` : ''}.\n`
|
(await Promise.allSettled(
|
||||||
+ `This is ${userWarnCount == 1 ? '**the first warn**' : `warn number **${userWarnCount}**`}`
|
(message.reply_ids ?? []).map(msg => message.channel?.fetchMessage(msg))
|
||||||
+ ` for ${await fetchUsername(user._id)}.\n`
|
))
|
||||||
+ `**Infraction ID:** \`${infraction._id}\`\n`
|
.filter(m => m.status == 'fulfilled').map(m => (m as any).value.author_id),
|
||||||
+ `**Reason:** \`${infraction.reason}\``),
|
// Provided users
|
||||||
logModAction('warn', message.serverContext, message.member!, user._id, reason, infraction._id, `This is warn number ${userWarnCount} for this user.`),
|
userInput.split(','),
|
||||||
]);
|
);
|
||||||
|
|
||||||
|
for (const userStr of targetInput) {
|
||||||
|
try {
|
||||||
|
let user = await parseUserOrId(userStr);
|
||||||
|
if (!user) {
|
||||||
|
if (message.reply_ids?.length && userStr == userInput) {
|
||||||
|
reason = reason ? `${userInput} ${reason}` : userInput;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
embeds.push(embed(`I can't resolve \`${sanitizeMessageContent(userStr).trim()}\` to a user.`, null, '#ff785d'));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Silently ignore duplicates
|
||||||
|
if (handledUsers.includes(user._id)) continue;
|
||||||
|
handledUsers.push(user._id);
|
||||||
|
|
||||||
|
if ((user as any)?.bot != null) return await message.reply({ embeds: [
|
||||||
|
embed('You cannot warn bots.', null, EmbedColor.SoftError)
|
||||||
|
]});
|
||||||
|
|
||||||
|
targetUsers.push(user);
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e);
|
||||||
|
embeds.push(embed(
|
||||||
|
`Failed to warn target \`${sanitizeMessageContent(userStr).trim()}\`: ${e}`,
|
||||||
|
'Failed to warn: An error has occurred',
|
||||||
|
EmbedColor.Error,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const user of targetUsers) {
|
||||||
|
let infraction = {
|
||||||
|
_id: ulid(),
|
||||||
|
createdBy: message.author_id,
|
||||||
|
user: user._id,
|
||||||
|
reason: reason || 'No reason provided',
|
||||||
|
server: message.serverContext._id,
|
||||||
|
type: InfractionType.Manual,
|
||||||
|
date: Date.now(),
|
||||||
|
} as Infraction;
|
||||||
|
|
||||||
|
let { userWarnCount } = await storeInfraction(infraction);
|
||||||
|
await logModAction(
|
||||||
|
'warn',
|
||||||
|
message.serverContext,
|
||||||
|
message.member!,
|
||||||
|
user._id,
|
||||||
|
reason || 'No reason provided',
|
||||||
|
infraction._id,
|
||||||
|
`This is warn number ${userWarnCount} for this user.`
|
||||||
|
);
|
||||||
|
|
||||||
|
embeds.push({
|
||||||
|
title: `User warned`,
|
||||||
|
icon_url: user instanceof User ? user.generateAvatarURL() : undefined,
|
||||||
|
colour: EmbedColor.Success,
|
||||||
|
description: `This is ${userWarnCount == 1 ? '**the first warn**' : `warn number **${userWarnCount}**`}` +
|
||||||
|
` for ${await fetchUsername(user._id)}.\n` +
|
||||||
|
`**Infraction ID:** \`${infraction._id}\`\n` +
|
||||||
|
`**Reason:** \`${infraction.reason}\``
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let firstMsg = true;
|
||||||
|
while (embeds.length > 0) {
|
||||||
|
const targetEmbeds = embeds.splice(0, 10);
|
||||||
|
|
||||||
|
if (firstMsg) {
|
||||||
|
await message.reply({ embeds: targetEmbeds, content: 'Operation completed.' }, false);
|
||||||
|
} else {
|
||||||
|
await message.channel?.sendMessage({ embeds: targetEmbeds });
|
||||||
|
}
|
||||||
|
firstMsg = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} as SimpleCommand;
|
} as SimpleCommand;
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { Channel } from "@janderedev/revolt.js/dist/maps/Channels";
|
||||||
import { Permission } from "@janderedev/revolt.js/dist/permissions/definitions";
|
import { Permission } from "@janderedev/revolt.js/dist/permissions/definitions";
|
||||||
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
|
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
|
||||||
import { isSudo } from "./commands/botadm";
|
import { isSudo } from "./commands/botadm";
|
||||||
|
import { SendableEmbed } from "revolt-api";
|
||||||
|
|
||||||
const NO_MANAGER_MSG = '🔒 Missing permission';
|
const NO_MANAGER_MSG = '🔒 Missing permission';
|
||||||
const ULID_REGEX = /^[0-9A-HJ-KM-NP-TV-Z]{26}$/i;
|
const ULID_REGEX = /^[0-9A-HJ-KM-NP-TV-Z]{26}$/i;
|
||||||
|
@ -318,6 +319,33 @@ function sanitizeMessageContent(msg: string): string {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EmbedColor {
|
||||||
|
Error = "#ff450c",
|
||||||
|
SoftError = "#ff785d",
|
||||||
|
Warning = "#ffda55",
|
||||||
|
Success = "#23ff91",
|
||||||
|
}
|
||||||
|
|
||||||
|
function embed(content: string, title?: string|null, color?: string|EmbedColor): SendableEmbed {
|
||||||
|
return {
|
||||||
|
description: content,
|
||||||
|
title: title,
|
||||||
|
colour: color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dedupeArray<T>(...arrays: T[][]): T[] {
|
||||||
|
const found: T[] = [];
|
||||||
|
|
||||||
|
for (const array of arrays) {
|
||||||
|
for (const item of array) {
|
||||||
|
if (!found.includes(item)) found.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAutumnURL,
|
getAutumnURL,
|
||||||
hasPerm,
|
hasPerm,
|
||||||
|
@ -333,6 +361,9 @@ export {
|
||||||
uploadFile,
|
uploadFile,
|
||||||
sanitizeMessageContent,
|
sanitizeMessageContent,
|
||||||
sendLogMessage,
|
sendLogMessage,
|
||||||
|
embed,
|
||||||
|
dedupeArray,
|
||||||
|
EmbedColor,
|
||||||
NO_MANAGER_MSG,
|
NO_MANAGER_MSG,
|
||||||
ULID_REGEX,
|
ULID_REGEX,
|
||||||
USER_MENTION_REGEX,
|
USER_MENTION_REGEX,
|
||||||
|
|
Loading…
Reference in a new issue