Overwritting permissions for child commands (#269)

This commit is contained in:
Marcos Susaña 2024-10-02 18:16:16 -04:00 committed by GitHub
parent 44c872de71
commit 71cab8721e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 81 additions and 36 deletions

View File

@ -1,11 +1,11 @@
import type { FlatObjectKeys, PermissionStrings } from '../common';
import { PermissionsBitField } from '../structures/extra/Permissions';
import {
ApplicationCommandType,
ApplicationIntegrationType,
type EntryPointCommandHandlerType,
InteractionContextType,
type LocaleString,
PermissionFlagsBits,
} from '../types';
import type { CommandOption, OptionsRecord, SubCommand } from './applications/chat';
import type { DefaultLocale, ExtraProps, IgnoreCommand, MiddlewareContext } from './applications/shared';
@ -159,11 +159,11 @@ export function Declare(declare: CommandDeclareOptions) {
integrationTypes = declare.integrationTypes?.map(i => ApplicationIntegrationType[i]) ?? [
ApplicationIntegrationType.GuildInstall,
];
defaultMemberPermissions = Array.isArray(declare.defaultMemberPermissions)
? declare.defaultMemberPermissions?.reduce((acc, prev) => acc | PermissionFlagsBits[prev], BigInt(0))
defaultMemberPermissions = declare.defaultMemberPermissions
? PermissionsBitField.resolve(declare.defaultMemberPermissions)
: declare.defaultMemberPermissions;
botPermissions = Array.isArray(declare.botPermissions)
? declare.botPermissions?.reduce((acc, prev) => acc | PermissionFlagsBits[prev], BigInt(0))
botPermissions = declare.botPermissions
? PermissionsBitField.resolve(declare.botPermissions)
: declare.botPermissions;
description = '';
type: ApplicationCommandType = ApplicationCommandType.ChatInput;

View File

@ -169,10 +169,18 @@ export class HandleCommand {
resolver: OptionResolverStructure,
context: CommandContext,
) {
if (context.guildId && command.botPermissions && interaction.appPermissions) {
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
if (permissions) return command.onBotPermissionsFail?.(context, permissions);
if (context.guildId && interaction.appPermissions) {
if (command.botPermissions) {
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
if (permissions) return command.onBotPermissionsFail?.(context, permissions);
}
if (command.defaultMemberPermissions) {
const permissions = this.checkPermissions(interaction.member!.permissions, command.defaultMemberPermissions);
if (permissions) return command.onPermissionsFail?.(context, permissions);
}
}
if (!(await this.runOptions(command, context, resolver))) return;
const resultGlobal = await this.runGlobalMiddlewares(command, context);

View File

@ -3,6 +3,7 @@ import { basename, dirname } from 'node:path';
import type { EntryPointCommand } from '.';
import type { Logger, MakeRequired, NulleableCoalising, OmitInsert } from '../common';
import { BaseHandler, isCloudfareWorker } from '../common';
import { PermissionsBitField } from '../structures/extra/Permissions';
import {
type APIApplicationCommandChannelOption,
type APIApplicationCommandIntegerOption,
@ -483,8 +484,14 @@ export class CommandHandler extends BaseHandler {
option.onPermissionsFail?.bind(option) ??
commandInstance.onPermissionsFail?.bind(commandInstance) ??
this.client.options.commands?.defaults?.onPermissionsFail;
option.botPermissions ??= commandInstance.botPermissions;
option.defaultMemberPermissions ??= commandInstance.defaultMemberPermissions;
option.botPermissions = PermissionsBitField.add(
option.botPermissions ?? PermissionsBitField.None,
commandInstance.botPermissions,
);
option.defaultMemberPermissions ??= PermissionsBitField.add(
option.defaultMemberPermissions ?? PermissionsBitField.None,
commandInstance.defaultMemberPermissions,
);
option.contexts ??= commandInstance.contexts;
option.integrationTypes ??= commandInstance.integrationTypes;
option.props ??= commandInstance.props;

View File

@ -18,24 +18,19 @@ export class BitField<T extends object> {
return this.bit;
}
add(...bits: BitFieldResolvable<T>[]): bigint {
let reduced = BitField.None;
add(...bits: (BitFieldResolvable<T> | undefined)[]): bigint {
for (const bit of bits) {
reduced |= this.resolve(bit);
if (!bit) continue;
this.bit |= this.resolve(bit);
}
return (this.bit |= reduced);
return this.bit;
}
remove(...bits: BitFieldResolvable<T>[]): bigint {
let reduced = BitField.None;
for (const bit of bits) {
reduced |= this.resolve(bit);
this.bit &= ~this.resolve(bit);
}
return (this.bit &= ~reduced);
return this.bit;
}
has(...bits: BitFieldResolvable<T>[]) {
@ -52,27 +47,17 @@ export class BitField<T extends object> {
return this.bits === this.resolve(other);
}
resolve(bits?: BitFieldResolvable<T>): bigint {
resolve(bits: BitFieldResolvable<T>): bigint {
switch (typeof bits) {
case 'number':
return BigInt(bits);
case 'string':
return this.resolve(this.Flags[bits]);
case 'bigint':
return bits;
case 'object': {
if (!Array.isArray(bits)) {
throw new TypeError(`Cannot resolve permission: ${bits}`);
}
return bits.map(x => this.resolve(x)).reduce((acc, cur) => acc | cur, BitField.None);
}
return BitField.resolve(this.Flags[bits]);
default:
throw new TypeError(`Cannot resolve permission: ${typeof bits === 'symbol' ? String(bits) : (bits as any)}`);
return BitField.resolve<T>(bits);
}
}
keys(bits: BitFieldResolvable<T>[] = [this.bits]) {
const bitsResolved = bits.map(bit => BigInt(this.resolve(bit)));
const bitsResolved = bits.map(bit => this.resolve(bit));
return Object.entries(this.Flags).reduce((acc, value) => {
if (bitsResolved.some(bit => (bit & value[1]) === value[1])) {
acc.push(value[0]);
@ -83,7 +68,7 @@ export class BitField<T extends object> {
}
values(bits: BitFieldResolvable<T>[] = [this.bits]) {
const bitsResolved = bits.map(bit => BigInt(this.resolve(bit)));
const bitsResolved = bits.map(bit => this.resolve(bit));
return Object.entries(this.Flags).reduce((acc, value) => {
if (bitsResolved.some(bit => (bit & value[1]) === value[1])) {
acc.push(value[1]);
@ -92,4 +77,40 @@ export class BitField<T extends object> {
return acc;
}, [] as bigint[]);
}
static add<T extends object>(base: BitFieldResolvable<T>, ...bits: (BitFieldResolvable<T> | undefined)[]) {
base = BitField.resolve(base);
for (const bit of bits) {
if (!bit) continue;
base |= BitField.resolve(bit);
}
return base;
}
static remove<T extends object>(base: BitFieldResolvable<T>, ...bits: BitFieldResolvable<T>[]): bigint {
base = BitField.resolve(base);
for (const bit of bits) {
base &= ~BitField.resolve(bit);
}
return base;
}
static resolve<T extends object>(bits: BitFieldResolvable<T>): bigint {
switch (typeof bits) {
case 'number':
return BigInt(bits);
case 'bigint':
return bits;
case 'object': {
if (!Array.isArray(bits)) {
throw new TypeError(`Cannot resolve permission: ${bits}`);
}
return bits.map(x => BitField.resolve(x)).reduce((acc, cur) => acc | cur, BitField.None);
}
default:
throw new TypeError(`Cannot resolve permission: ${typeof bits === 'symbol' ? String(bits) : (bits as any)}`);
}
}
}

View File

@ -20,4 +20,13 @@ export class PermissionsBitField extends BitField<typeof PermissionFlagsBits> {
strictHas(...bits: BitFieldResolvable<typeof PermissionFlagsBits>[]) {
return super.has(...bits);
}
static resolve<T extends object = typeof PermissionFlagsBits>(bits: BitFieldResolvable<T>): bigint {
switch (typeof bits) {
case 'string':
return PermissionsBitField.resolve(PermissionFlagsBits[bits as keyof typeof PermissionFlagsBits]);
default:
return BitField.resolve(bits);
}
}
}