feat(commands): replace texts with events, add whitelisting
This commit is contained in:
parent
f6393c8226
commit
7835162fd5
15 changed files with 238 additions and 142 deletions
|
@ -3,6 +3,7 @@ import { GuildPayload } from '../../types/guild.ts'
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
|
||||
export const ready: GatewayEventHandler = async (gateway: Gateway, d: any) => {
|
||||
await gateway.client.guilds.flush()
|
||||
gateway.client.user = new User(gateway.client, d.user)
|
||||
gateway.sessionID = d.session_id
|
||||
gateway.debug(`Received READY. Session: ${gateway.sessionID}`)
|
||||
|
|
|
@ -20,7 +20,7 @@ export class MemberRolesManager extends BaseChildManager<
|
|||
async get (id: string): Promise<Role | undefined> {
|
||||
const res = await this.parent.get(id)
|
||||
const mem = await (this.parent as any).guild.members._get(this.member.id) as MemberPayload
|
||||
if (res !== undefined && mem.roles.includes(res.id) === true) return res
|
||||
if (res !== undefined && (mem.roles.includes(res.id) === true || res.id === this.member.guild.id)) return res
|
||||
else return undefined
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export class MemberRolesManager extends BaseChildManager<
|
|||
const arr = (await this.parent.array()) as Role[]
|
||||
const mem = await (this.parent as any).guild.members._get(this.member.id) as MemberPayload
|
||||
return arr.filter(
|
||||
(c: any) => mem.roles.includes(c.id)
|
||||
(c: any) => mem.roles.includes(c.id) as boolean || c.id === this.member.guild.id
|
||||
) as any
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Member } from '../structures/member.ts'
|
|||
import { GUILD_MEMBER } from '../types/endpoint.ts'
|
||||
import { MemberPayload } from '../types/guild.ts'
|
||||
import { BaseManager } from './base.ts'
|
||||
import { Permissions } from "../utils/permissions.ts"
|
||||
|
||||
export class MembersManager extends BaseManager<MemberPayload, Member> {
|
||||
guild: Guild
|
||||
|
@ -14,11 +15,17 @@ export class MembersManager extends BaseManager<MemberPayload, Member> {
|
|||
this.guild = guild
|
||||
}
|
||||
|
||||
async get (key: string): Promise<Member | undefined> {
|
||||
async get(key: string): Promise<Member | undefined> {
|
||||
const raw = await this._get(key)
|
||||
if (raw === undefined) return
|
||||
const user = new User(this.client, raw.user)
|
||||
const res = new this.DataType(this.client, raw, user, this.guild)
|
||||
const roles = await this.guild.roles.array()
|
||||
let permissions = new Permissions(Permissions.DEFAULT)
|
||||
if (roles !== undefined) {
|
||||
const mRoles = roles.filter(r => raw.roles.includes(r.id) as boolean || r.id === this.guild.id)
|
||||
permissions = new Permissions(mRoles.map(r => r.permissions))
|
||||
}
|
||||
const res = new this.DataType(this.client, raw, user, this.guild, permissions)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -27,7 +34,13 @@ export class MembersManager extends BaseManager<MemberPayload, Member> {
|
|||
this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(async data => {
|
||||
await this.set(id, data as MemberPayload)
|
||||
const user: User = new User(this.client, data.user)
|
||||
const res = new Member(this.client, data as MemberPayload, user, this.guild)
|
||||
const roles = await this.guild.roles.array()
|
||||
let permissions = new Permissions(Permissions.DEFAULT)
|
||||
if (roles !== undefined) {
|
||||
const mRoles = roles.filter(r => data.roles.includes(r.id) as boolean || r.id === this.guild.id)
|
||||
permissions = new Permissions(mRoles.map(r => r.permissions))
|
||||
}
|
||||
const res = new Member(this.client, data as MemberPayload, user, this.guild, permissions)
|
||||
resolve(res)
|
||||
}).catch(e => reject(e))
|
||||
})
|
||||
|
|
|
@ -46,6 +46,16 @@ export class Command {
|
|||
args?: number | boolean
|
||||
/** Permission(s) required for using Command */
|
||||
permissions?: string | string[]
|
||||
/** Permission(s) bot will need in order to execute Command */
|
||||
botPermissions?: string | string[]
|
||||
/** Role(s) user will require in order to use Command. List or one of ID or name */
|
||||
roles?: string | string[]
|
||||
/** Whitelisted Guilds. Only these Guild(s) can execute Command. (List or one of IDs) */
|
||||
whitelistedGuilds?: string | string[]
|
||||
/** Whitelisted Channels. Command can be executed only in these channels. (List or one of IDs) */
|
||||
whitelistedChannels?: string | string[]
|
||||
/** Whitelisted Users. Command can be executed only by these Users (List or one of IDs) */
|
||||
whitelistedUsers?: string | string[]
|
||||
/** Whether the Command can only be used in Guild (if allowed in DMs) */
|
||||
guildOnly?: boolean
|
||||
/** Whether the Command can only be used in Bot's DMs (if allowed) */
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Message } from "../../mod.ts"
|
||||
import { Embed } from "../structures/embed.ts"
|
||||
import { awaitSync } from "../utils/mixedPromise.ts"
|
||||
import { Client, ClientOptions } from './client.ts'
|
||||
import { CommandContext, CommandsManager, parseCommand } from './command.ts'
|
||||
|
@ -23,33 +22,6 @@ export interface CommandClientOptions extends ClientOptions {
|
|||
caseSensitive?: boolean
|
||||
}
|
||||
|
||||
type CommandText = string | Embed
|
||||
|
||||
export interface CommandTexts {
|
||||
GUILD_ONLY?: CommandText
|
||||
OWNER_ONLY?: CommandText
|
||||
DMS_ONLY?: CommandText
|
||||
ERROR?: CommandText
|
||||
}
|
||||
|
||||
export const DefaultCommandTexts: CommandTexts = {
|
||||
GUILD_ONLY: 'This command can only be used in a Server!',
|
||||
OWNER_ONLY: 'This command can only be used by Bot Owners!',
|
||||
DMS_ONLY: "This command can only be used in Bot's DMs!",
|
||||
ERROR: 'An error occured while executing command!'
|
||||
}
|
||||
|
||||
interface Replaces {
|
||||
[name: string]: string
|
||||
}
|
||||
|
||||
export const massReplace = (text: string, replaces: Replaces): string => {
|
||||
Object.entries(replaces).forEach(replace => {
|
||||
text = text.replace(new RegExp(`{{${replace[0]}}}`, 'g'), replace[1])
|
||||
})
|
||||
return text
|
||||
}
|
||||
|
||||
export class CommandClient extends Client implements CommandClientOptions {
|
||||
prefix: string | string[]
|
||||
mentionPrefix: boolean
|
||||
|
@ -66,7 +38,6 @@ export class CommandClient extends Client implements CommandClientOptions {
|
|||
caseSensitive: boolean
|
||||
extensions: ExtensionsManager = new ExtensionsManager(this)
|
||||
commands: CommandsManager = new CommandsManager(this)
|
||||
texts: CommandTexts = DefaultCommandTexts
|
||||
|
||||
constructor(options: CommandClientOptions) {
|
||||
super(options)
|
||||
|
@ -162,31 +133,9 @@ export class CommandClient extends Client implements CommandClientOptions {
|
|||
|
||||
if (command === undefined) return
|
||||
|
||||
const baseReplaces: Replaces = {
|
||||
command: command.name,
|
||||
nameUsed: parsed.name,
|
||||
prefix,
|
||||
username: msg.author.username,
|
||||
tag: msg.author.tag,
|
||||
mention: msg.author.mention,
|
||||
id: msg.author.id
|
||||
}
|
||||
|
||||
if (command.guildOnly === true && msg.guild === undefined) {
|
||||
if (this.texts.GUILD_ONLY !== undefined)
|
||||
return this.sendProcessedText(msg, this.texts.GUILD_ONLY, baseReplaces)
|
||||
return
|
||||
}
|
||||
if (command.dmOnly === true && msg.guild !== undefined) {
|
||||
if (this.texts.DMS_ONLY !== undefined)
|
||||
return this.sendProcessedText(msg, this.texts.DMS_ONLY, baseReplaces)
|
||||
return
|
||||
}
|
||||
if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) {
|
||||
if (this.texts.OWNER_ONLY !== undefined)
|
||||
return this.sendProcessedText(msg, this.texts.OWNER_ONLY, baseReplaces)
|
||||
return
|
||||
}
|
||||
if (command.whitelistedGuilds !== undefined && msg.guild !== undefined && command.whitelistedGuilds.includes(msg.guild.id) === false) return;
|
||||
if (command.whitelistedChannels !== undefined && command.whitelistedChannels.includes(msg.channel.id) === false) return;
|
||||
if (command.whitelistedUsers !== undefined && command.whitelistedUsers.includes(msg.author.id) === false) return;
|
||||
|
||||
const ctx: CommandContext = {
|
||||
client: this,
|
||||
|
@ -201,6 +150,22 @@ export class CommandClient extends Client implements CommandClientOptions {
|
|||
guild: msg.guild
|
||||
}
|
||||
|
||||
if (command.guildOnly === true && msg.guild === undefined) return this.emit('commandGuildOnly', { ctx, command })
|
||||
if (command.dmOnly === true && msg.guild !== undefined) return this.emit('commandDmOnly', { ctx, command })
|
||||
if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) return this.emit('commandOwnerOnly', { ctx, command })
|
||||
|
||||
if (command.permissions !== undefined && msg.guild !== undefined) {
|
||||
const missing: string[] = []
|
||||
let perms: string[] = []
|
||||
if (typeof command.permissions === 'string') perms = [command.permissions]
|
||||
else perms = command.permissions
|
||||
for (const perm of perms) {
|
||||
const has = msg.member?.permissions.has(perm)
|
||||
if (has !== true) missing.push(perm)
|
||||
}
|
||||
if (missing.length !== 0) return this.emit('commandMissingPermissions', { command, missing, ctx })
|
||||
}
|
||||
|
||||
try {
|
||||
this.emit('commandUsed', { context: ctx })
|
||||
|
||||
|
@ -210,30 +175,7 @@ export class CommandClient extends Client implements CommandClientOptions {
|
|||
const result = await awaitSync(command.execute(ctx))
|
||||
command.afterExecute(ctx, result)
|
||||
} catch (e) {
|
||||
if (this.texts.ERROR !== undefined)
|
||||
this.sendProcessedText(
|
||||
msg,
|
||||
this.texts.ERROR,
|
||||
Object.assign(baseReplaces, { error: e.message })
|
||||
)
|
||||
this.emit('commandError', { command, parsed, error: e })
|
||||
}
|
||||
}
|
||||
|
||||
sendProcessedText(msg: Message, text: CommandText, replaces: Replaces): any {
|
||||
if (typeof text === 'string') {
|
||||
text = massReplace(text, replaces)
|
||||
return msg.channel.send(text)
|
||||
} else {
|
||||
if (text.description !== undefined)
|
||||
text.description = massReplace(text.description, replaces)
|
||||
if (text.title !== undefined)
|
||||
text.description = massReplace(text.title, replaces)
|
||||
if (text.author?.name !== undefined)
|
||||
text.description = massReplace(text.author.name, replaces)
|
||||
if (text.footer?.text !== undefined)
|
||||
text.description = massReplace(text.footer.text, replaces)
|
||||
return msg.channel.send(text)
|
||||
this.emit('commandError', { command, parsed, error: e, ctx })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { GuildChannelsManager } from '../managers/guildChannels.ts'
|
|||
import { MembersManager } from '../managers/members.ts'
|
||||
import { Role } from './role.ts'
|
||||
import { GuildEmojisManager } from '../managers/guildEmojis.ts'
|
||||
import { Member } from "./member.ts"
|
||||
|
||||
export class Guild extends Base {
|
||||
id: string
|
||||
|
@ -214,4 +215,10 @@ export class Guild extends Base {
|
|||
async getEveryoneRole (): Promise<Role> {
|
||||
return (await this.roles.array().then(arr => arr?.sort((b, a) => a.position - b.position)[0]) as any) as Role
|
||||
}
|
||||
|
||||
async me(): Promise<Member> {
|
||||
const get = await this.members.get(this.client.user?.id as string)
|
||||
if (get === undefined) throw new Error('Guild#me is not cached')
|
||||
return get
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { MemberRolesManager } from "../managers/memberRoles.ts"
|
||||
import { Client } from '../models/client.ts'
|
||||
import { MemberPayload } from '../types/guild.ts'
|
||||
import { Permissions } from "../utils/permissions.ts"
|
||||
import { Base } from './base.ts'
|
||||
import { Guild } from "./guild.ts"
|
||||
import { User } from './user.ts'
|
||||
|
@ -15,13 +16,12 @@ export class Member extends Base {
|
|||
deaf: boolean
|
||||
mute: boolean
|
||||
guild: Guild
|
||||
permissions: Permissions
|
||||
|
||||
constructor (client: Client, data: MemberPayload, user: User, guild: Guild) {
|
||||
constructor (client: Client, data: MemberPayload, user: User, guild: Guild, perms?: Permissions) {
|
||||
super(client)
|
||||
this.id = data.user.id
|
||||
this.user = user
|
||||
// this.user =
|
||||
// cache.get('user', data.user.id) ?? new User(this.client, data.user)
|
||||
this.nick = data.nick
|
||||
this.guild = guild
|
||||
this.roles = new MemberRolesManager(this.client, this.guild.roles, this)
|
||||
|
@ -29,8 +29,8 @@ export class Member extends Base {
|
|||
this.premiumSince = data.premium_since
|
||||
this.deaf = data.deaf
|
||||
this.mute = data.mute
|
||||
// TODO: Cache in Gateway Event Code
|
||||
// cache.set('member', this.id, this)
|
||||
if (perms !== undefined) this.permissions = perms
|
||||
else this.permissions = new Permissions(Permissions.DEFAULT)
|
||||
}
|
||||
|
||||
protected readFromData (data: MemberPayload): void {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Client } from '../models/client.ts'
|
||||
import { Base } from './base.ts'
|
||||
import { RolePayload } from '../types/role.ts'
|
||||
import { Permissions } from "../utils/permissions.ts"
|
||||
|
||||
export class Role extends Base {
|
||||
id: string
|
||||
|
@ -8,7 +9,7 @@ export class Role extends Base {
|
|||
color: number
|
||||
hoist: boolean
|
||||
position: number
|
||||
permissions: string
|
||||
permissions: Permissions
|
||||
managed: boolean
|
||||
mentionable: boolean
|
||||
|
||||
|
@ -25,11 +26,9 @@ export class Role extends Base {
|
|||
this.color = data.color
|
||||
this.hoist = data.hoist
|
||||
this.position = data.position
|
||||
this.permissions = data.permissions
|
||||
this.permissions = new Permissions(data.permissions)
|
||||
this.managed = data.managed
|
||||
this.mentionable = data.mentionable
|
||||
// TODO: Cache in Gateway Event Code
|
||||
// cache.set('role', this.id, this)
|
||||
}
|
||||
|
||||
protected readFromData (data: RolePayload): void {
|
||||
|
@ -38,7 +37,7 @@ export class Role extends Base {
|
|||
this.color = data.color ?? this.color
|
||||
this.hoist = data.hoist ?? this.hoist
|
||||
this.position = data.position ?? this.position
|
||||
this.permissions = data.permissions ?? this.permissions
|
||||
this.permissions = new Permissions(data.permissions) ?? this.permissions
|
||||
this.managed = data.managed ?? this.managed
|
||||
this.mentionable = data.mentionable ?? this.mentionable
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Client } from '../models/client.ts'
|
||||
import { UserPayload } from '../types/user.ts'
|
||||
import { UserFlagsManager } from "../utils/userFlags.ts"
|
||||
import { Base } from './base.ts'
|
||||
|
||||
export class User extends Base {
|
||||
|
@ -13,9 +14,9 @@ export class User extends Base {
|
|||
locale?: string
|
||||
verified?: boolean
|
||||
email?: string
|
||||
flags?: number
|
||||
flags?: UserFlagsManager
|
||||
premiumType?: 0 | 1 | 2
|
||||
publicFlags?: number
|
||||
publicFlags?: UserFlagsManager
|
||||
|
||||
get tag (): string {
|
||||
return `${this.username}#${this.discriminator}`
|
||||
|
@ -41,11 +42,9 @@ export class User extends Base {
|
|||
this.locale = data.locale
|
||||
this.verified = data.verified
|
||||
this.email = data.email
|
||||
this.flags = data.flags
|
||||
this.flags = new UserFlagsManager(data.flags)
|
||||
this.premiumType = data.premium_type
|
||||
this.publicFlags = data.public_flags
|
||||
// TODO: Cache in Gateway Event Code
|
||||
// cache.set('user', this.id, this)
|
||||
this.publicFlags = new UserFlagsManager(data.public_flags)
|
||||
}
|
||||
|
||||
protected readFromData (data: UserPayload): void {
|
||||
|
@ -59,9 +58,9 @@ export class User extends Base {
|
|||
this.locale = data.locale ?? this.locale
|
||||
this.verified = data.verified ?? this.verified
|
||||
this.email = data.email ?? this.email
|
||||
this.flags = data.flags ?? this.flags
|
||||
this.flags = new UserFlagsManager(data.flags) ?? this.flags
|
||||
this.premiumType = data.premium_type ?? this.premiumType
|
||||
this.publicFlags = data.public_flags ?? this.publicFlags
|
||||
this.publicFlags = new UserFlagsManager(data.public_flags) ?? this.publicFlags
|
||||
}
|
||||
|
||||
toString (): string {
|
||||
|
|
|
@ -13,6 +13,7 @@ export default class UserinfoCommand extends Command {
|
|||
.setAuthor({ name: member.user.tag })
|
||||
.addField("ID", member.id)
|
||||
.addField("Roles", roles.map(r => r.name).join(", "))
|
||||
.addField('Permissions', JSON.stringify(member.permissions.has('ADMINISTRATOR')))
|
||||
.setColor(0xff00ff)
|
||||
ctx.channel.send(embed)
|
||||
}
|
||||
|
|
|
@ -1,43 +1,35 @@
|
|||
// https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags
|
||||
|
||||
enum PermissionFlags {
|
||||
CREATE_INSTANT_INVITE = 0x00000001,
|
||||
|
||||
KICK_MEMBERS = 0x00000002,
|
||||
BAN_MEMBERS = 0x00000004,
|
||||
ADMINISTRATOR = 0x00000008,
|
||||
MANAGE_CHANNELS = 0x00000010,
|
||||
MANAGE_GUILD = 0x00000020,
|
||||
|
||||
ADD_REACTIONS = 0x00000040,
|
||||
VIEW_AUDIT_LOG = 0x00000080,
|
||||
PRIORITY_SPEAKER = 0x00000100,
|
||||
STREAM = 0x00000200,
|
||||
|
||||
VIEW_CHANNEL = 0x00000400,
|
||||
SEND_MESSAGES = 0x00000800,
|
||||
SEND_TTS_MESSAGES = 0x00001000,
|
||||
MANAGE_MESSAGES = 0x00002000,
|
||||
|
||||
EMBED_LINKS = 0x00004000,
|
||||
ATTACH_FILES = 0x00008000,
|
||||
READ_MESSAGE_HISTORY = 0x00010000,
|
||||
MENTION_EVERYONE = 0x00020000,
|
||||
USE_EXTERNAL_EMOJIS = 0x00040000,
|
||||
VIEW_GUILD_INSIGHTS = 0x00080000,
|
||||
|
||||
CONNECT = 0x00100000,
|
||||
SPEAK = 0x00200000,
|
||||
MUTE_MEMBERS = 0x00400000,
|
||||
DEAFEN_MEMBERS = 0x00800000,
|
||||
MOVE_MEMBERS = 0x01000000,
|
||||
USE_VAD = 0x02000000,
|
||||
|
||||
CHANGE_NICKNAME = 0x04000000,
|
||||
MANAGE_NICKNAMES = 0x08000000,
|
||||
MANAGE_ROLES = 0x10000000,
|
||||
MANAGE_WEBHOOKS = 0x20000000,
|
||||
MANAGE_EMOJIS = 0x40000000
|
||||
}
|
||||
|
||||
export { PermissionFlags }
|
||||
export const PermissionFlags: { [key: string]: number } = {
|
||||
CREATE_INSTANT_INVITE: 1 << 0,
|
||||
KICK_MEMBERS: 1 << 1,
|
||||
BAN_MEMBERS: 1 << 2,
|
||||
ADMINISTRATOR: 1 << 3,
|
||||
MANAGE_CHANNELS: 1 << 4,
|
||||
MANAGE_GUILD: 1 << 5,
|
||||
ADD_REACTIONS: 1 << 6,
|
||||
VIEW_AUDIT_LOG: 1 << 7,
|
||||
PRIORITY_SPEAKER: 1 << 8,
|
||||
STREAM: 1 << 9,
|
||||
VIEW_CHANNEL: 1 << 10,
|
||||
SEND_MESSAGES: 1 << 11,
|
||||
SEND_TTS_MESSAGES: 1 << 12,
|
||||
MANAGE_MESSAGES: 1 << 13,
|
||||
EMBED_LINKS: 1 << 14,
|
||||
ATTACH_FILES: 1 << 15,
|
||||
READ_MESSAGE_HISTORY: 1 << 16,
|
||||
MENTION_EVERYONE: 1 << 17,
|
||||
USE_EXTERNAL_EMOJIS: 1 << 18,
|
||||
VIEW_GUILD_INSIGHTS: 1 << 19,
|
||||
CONNECT: 1 << 20,
|
||||
SPEAK: 1 << 21,
|
||||
MUTE_MEMBERS: 1 << 22,
|
||||
DEAFEN_MEMBERS: 1 << 23,
|
||||
MOVE_MEMBERS: 1 << 24,
|
||||
USE_VAD: 1 << 25,
|
||||
CHANGE_NICKNAME: 1 << 26,
|
||||
MANAGE_NICKNAMES: 1 << 27,
|
||||
MANAGE_ROLES: 1 << 28,
|
||||
MANAGE_WEBHOOKS: 1 << 29,
|
||||
MANAGE_EMOJIS: 1 << 30,
|
||||
}
|
16
src/types/userFlags.ts
Normal file
16
src/types/userFlags.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
export const UserFlags = {
|
||||
DISCORD_EMPLOYEE: 1 << 0,
|
||||
PARTNERED_SERVER_OWNER: 1 << 1,
|
||||
DISCORD_PARTNER: 1 << 1,
|
||||
HYPESQUAD_EVENTS: 1 << 2,
|
||||
BUGHUNTER_LEVEL_1: 1 << 3,
|
||||
HOUSE_BRAVERY: 1 << 6,
|
||||
HOUSE_BRILLIANCE: 1 << 7,
|
||||
HOUSE_BALANCE: 1 << 8,
|
||||
EARLY_SUPPORTER: 1 << 9,
|
||||
TEAM_USER: 1 << 10,
|
||||
SYSTEM: 1 << 12,
|
||||
BUGHUNTER_LEVEL_2: 1 << 14,
|
||||
VERIFIED_BOT: 1 << 16,
|
||||
EARLY_VERIFIED_DEVELOPER: 1 << 17
|
||||
}
|
86
src/utils/bitfield.ts
Normal file
86
src/utils/bitfield.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Ported from https://github.com/discordjs/discord.js/blob/master/src/util/BitField.js
|
||||
export type BitFieldResolvable = number | BitField | string | BitField[]
|
||||
|
||||
export class BitField {
|
||||
flags: { [name: string]: number } = {}
|
||||
bitfield: any
|
||||
|
||||
constructor(flags: { [name: string]: number }, bits: any) {
|
||||
this.flags = flags
|
||||
this.bitfield = BitField.resolve(this.flags, bits)
|
||||
}
|
||||
|
||||
any(bit: BitFieldResolvable): boolean {
|
||||
return (this.bitfield & BitField.resolve(this.flags, bit)) !== 0
|
||||
}
|
||||
|
||||
equals(bit: BitFieldResolvable): boolean {
|
||||
return this.bitfield === BitField.resolve(this.flags, bit)
|
||||
}
|
||||
|
||||
has(bit: BitFieldResolvable, ...args: any[]): boolean {
|
||||
if (Array.isArray(bit)) return bit.every(p => this.has(p))
|
||||
return (this.bitfield & BitField.resolve(this.flags, bit)) === bit
|
||||
}
|
||||
|
||||
missing(bits: any, ...hasParams: any[]): string[] {
|
||||
if (!Array.isArray(bits)) bits = new BitField(this.flags, bits).toArray(false)
|
||||
return bits.filter((p: any) => !this.has(p, ...hasParams))
|
||||
}
|
||||
|
||||
freeze(): Readonly<BitField> {
|
||||
return Object.freeze(this)
|
||||
}
|
||||
|
||||
add(...bits: BitFieldResolvable[]): BitField {
|
||||
let total = 0
|
||||
for (const bit of bits) {
|
||||
total |= BitField.resolve(this.flags, bit)
|
||||
}
|
||||
if (Object.isFrozen(this)) return new BitField(this.flags, this.bitfield | total)
|
||||
this.bitfield |= total
|
||||
return this
|
||||
}
|
||||
|
||||
remove(...bits: BitFieldResolvable[]): BitField {
|
||||
let total = 0
|
||||
for (const bit of bits) {
|
||||
total |= BitField.resolve(this.flags, bit)
|
||||
}
|
||||
if (Object.isFrozen(this)) return new BitField(this.flags, this.bitfield & ~total)
|
||||
this.bitfield &= ~total
|
||||
return this
|
||||
}
|
||||
|
||||
serialize(...hasParams: any[]): { [key: string]: any } {
|
||||
const serialized: { [key: string]: any } = {}
|
||||
for (const [flag, bit] of Object.entries(this.flags)) serialized[flag] = this.has(BitField.resolve(this.flags, bit), ...hasParams)
|
||||
return serialized
|
||||
}
|
||||
|
||||
toArray(...hasParams: any[]): string[] {
|
||||
return Object.keys(this.flags).filter(bit => this.has(BitField.resolve(this.flags, bit), ...hasParams))
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return this.bitfield
|
||||
}
|
||||
|
||||
valueOf(): any {
|
||||
return this.bitfield
|
||||
}
|
||||
|
||||
*[Symbol.iterator](): any {
|
||||
yield* this.toArray()
|
||||
}
|
||||
|
||||
static resolve(flags: any, bit: BitFieldResolvable = 0): number {
|
||||
if (typeof bit === 'string' && !isNaN(parseInt(bit))) return parseInt(bit)
|
||||
if (typeof bit === 'number' && bit >= 0) return bit
|
||||
if (bit instanceof BitField) return this.resolve(flags, bit.bitfield)
|
||||
if (Array.isArray(bit)) return bit.map(p => this.resolve(flags, p)).reduce((prev, p) => prev | p, 0)
|
||||
if (typeof bit === 'string' && typeof flags[bit] !== 'undefined') return flags[bit]
|
||||
const error = new RangeError('BITFIELD_INVALID')
|
||||
throw error
|
||||
}
|
||||
}
|
22
src/utils/permissions.ts
Normal file
22
src/utils/permissions.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Ported from https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
|
||||
import { PermissionFlags } from "../types/permissionFlags.ts"
|
||||
import { BitField } from "./bitfield.ts"
|
||||
|
||||
export type PermissionResolvable = string | number | Permissions | PermissionResolvable[]
|
||||
|
||||
export class Permissions extends BitField {
|
||||
static DEFAULT = 104324673
|
||||
static ALL = Object.values(PermissionFlags).reduce((all, p) => all | p, 0)
|
||||
|
||||
constructor(bits: any) {
|
||||
super(PermissionFlags, bits)
|
||||
}
|
||||
|
||||
any(permission: PermissionResolvable, checkAdmin = true): boolean {
|
||||
return (checkAdmin && super.has(this.flags.ADMINISTRATOR)) || super.any(permission as any)
|
||||
}
|
||||
|
||||
has(permission: PermissionResolvable, checkAdmin = true): boolean {
|
||||
return (checkAdmin && super.has(this.flags.ADMINISTRATOR)) || super.has(permission as any)
|
||||
}
|
||||
}
|
8
src/utils/userFlags.ts
Normal file
8
src/utils/userFlags.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { UserFlags } from "../types/userFlags.ts";
|
||||
import { BitField } from "./bitfield.ts";
|
||||
|
||||
export class UserFlagsManager extends BitField {
|
||||
constructor(bits: any) {
|
||||
super(UserFlags, bits)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue