- Fixed member requirement for Mute command

- Fixing other random shit
- Limit TIME to Max32BitInt
- Adding case delete commandoption
This commit is contained in:
D3vision 2023-12-07 23:29:00 +01:00
parent c8fb823b05
commit 427f07c5bb
8 changed files with 602 additions and 569 deletions

View File

@ -6,6 +6,7 @@ import { inspect } from 'util';
import Util from '../../../../utilities/Util.js';
import { EmbedDefaultColor, InfractionColors } from '../../../../constants/Constants.js';
import { APIEmbed, GuildChannel, User } from 'discord.js';
import Infraction from '../../../interfaces/Infraction.js';
class CaseCommand extends SlashCommand
{
@ -22,12 +23,13 @@ class CaseCommand extends SlashCommand
minimum: 0,
required: true
}, {
name: [ 'export', 'verbose', 'changes' ], //
name: [ 'export', 'verbose', 'changes', 'delete' ], //
type: CommandOptionType.BOOLEAN,
description: [
'Print out raw infraction data in JSON form',
'Print out more detailed information about the case',
'List changes to the case'
'List changes to the case',
'Delete the case'
],
dependsOn: [ 'id' ],
flag: true,
@ -41,24 +43,32 @@ class CaseCommand extends SlashCommand
});
}
async execute (invoker: InvokerWrapper, opts: CommandParams)
async execute (invoker: InvokerWrapper<true>, opts: CommandParams)
{
const { id, verbose, export: exp, changes } = opts;
const { id, verbose, export: exp, changes, delete: remove } = opts;
const guild = invoker.guild!;
const infraction = await this.client.storageManager.mongodb.infractions.findOne({
id: `${guild.id}:${id?.asNumber}`
}, { projection: { _id: 0 } });
const infraction = await new Infraction(this.client, this.logger, { guild, case: id!.asNumber }).fetch(true).catch(() => null);
if (!infraction)
return { emoji: 'failure', index: 'COMMAND_CASE_NOTFOUND', params: { caseID: id!.asNumber } };
if (remove?.asBool === true)
{
if (!invoker.member?.permissions.has('Administrator'))
return { emoji: 'failure', index: 'ERR_MISSING_PERMISSIONS' };
await infraction.resolve(invoker.member, invoker.format('COMMAND_CASE_DELETED_LOG'), false);
await this.client.storageManager.mongodb.infractions.deleteOne({
id: `${guild.id}:${id?.asNumber}`
});
return { emoji: 'success', index: 'COMMAND_CASE_DELETED', params: { caseID: id!.asNumber } };
}
if (exp?.asString)
return `\`\`\`js\n${inspect(infraction)}\`\`\``;
if (changes?.asString)
return { embed: await this._listChanges(invoker, infraction) };
return { embed: await this._listChanges(invoker, infraction.json) };
const target = infraction.targetType === 'USER' ? await this.client.resolver.resolveUser(infraction.target) : await guild.resolveChannel(infraction.target);
const staff = await this.client.resolver.resolveUser(infraction.executor);
const target = infraction.targetType === 'USER' ? await this.client.resolver.resolveUser(infraction.targetId!) : await guild.resolveChannel(infraction.targetId);
const staff = await this.client.resolver.resolveUser(infraction.executor!);
let index = 'COMMAND_CASE_TEMPLATE',
caseTitleIndex = 'COMMAND_CASE_TITLE',
@ -75,7 +85,7 @@ class CaseCommand extends SlashCommand
targetUserIndex += '_VERBOSE';
targetChannelIndex += '_VERBOSE';
}
const { json } = infraction;
let description = invoker.format(index, {
uniqueID: infraction.id,
type: infraction.type,
@ -86,25 +96,25 @@ class CaseCommand extends SlashCommand
target: infraction.targetType === 'USER' ? invoker.format(targetUserIndex, { target: (target as User).tag, targetID: target!.id }) : invoker.format(targetChannelIndex, { target: (target as GuildChannel).name, targetID: target!.id }),
staff: staff?.tag??'N/A',
staffID: staff?.id??'N/A',
nrChanges: infraction.changes?.length || 0,
changes: infraction.changes?.map((change) => change.type).join(', ') || 'N/A',
nrChanges: json.changes?.length || 0,
changes: json.changes?.map((change) => change.type).join(', ') || 'N/A',
guild: guild.id,
channel: infraction.channel,
message: infraction.message
channel: json.channel,
message: json.message
});
if (infraction.data?.seconds)
description += '\n' + invoker.format(caseSlowmodeIndex, { readable: Util.humanise(infraction.data.seconds), seconds: infraction.data.seconds });
if (infraction.duration !== null)
if (json.duration !== null)
{
const duration = Math.floor(infraction.duration / 1000);
const duration = Math.floor(json.duration / 1000);
description += '\n' + invoker.format(caseLengthIndex, { time: Util.humanise(duration), inSeconds: duration });
}
if (guild._settings.modpoints.enabled)
description += '\n' + invoker.format('COMMAND_CASE_MODPOINTS', {
points: infraction.points,
expires: infraction.expiration ? `<t:${Math.round(infraction.expiration / 1000)}:R>` : false
expires: json.expiration ? `<t:${Math.round(json.expiration / 1000)}:R>` : false
});
description += '\n\n' + invoker.format('COMMAND_CASE_REASON', { reason: infraction.reason });

View File

@ -3,7 +3,7 @@ import DiscordClient from '../../../DiscordClient.js';
import { Mute } from '../../../infractions/index.js';
import { CommandError, ModerationCommand } from '../../../interfaces/index.js';
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
import UserWrapper from '../../wrappers/UserWrapper.js';
import MemberWrapper from '../../wrappers/MemberWrapper.js';
class MuteCommand extends ModerationCommand
{
@ -41,9 +41,9 @@ class MuteCommand extends ModerationCommand
else if (!me!.permissions.has('ManageRoles'))
throw new CommandError(invoker, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', formatParams: { command: this.name, missing: 'ManageRoles' } });
const wrappers = await Promise.all(users.asUsers.map(user => this.client.getUserWrapper(user)));
const wrappers = await Promise.all(users!.asUsers.map(user => guild.memberWrapper(user)));
return this.client.moderation.handleInfraction(Mute, invoker, {
targets: wrappers.filter(Boolean) as UserWrapper[],
targets: wrappers.filter(Boolean) as MemberWrapper[],
args
});

View File

@ -3,7 +3,7 @@ import DiscordClient from '../../../DiscordClient.js';
import { Nickname } from '../../../infractions/index.js';
import { CommandError, ModerationCommand } from '../../../interfaces/index.js';
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
import UserWrapper from '../../wrappers/UserWrapper.js';
import MemberWrapper from '../../wrappers/MemberWrapper.js';
class NicknameCommand extends ModerationCommand
{
@ -28,15 +28,15 @@ class NicknameCommand extends ModerationCommand
}
async execute (invoker: InvokerWrapper, { users, name, ...args }: CommandParams)
async execute (invoker: InvokerWrapper<true>, { users, name, ...args }: CommandParams)
{
if (!users)
throw new CommandError(invoker, { index: 'MODERATION_MISSING_USERS' });
const wrappers = await Promise.all(users.asUsers.map(user => this.client.getUserWrapper(user)));
const wrappers = await Promise.all(users!.asUsers.map(user => invoker.guild.memberWrapper(user)));
return this.client.moderation.handleInfraction(Nickname, invoker, {
targets: wrappers.filter(Boolean) as UserWrapper[],
targets: wrappers.filter(Boolean) as MemberWrapper[],
args,
data: {
name: name?.asString

View File

@ -21,7 +21,6 @@ class MuteInfraction extends Infraction
}
member?: MemberWrapper;
duration?: number;
constructor (client: DiscordClient, logger: LoggerClient, opts: MuteData)
{
@ -52,10 +51,7 @@ class MuteInfraction extends Infraction
this.member = opts.target;
const { mute } = this.guild._settings;
if (!this.duration && (!mute.permanent || mute.type === MuteType.Timeout))
{
this.duration = mute.default * 1000;
}
}
}
@ -277,6 +273,7 @@ class MuteInfraction extends Infraction
break;
}
}
await super.resolve(_staff, _reason, _notify);
return { message, error };
}

View File

@ -8,6 +8,7 @@ import Command from './commands/Command.js';
import moment from 'moment';
import { GuildBasedChannel, GuildMember, Role, User } from 'discord.js';
import Module from './Module.js';
import { Max32BitInt } from '../../constants/Constants.js';
const PointsReg = /^([-+]?[0-9]+) ?(points|point|pts|pt|p)$/iu;
const ChannelType: {[key: string]: number} = {
@ -100,6 +101,8 @@ class CommandOption
this.#minimum = options.minimum;
if (typeof options.maximum === 'number')
this.#maximum = options.maximum;
if (typeof this.#maximum === 'undefined' || this.#maximum > Number.MAX_SAFE_INTEGER)
this.#maximum = Number.MAX_SAFE_INTEGER;
this.#slashOption = options.slashOption || false;
this.#flag = options.flag ?? false; // used with message based command options
@ -277,7 +280,7 @@ class CommandOption
POINTS: async () =>
{
if (this.slashOption)
return { value: this.#rawValue };
return { value: parseInt(this.#rawValue as string) };
let value = null,
removed = null;
if (!this.#rawValue)
@ -470,6 +473,8 @@ class CommandOption
const value = this.client.resolver.resolveTime(this.#rawValue);
if (value === null)
return { error: true };
if ((value*1000) > Max32BitInt)
return { error: true, index: 'O_COMMANDHANDLER_TYPETIME_MAX', params: { maximum: Util.humanise(Max32BitInt/1000) } };
if (typeof this.#maximum !== 'undefined' && value > this.#maximum)
return { error: true, index: 'O_COMMANDHANDLER_TYPETIME_MAX', params: { maximum: Util.humanise(this.#maximum) } };
return { value, removed: [ this.#rawValue ] };

View File

@ -244,9 +244,12 @@ class Infraction
async save ()
{
const { json } = this;
const filter: {id: string, _id?: ObjectId} = { id: this.id };
if (this.#mongoId)
filter._id = this.#mongoId;
if (json.points && typeof json.points !== 'number')
throw new Error('Invalid points type');
return this.#client.mongodb.infractions.updateOne(filter, { $set: this.json })
.catch((error: Error) =>
{
@ -566,6 +569,16 @@ class Infraction
return InfractionColors[this.#type!];
}
get duration ()
{
return this.#duration;
}
set duration (duration: number | null)
{
this.#duration = duration;
}
// Super Functions
protected _succeed (): InfractionSuccess
{

View File

@ -2,6 +2,7 @@ import { InfractionType } from "../../@types/Client.js";
const ZeroWidthChar = '\u200b';
const EmbedDefaultColor = 619452;
const Max32BitInt = 2147483647;
const UploadLimit = {
'0': 8,
@ -235,6 +236,7 @@ export {
UploadLimit,
ZeroWidthChar,
EmbedDefaultColor,
Max32BitInt,
PermissionNames,
EmbedLimits,
InfractionResolves,

View File

@ -369,6 +369,12 @@ View a specific case
[COMMAND_CASE_NOTFOUND]
No case matching ID `{caseID}` was found.
[COMMAND_CASE_DELETED]
Case `{caseID}` was deleted.
[COMMAND_CASE_DELETED_LOG]
Case deleted.
[COMMAND_CASE_TITLE]
{emoji_book} Case **#{caseID}**