forked from Galactic/galactic-bot
- Fixed member requirement for Mute command
- Fixing other random shit - Limit TIME to Max32BitInt - Adding case delete commandoption
This commit is contained in:
parent
c8fb823b05
commit
427f07c5bb
@ -6,6 +6,7 @@ import { inspect } from 'util';
|
|||||||
import Util from '../../../../utilities/Util.js';
|
import Util from '../../../../utilities/Util.js';
|
||||||
import { EmbedDefaultColor, InfractionColors } from '../../../../constants/Constants.js';
|
import { EmbedDefaultColor, InfractionColors } from '../../../../constants/Constants.js';
|
||||||
import { APIEmbed, GuildChannel, User } from 'discord.js';
|
import { APIEmbed, GuildChannel, User } from 'discord.js';
|
||||||
|
import Infraction from '../../../interfaces/Infraction.js';
|
||||||
|
|
||||||
class CaseCommand extends SlashCommand
|
class CaseCommand extends SlashCommand
|
||||||
{
|
{
|
||||||
@ -22,12 +23,13 @@ class CaseCommand extends SlashCommand
|
|||||||
minimum: 0,
|
minimum: 0,
|
||||||
required: true
|
required: true
|
||||||
}, {
|
}, {
|
||||||
name: [ 'export', 'verbose', 'changes' ], //
|
name: [ 'export', 'verbose', 'changes', 'delete' ], //
|
||||||
type: CommandOptionType.BOOLEAN,
|
type: CommandOptionType.BOOLEAN,
|
||||||
description: [
|
description: [
|
||||||
'Print out raw infraction data in JSON form',
|
'Print out raw infraction data in JSON form',
|
||||||
'Print out more detailed information about the case',
|
'Print out more detailed information about the case',
|
||||||
'List changes to the case'
|
'List changes to the case',
|
||||||
|
'Delete the case'
|
||||||
],
|
],
|
||||||
dependsOn: [ 'id' ],
|
dependsOn: [ 'id' ],
|
||||||
flag: true,
|
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 guild = invoker.guild!;
|
||||||
|
|
||||||
const infraction = await this.client.storageManager.mongodb.infractions.findOne({
|
const infraction = await new Infraction(this.client, this.logger, { guild, case: id!.asNumber }).fetch(true).catch(() => null);
|
||||||
id: `${guild.id}:${id?.asNumber}`
|
|
||||||
}, { projection: { _id: 0 } });
|
|
||||||
|
|
||||||
if (!infraction)
|
if (!infraction)
|
||||||
return { emoji: 'failure', index: 'COMMAND_CASE_NOTFOUND', params: { caseID: id!.asNumber } };
|
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)
|
if (exp?.asString)
|
||||||
return `\`\`\`js\n${inspect(infraction)}\`\`\``;
|
return `\`\`\`js\n${inspect(infraction)}\`\`\``;
|
||||||
if (changes?.asString)
|
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 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);
|
const staff = await this.client.resolver.resolveUser(infraction.executor!);
|
||||||
|
|
||||||
let index = 'COMMAND_CASE_TEMPLATE',
|
let index = 'COMMAND_CASE_TEMPLATE',
|
||||||
caseTitleIndex = 'COMMAND_CASE_TITLE',
|
caseTitleIndex = 'COMMAND_CASE_TITLE',
|
||||||
@ -75,7 +85,7 @@ class CaseCommand extends SlashCommand
|
|||||||
targetUserIndex += '_VERBOSE';
|
targetUserIndex += '_VERBOSE';
|
||||||
targetChannelIndex += '_VERBOSE';
|
targetChannelIndex += '_VERBOSE';
|
||||||
}
|
}
|
||||||
|
const { json } = infraction;
|
||||||
let description = invoker.format(index, {
|
let description = invoker.format(index, {
|
||||||
uniqueID: infraction.id,
|
uniqueID: infraction.id,
|
||||||
type: infraction.type,
|
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 }),
|
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',
|
staff: staff?.tag??'N/A',
|
||||||
staffID: staff?.id??'N/A',
|
staffID: staff?.id??'N/A',
|
||||||
nrChanges: infraction.changes?.length || 0,
|
nrChanges: json.changes?.length || 0,
|
||||||
changes: infraction.changes?.map((change) => change.type).join(', ') || 'N/A',
|
changes: json.changes?.map((change) => change.type).join(', ') || 'N/A',
|
||||||
guild: guild.id,
|
guild: guild.id,
|
||||||
channel: infraction.channel,
|
channel: json.channel,
|
||||||
message: infraction.message
|
message: json.message
|
||||||
});
|
});
|
||||||
|
|
||||||
if (infraction.data?.seconds)
|
if (infraction.data?.seconds)
|
||||||
description += '\n' + invoker.format(caseSlowmodeIndex, { readable: Util.humanise(infraction.data.seconds), seconds: 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 });
|
description += '\n' + invoker.format(caseLengthIndex, { time: Util.humanise(duration), inSeconds: duration });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guild._settings.modpoints.enabled)
|
if (guild._settings.modpoints.enabled)
|
||||||
description += '\n' + invoker.format('COMMAND_CASE_MODPOINTS', {
|
description += '\n' + invoker.format('COMMAND_CASE_MODPOINTS', {
|
||||||
points: infraction.points,
|
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 });
|
description += '\n\n' + invoker.format('COMMAND_CASE_REASON', { reason: infraction.reason });
|
||||||
|
@ -3,7 +3,7 @@ import DiscordClient from '../../../DiscordClient.js';
|
|||||||
import { Mute } from '../../../infractions/index.js';
|
import { Mute } from '../../../infractions/index.js';
|
||||||
import { CommandError, ModerationCommand } from '../../../interfaces/index.js';
|
import { CommandError, ModerationCommand } from '../../../interfaces/index.js';
|
||||||
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
|
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
|
||||||
import UserWrapper from '../../wrappers/UserWrapper.js';
|
import MemberWrapper from '../../wrappers/MemberWrapper.js';
|
||||||
|
|
||||||
class MuteCommand extends ModerationCommand
|
class MuteCommand extends ModerationCommand
|
||||||
{
|
{
|
||||||
@ -41,9 +41,9 @@ class MuteCommand extends ModerationCommand
|
|||||||
else if (!me!.permissions.has('ManageRoles'))
|
else if (!me!.permissions.has('ManageRoles'))
|
||||||
throw new CommandError(invoker, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', formatParams: { command: this.name, missing: '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, {
|
return this.client.moderation.handleInfraction(Mute, invoker, {
|
||||||
targets: wrappers.filter(Boolean) as UserWrapper[],
|
targets: wrappers.filter(Boolean) as MemberWrapper[],
|
||||||
args
|
args
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import DiscordClient from '../../../DiscordClient.js';
|
|||||||
import { Nickname } from '../../../infractions/index.js';
|
import { Nickname } from '../../../infractions/index.js';
|
||||||
import { CommandError, ModerationCommand } from '../../../interfaces/index.js';
|
import { CommandError, ModerationCommand } from '../../../interfaces/index.js';
|
||||||
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
|
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
|
||||||
import UserWrapper from '../../wrappers/UserWrapper.js';
|
import MemberWrapper from '../../wrappers/MemberWrapper.js';
|
||||||
|
|
||||||
class NicknameCommand extends ModerationCommand
|
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)
|
if (!users)
|
||||||
throw new CommandError(invoker, { index: 'MODERATION_MISSING_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, {
|
return this.client.moderation.handleInfraction(Nickname, invoker, {
|
||||||
targets: wrappers.filter(Boolean) as UserWrapper[],
|
targets: wrappers.filter(Boolean) as MemberWrapper[],
|
||||||
args,
|
args,
|
||||||
data: {
|
data: {
|
||||||
name: name?.asString
|
name: name?.asString
|
||||||
|
@ -21,7 +21,6 @@ class MuteInfraction extends Infraction
|
|||||||
}
|
}
|
||||||
|
|
||||||
member?: MemberWrapper;
|
member?: MemberWrapper;
|
||||||
duration?: number;
|
|
||||||
|
|
||||||
constructor (client: DiscordClient, logger: LoggerClient, opts: MuteData)
|
constructor (client: DiscordClient, logger: LoggerClient, opts: MuteData)
|
||||||
{
|
{
|
||||||
@ -52,10 +51,7 @@ class MuteInfraction extends Infraction
|
|||||||
this.member = opts.target;
|
this.member = opts.target;
|
||||||
const { mute } = this.guild._settings;
|
const { mute } = this.guild._settings;
|
||||||
if (!this.duration && (!mute.permanent || mute.type === MuteType.Timeout))
|
if (!this.duration && (!mute.permanent || mute.type === MuteType.Timeout))
|
||||||
{
|
|
||||||
this.duration = mute.default * 1000;
|
this.duration = mute.default * 1000;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -277,6 +273,7 @@ class MuteInfraction extends Infraction
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await super.resolve(_staff, _reason, _notify);
|
||||||
return { message, error };
|
return { message, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import Command from './commands/Command.js';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { GuildBasedChannel, GuildMember, Role, User } from 'discord.js';
|
import { GuildBasedChannel, GuildMember, Role, User } from 'discord.js';
|
||||||
import Module from './Module.js';
|
import Module from './Module.js';
|
||||||
|
import { Max32BitInt } from '../../constants/Constants.js';
|
||||||
|
|
||||||
const PointsReg = /^([-+]?[0-9]+) ?(points|point|pts|pt|p)$/iu;
|
const PointsReg = /^([-+]?[0-9]+) ?(points|point|pts|pt|p)$/iu;
|
||||||
const ChannelType: {[key: string]: number} = {
|
const ChannelType: {[key: string]: number} = {
|
||||||
@ -100,6 +101,8 @@ class CommandOption
|
|||||||
this.#minimum = options.minimum;
|
this.#minimum = options.minimum;
|
||||||
if (typeof options.maximum === 'number')
|
if (typeof options.maximum === 'number')
|
||||||
this.#maximum = options.maximum;
|
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.#slashOption = options.slashOption || false;
|
||||||
this.#flag = options.flag ?? false; // used with message based command options
|
this.#flag = options.flag ?? false; // used with message based command options
|
||||||
@ -277,7 +280,7 @@ class CommandOption
|
|||||||
POINTS: async () =>
|
POINTS: async () =>
|
||||||
{
|
{
|
||||||
if (this.slashOption)
|
if (this.slashOption)
|
||||||
return { value: this.#rawValue };
|
return { value: parseInt(this.#rawValue as string) };
|
||||||
let value = null,
|
let value = null,
|
||||||
removed = null;
|
removed = null;
|
||||||
if (!this.#rawValue)
|
if (!this.#rawValue)
|
||||||
@ -470,6 +473,8 @@ class CommandOption
|
|||||||
const value = this.client.resolver.resolveTime(this.#rawValue);
|
const value = this.client.resolver.resolveTime(this.#rawValue);
|
||||||
if (value === null)
|
if (value === null)
|
||||||
return { error: true };
|
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)
|
if (typeof this.#maximum !== 'undefined' && value > this.#maximum)
|
||||||
return { error: true, index: 'O_COMMANDHANDLER_TYPETIME_MAX', params: { maximum: Util.humanise(this.#maximum) } };
|
return { error: true, index: 'O_COMMANDHANDLER_TYPETIME_MAX', params: { maximum: Util.humanise(this.#maximum) } };
|
||||||
return { value, removed: [ this.#rawValue ] };
|
return { value, removed: [ this.#rawValue ] };
|
||||||
|
@ -244,9 +244,12 @@ class Infraction
|
|||||||
|
|
||||||
async save ()
|
async save ()
|
||||||
{
|
{
|
||||||
|
const { json } = this;
|
||||||
const filter: {id: string, _id?: ObjectId} = { id: this.id };
|
const filter: {id: string, _id?: ObjectId} = { id: this.id };
|
||||||
if (this.#mongoId)
|
if (this.#mongoId)
|
||||||
filter._id = 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 })
|
return this.#client.mongodb.infractions.updateOne(filter, { $set: this.json })
|
||||||
.catch((error: Error) =>
|
.catch((error: Error) =>
|
||||||
{
|
{
|
||||||
@ -566,6 +569,16 @@ class Infraction
|
|||||||
return InfractionColors[this.#type!];
|
return InfractionColors[this.#type!];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get duration ()
|
||||||
|
{
|
||||||
|
return this.#duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
set duration (duration: number | null)
|
||||||
|
{
|
||||||
|
this.#duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
// Super Functions
|
// Super Functions
|
||||||
protected _succeed (): InfractionSuccess
|
protected _succeed (): InfractionSuccess
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@ import { InfractionType } from "../../@types/Client.js";
|
|||||||
|
|
||||||
const ZeroWidthChar = '\u200b';
|
const ZeroWidthChar = '\u200b';
|
||||||
const EmbedDefaultColor = 619452;
|
const EmbedDefaultColor = 619452;
|
||||||
|
const Max32BitInt = 2147483647;
|
||||||
|
|
||||||
const UploadLimit = {
|
const UploadLimit = {
|
||||||
'0': 8,
|
'0': 8,
|
||||||
@ -235,6 +236,7 @@ export {
|
|||||||
UploadLimit,
|
UploadLimit,
|
||||||
ZeroWidthChar,
|
ZeroWidthChar,
|
||||||
EmbedDefaultColor,
|
EmbedDefaultColor,
|
||||||
|
Max32BitInt,
|
||||||
PermissionNames,
|
PermissionNames,
|
||||||
EmbedLimits,
|
EmbedLimits,
|
||||||
InfractionResolves,
|
InfractionResolves,
|
||||||
|
@ -369,6 +369,12 @@ View a specific case
|
|||||||
[COMMAND_CASE_NOTFOUND]
|
[COMMAND_CASE_NOTFOUND]
|
||||||
No case matching ID `{caseID}` was found.
|
No case matching ID `{caseID}` was found.
|
||||||
|
|
||||||
|
[COMMAND_CASE_DELETED]
|
||||||
|
Case `{caseID}` was deleted.
|
||||||
|
|
||||||
|
[COMMAND_CASE_DELETED_LOG]
|
||||||
|
Case deleted.
|
||||||
|
|
||||||
[COMMAND_CASE_TITLE]
|
[COMMAND_CASE_TITLE]
|
||||||
{emoji_book} Case **#{caseID}**
|
{emoji_book} Case **#{caseID}**
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user