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 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, | ||||
| } | ||||
| 
 | ||||
| export { PermissionFlags } | ||||
|  |  | |||
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue