Merge pull request #32 from DjDeveloperr/main
Added Message Mentions, mentionPrefix, Blocked Users/Channels/Guilds for Commands, MemberRolesManager, Improved REST Errors
This commit is contained in:
		
						commit
						7600a8e477
					
				
					 22 changed files with 385 additions and 177 deletions
				
			
		|  | @ -55,7 +55,7 @@ client.on('messageCreate', (msg: Message): void => { | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| // Connect to gateway | // Connect to gateway | ||||||
| // Replace with your bot's token and intents (Intents.All, Intents.Presence, Intents.GuildMembers) | // Replace with your bot's token and intents (Intents.All, Intents.None, Intents.Presence, Intents.GuildMembers) | ||||||
| client.connect('super secret token comes here', Intents.All) | client.connect('super secret token comes here', Intents.All) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | @ -84,7 +84,7 @@ class PingCommand extends Command { | ||||||
| client.commands.add(PingCommand) | client.commands.add(PingCommand) | ||||||
| 
 | 
 | ||||||
| // Connect to gateway | // Connect to gateway | ||||||
| // Replace with your bot's token and intents (Intents.All, Intents.Presence, Intents.GuildMembers) | // Replace with your bot's token and intents (Intents.All, Intents.None, Intents.Presence, Intents.GuildMembers) | ||||||
| client.connect('super secret token comes here', Intents.All) | client.connect('super secret token comes here', Intents.All) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								mod.ts
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								mod.ts
									
										
									
									
									
								
							|  | @ -26,7 +26,6 @@ export * from './src/structures/groupChannel.ts' | ||||||
| export * from './src/structures/guild.ts' | export * from './src/structures/guild.ts' | ||||||
| export * from './src/structures/guildCategoryChannel.ts' | export * from './src/structures/guildCategoryChannel.ts' | ||||||
| export * from './src/structures/guildNewsChannel.ts' | export * from './src/structures/guildNewsChannel.ts' | ||||||
| export * from './src/structures/guildTextChannel.ts' |  | ||||||
| export * from './src/structures/guildVoiceChannel.ts' | export * from './src/structures/guildVoiceChannel.ts' | ||||||
| export * from './src/structures/invite.ts' | export * from './src/structures/invite.ts' | ||||||
| export * from './src/structures/member.ts' | export * from './src/structures/member.ts' | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| import { Message } from '../../structures/message.ts' | import { Message } from '../../structures/message.ts' | ||||||
| import { MessageMentions } from '../../structures/messageMentions.ts' |  | ||||||
| import { TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
| import { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { MessagePayload } from '../../types/channel.ts' | import { MessagePayload } from '../../types/channel.ts' | ||||||
|  | @ -26,10 +25,10 @@ export const messageCreate: GatewayEventHandler = async ( | ||||||
|     await guild.members.set(d.author.id, d.member) |     await guild.members.set(d.author.id, d.member) | ||||||
|     member = await guild.members.get(d.author.id) |     member = await guild.members.get(d.author.id) | ||||||
|   } |   } | ||||||
|   const mentions = new MessageMentions() |   const message = new Message(gateway.client, d, channel as any, user) | ||||||
|   const message = new Message(gateway.client, d, channel as any, user, mentions) |  | ||||||
|   message.member = member |  | ||||||
|   if (guild !== undefined) message.guild = guild |   if (guild !== undefined) message.guild = guild | ||||||
|  |   await message.mentions.fromPayload(d) | ||||||
|  |   message.member = member | ||||||
|   if (message.member !== undefined) { |   if (message.member !== undefined) { | ||||||
|     if (message.member.user === undefined) { |     if (message.member.user === undefined) { | ||||||
|       const user = await gateway.client.users.get(message.member.id) |       const user = await gateway.client.users.get(message.member.id) | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ import { gatewayHandlers } from './handlers/index.ts' | ||||||
| import { GATEWAY_BOT } from '../types/endpoint.ts' | import { GATEWAY_BOT } from '../types/endpoint.ts' | ||||||
| import { GatewayCache } from '../managers/gatewayCache.ts' | import { GatewayCache } from '../managers/gatewayCache.ts' | ||||||
| import { ClientActivityPayload } from '../structures/presence.ts' | import { ClientActivityPayload } from '../structures/presence.ts' | ||||||
|  | import { delay } from "../utils/delay.ts" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Handles Discord gateway connection. |  * Handles Discord gateway connection. | ||||||
|  | @ -140,7 +141,7 @@ class Gateway { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private onclose (event: CloseEvent): void { |   private async onclose (event: CloseEvent): Promise<void> { | ||||||
|     this.debug(`Connection Closed with code: ${event.code}`) |     this.debug(`Connection Closed with code: ${event.code}`) | ||||||
| 
 | 
 | ||||||
|     if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) { |     if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) { | ||||||
|  | @ -178,7 +179,8 @@ class Gateway { | ||||||
|     } else if (event.code === GatewayCloseCodes.DISALLOWED_INTENTS) { |     } else if (event.code === GatewayCloseCodes.DISALLOWED_INTENTS) { | ||||||
|       throw new Error("Given Intents aren't allowed") |       throw new Error("Given Intents aren't allowed") | ||||||
|     } else { |     } else { | ||||||
|       this.debug('Unknown Close code, probably connection error. Reconnecting.') |       this.debug('Unknown Close code, probably connection error. Reconnecting in 5s.') | ||||||
|  |       await delay(5000) | ||||||
|       // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |       // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|       this.reconnect() |       this.reconnect() | ||||||
|     } |     } | ||||||
|  | @ -219,7 +221,7 @@ class Gateway { | ||||||
|         token: this.token, |         token: this.token, | ||||||
|         properties: { |         properties: { | ||||||
|           $os: Deno.build.os, |           $os: Deno.build.os, | ||||||
|           $browser: 'harmony', // TODO: Change lib name
 |           $browser: 'harmony', | ||||||
|           $device: 'harmony' |           $device: 'harmony' | ||||||
|         }, |         }, | ||||||
|         compress: true, |         compress: true, | ||||||
|  | @ -233,18 +235,17 @@ class Gateway { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (this.client.bot === false) { |     if (this.client.bot === false) { | ||||||
|       // TODO: Complete Selfbot support
 |  | ||||||
|       this.debug('Modify Identify Payload for Self-bot..') |       this.debug('Modify Identify Payload for Self-bot..') | ||||||
|       // delete payload.d['intents']
 |       delete payload.d.intents | ||||||
|       // payload.d.intents = Intents.None
 |  | ||||||
|       payload.d.presence = null |       payload.d.presence = null | ||||||
|       payload.d.properties = { |       payload.d.properties = { | ||||||
|         $os: 'Windows', |         $os: 'Windows', | ||||||
|         $browser: 'Firefox', |         $browser: 'Firefox', | ||||||
|         $device: '' |         $device: '', | ||||||
|  |         $referrer: '', | ||||||
|  |         $referring_domain: '' | ||||||
|       } |       } | ||||||
| 
 |       payload.d.synced_guilds = [] | ||||||
|       this.debug('Warn: Support for selfbots is incomplete') |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.send(payload) |     this.send(payload) | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import { Client } from '../models/client.ts' | ||||||
| import { Channel } from '../structures/channel.ts' | import { Channel } from '../structures/channel.ts' | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | ||||||
| import { GuildTextChannel } from '../structures/guildTextChannel.ts' | import { GuildTextChannel } from '../structures/textChannel.ts' | ||||||
| import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { | import { | ||||||
|   GuildChannelCategoryPayload, |   GuildChannelCategoryPayload, | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								src/managers/memberRoles.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/managers/memberRoles.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | import { Client } from '../models/client.ts' | ||||||
|  | import { BaseChildManager } from './baseChild.ts' | ||||||
|  | import { RolePayload } from "../types/role.ts" | ||||||
|  | import { Role } from "../structures/role.ts" | ||||||
|  | import { Member } from "../structures/member.ts" | ||||||
|  | import { RolesManager } from "./roles.ts" | ||||||
|  | import { MemberPayload } from "../types/guild.ts" | ||||||
|  | 
 | ||||||
|  | export class MemberRolesManager extends BaseChildManager< | ||||||
|  |   RolePayload, | ||||||
|  |   Role | ||||||
|  | > { | ||||||
|  |   member: Member | ||||||
|  | 
 | ||||||
|  |   constructor (client: Client, parent: RolesManager, member: Member) { | ||||||
|  |     super(client, parent as any) | ||||||
|  |     this.member = member | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   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 | ||||||
|  |     else return undefined | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async array (): Promise<Role[]> { | ||||||
|  |     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) | ||||||
|  |     ) as any | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async flush (): Promise<boolean> { | ||||||
|  |     const arr = await this.array() | ||||||
|  |     for (const elem of arr) { | ||||||
|  |       this.parent.delete(elem.id) | ||||||
|  |     } | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -18,11 +18,7 @@ export class MembersManager extends BaseManager<MemberPayload, Member> { | ||||||
|     const raw = await this._get(key) |     const raw = await this._get(key) | ||||||
|     if (raw === undefined) return |     if (raw === undefined) return | ||||||
|     const user = new User(this.client, raw.user) |     const user = new User(this.client, raw.user) | ||||||
|     const res = new this.DataType(this.client, raw, user) |     const res = new this.DataType(this.client, raw, user, this.guild) | ||||||
|     for (const roleid of res.roleIDs as string[]) { |  | ||||||
|       const role = await this.guild.roles.get(roleid) |  | ||||||
|       if (role !== undefined) res.roles.push(role) |  | ||||||
|     } |  | ||||||
|     return res |     return res | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -31,11 +27,7 @@ export class MembersManager extends BaseManager<MemberPayload, Member> { | ||||||
|       this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(async data => { |       this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(async data => { | ||||||
|         await this.set(id, data as MemberPayload) |         await this.set(id, data as MemberPayload) | ||||||
|         const user: User = new User(this.client, data.user) |         const user: User = new User(this.client, data.user) | ||||||
|         const res = new Member(this.client, data as MemberPayload, user) |         const res = new Member(this.client, data as MemberPayload, user, this.guild) | ||||||
|         for (const roleid of res.roleIDs as string[]) { |  | ||||||
|           const role = await this.guild.roles.get(roleid) |  | ||||||
|           if (role !== undefined) res.roles.push(role) |  | ||||||
|         } |  | ||||||
|         resolve(res) |         resolve(res) | ||||||
|       }).catch(e => reject(e)) |       }).catch(e => reject(e)) | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { Message } from '../structures/message.ts' | import { Message } from '../structures/message.ts' | ||||||
| import { MessageMentions } from '../structures/messageMentions.ts' |  | ||||||
| import { TextChannel } from '../structures/textChannel.ts' | import { TextChannel } from '../structures/textChannel.ts' | ||||||
| import { User } from '../structures/user.ts' | import { User } from '../structures/user.ts' | ||||||
| import { MessagePayload } from '../types/channel.ts' | import { MessagePayload } from '../types/channel.ts' | ||||||
|  | @ -21,9 +20,10 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|       channel = await this.client.channels.fetch(raw.channel_id) |       channel = await this.client.channels.fetch(raw.channel_id) | ||||||
| 
 | 
 | ||||||
|     const author = new User(this.client, raw.author) |     const author = new User(this.client, raw.author) | ||||||
|     const mentions = new MessageMentions() |  | ||||||
| 
 | 
 | ||||||
|     return new this.DataType(this.client, raw, channel, author, mentions) as any |     const res = new this.DataType(this.client, raw, channel, author) as any | ||||||
|  |     await res.mentions.fromPayload(raw) | ||||||
|  |     return res | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fetch (channelID: string, id: string): Promise<Message> { |   async fetch (channelID: string, id: string): Promise<Message> { | ||||||
|  | @ -45,18 +45,16 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|             (data as MessagePayload).author |             (data as MessagePayload).author | ||||||
|           ) |           ) | ||||||
| 
 | 
 | ||||||
|           // TODO: Make this thing work (MessageMentions)
 |           const res = new Message( | ||||||
|           const mentions = new MessageMentions() |  | ||||||
| 
 |  | ||||||
|           resolve( |  | ||||||
|             new Message( |  | ||||||
|             this.client, |             this.client, | ||||||
|             data as MessagePayload, |             data as MessagePayload, | ||||||
|             channel as TextChannel, |             channel as TextChannel, | ||||||
|               author, |             author | ||||||
|               mentions |  | ||||||
|             ) |  | ||||||
|           ) |           ) | ||||||
|  | 
 | ||||||
|  |           await res.mentions.fromPayload(data) | ||||||
|  | 
 | ||||||
|  |           resolve(res) | ||||||
|         }) |         }) | ||||||
|         .catch(e => reject(e)) |         .catch(e => reject(e)) | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|  | @ -35,6 +35,8 @@ export class Command { | ||||||
|   description?: string |   description?: string | ||||||
|   /** Array of Aliases of Command, or only string */ |   /** Array of Aliases of Command, or only string */ | ||||||
|   aliases?: string | string[] |   aliases?: string | string[] | ||||||
|  |   /** Category of the Command */ | ||||||
|  |   category?: string | ||||||
|   /** Usage of Command, only Argument Names */ |   /** Usage of Command, only Argument Names */ | ||||||
|   usage?: string | string[] |   usage?: string | string[] | ||||||
|   /** Usage Example of Command, only Arguments (without Prefix and Name) */ |   /** Usage Example of Command, only Arguments (without Prefix and Name) */ | ||||||
|  | @ -50,17 +52,27 @@ export class Command { | ||||||
|   /** Whether the Command can only be used by Bot Owners */ |   /** Whether the Command can only be used by Bot Owners */ | ||||||
|   ownerOnly?: boolean |   ownerOnly?: boolean | ||||||
| 
 | 
 | ||||||
|   execute (ctx?: CommandContext): any {} |   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ | ||||||
|  |   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { return true } | ||||||
|  |   /** Actual command code, which is executed when all checks have passed. */ | ||||||
|  |   execute(ctx: CommandContext): any { } | ||||||
|  |   /** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */ | ||||||
|  |   afterExecute(ctx: CommandContext, executeResult: any): any { } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class CommandsManager { | export class CommandsManager { | ||||||
|   client: CommandClient |   client: CommandClient | ||||||
|   list: Collection<string, Command> = new Collection() |   list: Collection<string, Command> = new Collection() | ||||||
|  |   disabled: Set<string> = new Set() | ||||||
|  |   disabledCategories: Set<string> = new Set() | ||||||
| 
 | 
 | ||||||
|   constructor(client: CommandClient) { |   constructor(client: CommandClient) { | ||||||
|     this.client = client |     this.client = client | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** Number of loaded Commands */ | ||||||
|  |   get count(): number { return this.list.size } | ||||||
|  | 
 | ||||||
|   /** Find a Command by name/alias */ |   /** Find a Command by name/alias */ | ||||||
|   find(search: string): Command | undefined { |   find(search: string): Command | undefined { | ||||||
|     if (this.client.caseSensitive === false) search = search.toLowerCase() |     if (this.client.caseSensitive === false) search = search.toLowerCase() | ||||||
|  | @ -79,6 +91,15 @@ export class CommandsManager { | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** Fetch a Command including disable checks */ | ||||||
|  |   fetch(name: string, bypassDisable?: boolean): Command | undefined { | ||||||
|  |     const cmd = this.find(name) | ||||||
|  |     if (cmd === undefined) return | ||||||
|  |     if (this.isDisabled(cmd) && bypassDisable !== true) return | ||||||
|  |     if (cmd.category !== undefined && this.isCategoryDisabled(cmd.category) && bypassDisable !== true) return | ||||||
|  |     return cmd | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   /** Check whether a Command exists or not */ |   /** Check whether a Command exists or not */ | ||||||
|   exists(search: Command | string): boolean { |   exists(search: Command | string): boolean { | ||||||
|     let exists = false |     let exists = false | ||||||
|  | @ -111,6 +132,41 @@ export class CommandsManager { | ||||||
|     if (find === undefined) return false |     if (find === undefined) return false | ||||||
|     else return this.list.delete(find.name) |     else return this.list.delete(find.name) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** Get all Commands of given Category */ | ||||||
|  |   category(name: string): Collection<string, Command> { | ||||||
|  |     return this.list.filter(c => c.category === name) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Check whether a Command is disabled or not */ | ||||||
|  |   isDisabled(name: string | Command): boolean { | ||||||
|  |     const cmd = typeof name === "string" ? this.find(name) : name | ||||||
|  |     if (cmd === undefined) return false | ||||||
|  |     const exists = this.exists(name) | ||||||
|  |     if (!exists) return false | ||||||
|  |     return this.disabled.has(cmd.name) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Disable a Command */ | ||||||
|  |   disable(name: string | Command): boolean { | ||||||
|  |     const cmd = typeof name === "string" ? this.find(name) : name | ||||||
|  |     if (cmd === undefined) return false | ||||||
|  |     if (this.isDisabled(cmd)) return false | ||||||
|  |     this.disabled.add(cmd.name) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Check whether a Category is disabled */ | ||||||
|  |   isCategoryDisabled(name: string): boolean { | ||||||
|  |     return this.disabledCategories.has(name) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Disable a Category of Commands */ | ||||||
|  |   disableCategory(name: string): boolean { | ||||||
|  |     if (this.isCategoryDisabled(name)) return false | ||||||
|  |     this.disabledCategories.add(name) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ParsedCommand { | export interface ParsedCommand { | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| import { Embed, Message } from '../../mod.ts' | import { Embed, Message } from '../../mod.ts' | ||||||
|  | import { awaitSync } from "../utils/mixedPromise.ts" | ||||||
| import { Client, ClientOptions } from './client.ts' | import { Client, ClientOptions } from './client.ts' | ||||||
| import { CommandContext, CommandsManager, parseCommand } from './command.ts' | import { CommandContext, CommandsManager, parseCommand } from './command.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -9,6 +10,9 @@ export interface CommandClientOptions extends ClientOptions { | ||||||
|   mentionPrefix?: boolean |   mentionPrefix?: boolean | ||||||
|   getGuildPrefix?: (guildID: string) => PrefixReturnType |   getGuildPrefix?: (guildID: string) => PrefixReturnType | ||||||
|   getUserPrefix?: (userID: string) => PrefixReturnType |   getUserPrefix?: (userID: string) => PrefixReturnType | ||||||
|  |   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|  |   isUserBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|  |   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|   spacesAfterPrefix?: boolean |   spacesAfterPrefix?: boolean | ||||||
|   betterArgs?: boolean |   betterArgs?: boolean | ||||||
|   owners?: string[] |   owners?: string[] | ||||||
|  | @ -49,6 +53,9 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   mentionPrefix: boolean |   mentionPrefix: boolean | ||||||
|   getGuildPrefix: (guildID: string) => PrefixReturnType |   getGuildPrefix: (guildID: string) => PrefixReturnType | ||||||
|   getUserPrefix: (userID: string) => PrefixReturnType |   getUserPrefix: (userID: string) => PrefixReturnType | ||||||
|  |   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|  |   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|  |   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|   spacesAfterPrefix: boolean |   spacesAfterPrefix: boolean | ||||||
|   betterArgs: boolean |   betterArgs: boolean | ||||||
|   owners: string[] |   owners: string[] | ||||||
|  | @ -71,6 +78,18 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       options.getUserPrefix === undefined |       options.getUserPrefix === undefined | ||||||
|         ? (id: string) => this.prefix |         ? (id: string) => this.prefix | ||||||
|         : options.getUserPrefix |         : options.getUserPrefix | ||||||
|  |     this.isUserBlacklisted = | ||||||
|  |       options.isUserBlacklisted === undefined | ||||||
|  |         ? (id: string) => false | ||||||
|  |         : options.isUserBlacklisted | ||||||
|  |     this.isGuildBlacklisted = | ||||||
|  |       options.isGuildBlacklisted === undefined | ||||||
|  |         ? (id: string) => false | ||||||
|  |         : options.isGuildBlacklisted | ||||||
|  |     this.isChannelBlacklisted = | ||||||
|  |       options.isChannelBlacklisted === undefined | ||||||
|  |         ? (id: string) => false | ||||||
|  |         : options.isChannelBlacklisted | ||||||
|     this.spacesAfterPrefix = |     this.spacesAfterPrefix = | ||||||
|       options.spacesAfterPrefix === undefined |       options.spacesAfterPrefix === undefined | ||||||
|         ? false |         ? false | ||||||
|  | @ -92,26 +111,49 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   async processMessage(msg: Message): Promise<any> { |   async processMessage(msg: Message): Promise<any> { | ||||||
|     if (!this.allowBots && msg.author.bot === true) return |     if (!this.allowBots && msg.author.bot === true) return | ||||||
| 
 | 
 | ||||||
|  |     const isUserBlacklisted = await awaitSync(this.isUserBlacklisted(msg.author.id)) | ||||||
|  |     if (isUserBlacklisted === true) return | ||||||
|  | 
 | ||||||
|  |     const isChannelBlacklisted = await awaitSync(this.isChannelBlacklisted(msg.channel.id)) | ||||||
|  |     if (isChannelBlacklisted === true) return | ||||||
|  | 
 | ||||||
|  |     if (msg.guild !== undefined) { | ||||||
|  |       const isGuildBlacklisted = await awaitSync(this.isGuildBlacklisted(msg.guild.id)) | ||||||
|  |       if (isGuildBlacklisted === true) return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     let prefix: string | string[] = this.prefix |     let prefix: string | string[] = this.prefix | ||||||
| 
 | 
 | ||||||
|     if (msg.guild !== undefined) { |     if (msg.guild !== undefined) { | ||||||
|       let guildPrefix = this.getGuildPrefix(msg.guild.id) |       prefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) | ||||||
|       if (guildPrefix instanceof Promise) guildPrefix = await guildPrefix |  | ||||||
|       prefix = guildPrefix |  | ||||||
|     } else { |     } else { | ||||||
|       let userPrefix = this.getUserPrefix(msg.author.id) |       prefix = await awaitSync(this.getUserPrefix(msg.author.id)) | ||||||
|       if (userPrefix instanceof Promise) userPrefix = await userPrefix |  | ||||||
|       prefix = userPrefix |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     let mentionPrefix = false | ||||||
|  | 
 | ||||||
|     if (typeof prefix === 'string') { |     if (typeof prefix === 'string') { | ||||||
|       if (msg.content.startsWith(prefix) === false) return |       if (msg.content.startsWith(prefix) === false) { | ||||||
|  |         if (this.mentionPrefix) mentionPrefix = true | ||||||
|  |         else return | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) |       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) | ||||||
|       if (usedPrefix === undefined) return |       if (usedPrefix === undefined) { | ||||||
|  |         if (this.mentionPrefix) mentionPrefix = true | ||||||
|  |         else return | ||||||
|  |       } | ||||||
|       else prefix = usedPrefix |       else prefix = usedPrefix | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (mentionPrefix) { | ||||||
|  |       if (msg.content.startsWith(this.user?.mention as string) === true) prefix = this.user?.mention as string | ||||||
|  |       else if (msg.content.startsWith(this.user?.nickMention as string) === true) prefix = this.user?.nickMention as string | ||||||
|  |       else return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (typeof prefix !== 'string') return | ||||||
|  | 
 | ||||||
|     const parsed = parseCommand(this, msg, prefix) |     const parsed = parseCommand(this, msg, prefix) | ||||||
|     const command = this.commands.find(parsed.name) |     const command = this.commands.find(parsed.name) | ||||||
| 
 | 
 | ||||||
|  | @ -158,10 +200,15 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       this.emit('commandUsed', { context: ctx }) |       this.emit('commandUsed', { context: ctx }) | ||||||
|       command.execute(ctx) | 
 | ||||||
|  |       const beforeExecute = await awaitSync(command.beforeExecute(ctx)) | ||||||
|  |       if (beforeExecute === false) return | ||||||
|  | 
 | ||||||
|  |       const result = await awaitSync(command.execute(ctx)) | ||||||
|  |       command.afterExecute(ctx, result) | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       if (this.texts.ERROR !== undefined) |       if (this.texts.ERROR !== undefined) | ||||||
|         return this.sendProcessedText( |         this.sendProcessedText( | ||||||
|           msg, |           msg, | ||||||
|           this.texts.ERROR, |           this.texts.ERROR, | ||||||
|           Object.assign(baseReplaces, { error: e.message }) |           Object.assign(baseReplaces, { error: e.message }) | ||||||
|  |  | ||||||
|  | @ -25,13 +25,13 @@ export interface RequestHeaders { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface QueuedItem { | export interface QueuedItem { | ||||||
|  |   bucket?: string | null | ||||||
|  |   url: string | ||||||
|   onComplete: () => Promise<{ |   onComplete: () => Promise<{ | ||||||
|     rateLimited: any |     rateLimited: any | ||||||
|     bucket?: string | null |     bucket?: string | null | ||||||
|     before: boolean |     before: boolean | ||||||
|   } | undefined> |   } | undefined> | ||||||
|   bucket?: string | null |  | ||||||
|   url: string |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface RateLimit { | export interface RateLimit { | ||||||
|  | @ -93,10 +93,8 @@ export class RESTManager { | ||||||
|               request.bucket |               request.bucket | ||||||
|             ) |             ) | ||||||
|             if (rateLimitResetIn !== false) { |             if (rateLimitResetIn !== false) { | ||||||
|               // This request is still rate limited read to queue
 |  | ||||||
|               this.queue(request) |               this.queue(request) | ||||||
|             } else { |             } else { | ||||||
|               // This request is not rate limited so it should be run
 |  | ||||||
|               const result = await request.onComplete() |               const result = await request.onComplete() | ||||||
|               if (result?.rateLimited !== undefined) { |               if (result?.rateLimited !== undefined) { | ||||||
|                 this.queue({ |                 this.queue({ | ||||||
|  | @ -107,10 +105,8 @@ export class RESTManager { | ||||||
|             } |             } | ||||||
|           } else { |           } else { | ||||||
|             if (rateLimitedURLResetIn !== false) { |             if (rateLimitedURLResetIn !== false) { | ||||||
|               // This URL is rate limited readd to queue
 |  | ||||||
|               this.queue(request) |               this.queue(request) | ||||||
|             } else { |             } else { | ||||||
|               // This request has no bucket id so it should be processed
 |  | ||||||
|               const result = await request.onComplete() |               const result = await request.onComplete() | ||||||
|               if (result?.rateLimited !== undefined) { |               if (result?.rateLimited !== undefined) { | ||||||
|                 this.queue({ |                 this.queue({ | ||||||
|  | @ -253,27 +249,35 @@ export class RESTManager { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async handleStatusCode( |   async handleStatusCode( | ||||||
|     response: Response |     response: Response, body: any, data: { [key: string]: any } | ||||||
|   ): Promise<undefined> { |   ): Promise<undefined> { | ||||||
|     const status = response.status |     const status = response.status | ||||||
| 
 | 
 | ||||||
|     if ((status >= 200 && status < 400) || status === HttpResponseCode.TooManyRequests) return |     if ( | ||||||
|  |       (status >= 200 && status < 400) | ||||||
|  |       || status === HttpResponseCode.NoContent  | ||||||
|  |       || status === HttpResponseCode.TooManyRequests | ||||||
|  |     ) return | ||||||
| 
 | 
 | ||||||
|     const body = await response.json() |     let text: undefined | string = Deno.inspect(body.errors === undefined ? body : body.errors) | ||||||
|     const text = Deno.inspect(body.errors) |     if (text === 'undefined') text = undefined | ||||||
| 
 | 
 | ||||||
|     if (status === HttpResponseCode.Unauthorized) |     if (status === HttpResponseCode.Unauthorized) | ||||||
|       throw new Error(`Request was not successful (Unauthorized). Invalid Token.\n${text}`) |       throw new Error(`Request was not successful (Unauthorized). Invalid Token.\n${text}`) | ||||||
| 
 | 
 | ||||||
|  |     // At this point we know it is error
 | ||||||
|  |     let error = { url: response.url, status, method: data.method, body: data.body } | ||||||
|  |     if (body !== undefined) error = Object.assign(error, body) | ||||||
|  | 
 | ||||||
|     if ([ |     if ([ | ||||||
|       HttpResponseCode.BadRequest, |       HttpResponseCode.BadRequest, | ||||||
|       HttpResponseCode.NotFound, |       HttpResponseCode.NotFound, | ||||||
|       HttpResponseCode.Forbidden, |       HttpResponseCode.Forbidden, | ||||||
|       HttpResponseCode.MethodNotAllowed |       HttpResponseCode.MethodNotAllowed | ||||||
|     ].includes(status)) { |     ].includes(status)) { | ||||||
|       throw new Error(`Request - Client Error. Code: ${status}\n${text}`) |       throw new Error(Deno.inspect(error)) | ||||||
|     } else if (status === HttpResponseCode.GatewayUnavailable) { |     } else if (status === HttpResponseCode.GatewayUnavailable) { | ||||||
|       throw new Error(`Request - Server Error. Code: ${status}\n${text}`) |       throw new Error(Deno.inspect(error)) | ||||||
|     } else throw new Error('Request - Unknown Error') |     } else throw new Error('Request - Unknown Error') | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -319,12 +323,13 @@ export class RESTManager { | ||||||
| 
 | 
 | ||||||
|           const response = await fetch(urlToUse, requestData) |           const response = await fetch(urlToUse, requestData) | ||||||
|           const bucketFromHeaders = this.processHeaders(url, response.headers) |           const bucketFromHeaders = this.processHeaders(url, response.headers) | ||||||
|           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |  | ||||||
|           this.handleStatusCode(response) |  | ||||||
| 
 | 
 | ||||||
|           if (response.status === 204) return resolve(undefined) |           if (response.status === 204) return resolve(undefined) | ||||||
| 
 | 
 | ||||||
|           const json = await response.json() |           const json: any = await response.json() | ||||||
|  |           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|  |           this.handleStatusCode(response, json, requestData) | ||||||
|  | 
 | ||||||
|           if ( |           if ( | ||||||
|             json.retry_after !== undefined || |             json.retry_after !== undefined || | ||||||
|             json.message === 'You are being rate limited.' |             json.message === 'You are being rate limited.' | ||||||
|  |  | ||||||
|  | @ -1,48 +0,0 @@ | ||||||
| import { Client } from '../models/client.ts' |  | ||||||
| import { GuildTextChannelPayload, Overwrite } from '../types/channel.ts' |  | ||||||
| import { TextChannel } from './textChannel.ts' |  | ||||||
| import { Guild } from './guild.ts' |  | ||||||
| 
 |  | ||||||
| export class GuildTextChannel extends TextChannel { |  | ||||||
|   guildID: string |  | ||||||
|   name: string |  | ||||||
|   position: number |  | ||||||
|   permissionOverwrites: Overwrite[] |  | ||||||
|   nsfw: boolean |  | ||||||
|   parentID?: string |  | ||||||
|   rateLimit: number |  | ||||||
|   topic?: string |  | ||||||
|   guild: Guild |  | ||||||
| 
 |  | ||||||
|   get mention (): string { |  | ||||||
|     return `<#${this.id}>` |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   constructor (client: Client, data: GuildTextChannelPayload, guild: Guild) { |  | ||||||
|     super(client, data) |  | ||||||
|     this.guildID = data.guild_id |  | ||||||
|     this.name = data.name |  | ||||||
|     this.guild = guild |  | ||||||
|     this.position = data.position |  | ||||||
|     this.permissionOverwrites = data.permission_overwrites |  | ||||||
|     this.nsfw = data.nsfw |  | ||||||
|     this.parentID = data.parent_id |  | ||||||
|     this.topic = data.topic |  | ||||||
|     this.rateLimit = data.rate_limit_per_user |  | ||||||
|     // TODO: Cache in Gateway Event Code
 |  | ||||||
|     // cache.set('guildtextchannel', this.id, this)
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   protected readFromData (data: GuildTextChannelPayload): void { |  | ||||||
|     super.readFromData(data) |  | ||||||
|     this.guildID = data.guild_id ?? this.guildID |  | ||||||
|     this.name = data.name ?? this.name |  | ||||||
|     this.position = data.position ?? this.position |  | ||||||
|     this.permissionOverwrites = |  | ||||||
|       data.permission_overwrites ?? this.permissionOverwrites |  | ||||||
|     this.nsfw = data.nsfw ?? this.nsfw |  | ||||||
|     this.parentID = data.parent_id ?? this.parentID |  | ||||||
|     this.topic = data.topic ?? this.topic |  | ||||||
|     this.rateLimit = data.rate_limit_per_user ?? this.rateLimit |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -1,28 +1,30 @@ | ||||||
|  | import { MemberRolesManager } from "../managers/memberRoles.ts" | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { MemberPayload } from '../types/guild.ts' | import { MemberPayload } from '../types/guild.ts' | ||||||
| import { Base } from './base.ts' | import { Base } from './base.ts' | ||||||
| import { Role } from './role.ts' | import { Guild } from "./guild.ts" | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
| 
 | 
 | ||||||
| export class Member extends Base { | export class Member extends Base { | ||||||
|   id: string |   id: string | ||||||
|   user: User |   user: User | ||||||
|   nick?: string |   nick?: string | ||||||
|   roleIDs: string[] |   roles: MemberRolesManager | ||||||
|   roles: Role[] = [] |  | ||||||
|   joinedAt: string |   joinedAt: string | ||||||
|   premiumSince?: string |   premiumSince?: string | ||||||
|   deaf: boolean |   deaf: boolean | ||||||
|   mute: boolean |   mute: boolean | ||||||
|  |   guild: Guild | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, data: MemberPayload, user: User) { |   constructor (client: Client, data: MemberPayload, user: User, guild: Guild) { | ||||||
|     super(client) |     super(client) | ||||||
|     this.id = data.user.id |     this.id = data.user.id | ||||||
|     this.user = user |     this.user = user | ||||||
|     // this.user =
 |     // this.user =
 | ||||||
|     //   cache.get('user', data.user.id) ?? new User(this.client, data.user)
 |     //   cache.get('user', data.user.id) ?? new User(this.client, data.user)
 | ||||||
|     this.nick = data.nick |     this.nick = data.nick | ||||||
|     this.roleIDs = data.roles |     this.guild = guild | ||||||
|  |     this.roles = new MemberRolesManager(this.client, this.guild.roles, this) | ||||||
|     this.joinedAt = data.joined_at |     this.joinedAt = data.joined_at | ||||||
|     this.premiumSince = data.premium_since |     this.premiumSince = data.premium_since | ||||||
|     this.deaf = data.deaf |     this.deaf = data.deaf | ||||||
|  | @ -34,7 +36,6 @@ export class Member extends Base { | ||||||
|   protected readFromData (data: MemberPayload): void { |   protected readFromData (data: MemberPayload): void { | ||||||
|     super.readFromData(data.user) |     super.readFromData(data.user) | ||||||
|     this.nick = data.nick ?? this.nick |     this.nick = data.nick ?? this.nick | ||||||
|     this.roleIDs = data.roles ?? this.roles.map(r => r.id) |  | ||||||
|     this.joinedAt = data.joined_at ?? this.joinedAt |     this.joinedAt = data.joined_at ?? this.joinedAt | ||||||
|     this.premiumSince = data.premium_since ?? this.premiumSince |     this.premiumSince = data.premium_since ?? this.premiumSince | ||||||
|     this.deaf = data.deaf ?? this.deaf |     this.deaf = data.deaf ?? this.deaf | ||||||
|  |  | ||||||
|  | @ -19,9 +19,9 @@ import { TextChannel } from './textChannel.ts' | ||||||
| import { DMChannel } from './dmChannel.ts' | import { DMChannel } from './dmChannel.ts' | ||||||
| import { Guild } from './guild.ts' | import { Guild } from './guild.ts' | ||||||
| 
 | 
 | ||||||
|  | type AllMessageOptions = MessageOption | Embed | ||||||
|  | 
 | ||||||
| export class Message extends Base { | export class Message extends Base { | ||||||
|   // eslint-disable-next-line @typescript-eslint/prefer-readonly
 |  | ||||||
|   private data: MessagePayload |  | ||||||
|   id: string |   id: string | ||||||
|   channelID: string |   channelID: string | ||||||
|   channel: TextChannel |   channel: TextChannel | ||||||
|  | @ -53,26 +53,19 @@ export class Message extends Base { | ||||||
|     client: Client, |     client: Client, | ||||||
|     data: MessagePayload, |     data: MessagePayload, | ||||||
|     channel: TextChannel, |     channel: TextChannel, | ||||||
|     author: User, |     author: User | ||||||
|     mentions: MessageMentions |  | ||||||
|   ) { |   ) { | ||||||
|     super(client) |     super(client) | ||||||
|     this.data = data |  | ||||||
|     this.id = data.id |     this.id = data.id | ||||||
|     this.channelID = data.channel_id |     this.channelID = data.channel_id | ||||||
|     this.guildID = data.guild_id |     this.guildID = data.guild_id | ||||||
|     this.author = author |     this.author = author | ||||||
|     // this.author =
 |  | ||||||
|     //   this.client.users.get(data.author.id) || new User(this.client, data.author)
 |  | ||||||
|     this.content = data.content |     this.content = data.content | ||||||
|     this.timestamp = data.timestamp |     this.timestamp = data.timestamp | ||||||
|     this.editedTimestamp = data.edited_timestamp |     this.editedTimestamp = data.edited_timestamp | ||||||
|     this.tts = data.tts |     this.tts = data.tts | ||||||
|     this.mentionEveryone = data.mention_everyone |     this.mentionEveryone = data.mention_everyone | ||||||
|     this.mentions = mentions |     this.mentions = new MessageMentions(this.client, this) | ||||||
|     // this.mentions = data.mentions.map(
 |  | ||||||
|     //   v => this.client.users.get(v.id) || new User(client, v)
 |  | ||||||
|     // )
 |  | ||||||
|     this.mentionRoles = data.mention_roles |     this.mentionRoles = data.mention_roles | ||||||
|     this.mentionChannels = data.mention_channels |     this.mentionChannels = data.mention_channels | ||||||
|     this.attachments = data.attachments |     this.attachments = data.attachments | ||||||
|  | @ -87,27 +80,17 @@ export class Message extends Base { | ||||||
|     this.messageReference = data.message_reference |     this.messageReference = data.message_reference | ||||||
|     this.flags = data.flags |     this.flags = data.flags | ||||||
|     this.channel = channel |     this.channel = channel | ||||||
|     // TODO: Cache in Gateway Event Code
 |  | ||||||
|     // if (!noSave) this.client.messages.set(this.id, data)
 |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected readFromData (data: MessagePayload): void { |   protected readFromData (data: MessagePayload): void { | ||||||
|     super.readFromData(data) |     super.readFromData(data) | ||||||
|     this.channelID = data.channel_id ?? this.channelID |     this.channelID = data.channel_id ?? this.channelID | ||||||
|     this.guildID = data.guild_id ?? this.guildID |     this.guildID = data.guild_id ?? this.guildID | ||||||
|     // this.author =
 |  | ||||||
|     //   this.client.users.get(data.author.id) ||
 |  | ||||||
|     //   this.author ||
 |  | ||||||
|     //   new User(this.client, data.author)
 |  | ||||||
|     this.content = data.content ?? this.content |     this.content = data.content ?? this.content | ||||||
|     this.timestamp = data.timestamp ?? this.timestamp |     this.timestamp = data.timestamp ?? this.timestamp | ||||||
|     this.editedTimestamp = data.edited_timestamp ?? this.editedTimestamp |     this.editedTimestamp = data.edited_timestamp ?? this.editedTimestamp | ||||||
|     this.tts = data.tts ?? this.tts |     this.tts = data.tts ?? this.tts | ||||||
|     this.mentionEveryone = data.mention_everyone ?? this.mentionEveryone |     this.mentionEveryone = data.mention_everyone ?? this.mentionEveryone | ||||||
|     // this.mentions =
 |  | ||||||
|     //   data.mentions.map(
 |  | ||||||
|     //     v => this.client.users.get(v.id) || new User(this.client, v)
 |  | ||||||
|     //   ) ?? this.mentions
 |  | ||||||
|     this.mentionRoles = data.mention_roles ?? this.mentionRoles |     this.mentionRoles = data.mention_roles ?? this.mentionRoles | ||||||
|     this.mentionChannels = data.mention_channels ?? this.mentionChannels |     this.mentionChannels = data.mention_channels ?? this.mentionChannels | ||||||
|     this.attachments = data.attachments ?? this.attachments |     this.attachments = data.attachments ?? this.attachments | ||||||
|  | @ -124,13 +107,13 @@ export class Message extends Base { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async edit (text?: string, option?: MessageOption): Promise<Message> { |   async edit (text?: string, option?: MessageOption): Promise<Message> { | ||||||
|     return this.channel.edit(this.id, text, option)   |     return this.channel.editMessage(this.id, text, option)   | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async reply(text: string, options?: MessageOption): Promise<Message> { |   async reply(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise<Message> { | ||||||
|     // TODO: Use inline replies once they're out
 |     // TODO: Use inline replies once they're out
 | ||||||
|     if (this.channel instanceof DMChannel) return this.channel.send(text, options) |     if (this.channel instanceof DMChannel) return this.channel.send(text, option) | ||||||
|     return this.channel.send(`${this.author.mention}, ${text}`, options) |     return this.channel.send(`${this.author.mention}, ${text}`, option) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async delete (): Promise<void> { |   async delete (): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -1,3 +1,55 @@ | ||||||
|  | import { Client } from "../models/client.ts"; | ||||||
|  | import { MessagePayload } from "../types/channel.ts"; | ||||||
|  | import { Collection } from "../utils/collection.ts"; | ||||||
|  | import { GuildTextChannel } from "./textChannel.ts"; | ||||||
|  | import { Message } from "./message.ts"; | ||||||
|  | import { Role } from "./role.ts"; | ||||||
|  | import { User } from "./user.ts"; | ||||||
|  | 
 | ||||||
| export class MessageMentions { | export class MessageMentions { | ||||||
|     str: string = "str" |   client: Client | ||||||
|  |   message: Message | ||||||
|  |   users: Collection<string, User> = new Collection() | ||||||
|  |   roles: Collection<string, Role> = new Collection() | ||||||
|  |   channels: Collection<string, GuildTextChannel> = new Collection() | ||||||
|  |   everyone: boolean = false | ||||||
|  | 
 | ||||||
|  |   static EVERYONE_MENTION = /@(everyone|here)/g | ||||||
|  |   static USER_MENTION = /<@!?(\d{17,19})>/g | ||||||
|  |   static ROLE_MENTION = /<@&(\d{17,19})>/g | ||||||
|  |   static CHANNEL_MENTION = /<#(\d{17,19})>/g | ||||||
|  | 
 | ||||||
|  |   constructor(client: Client, message: Message) { | ||||||
|  |     this.client = client | ||||||
|  |     this.message = message | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { | ||||||
|  |     payload.mentions.forEach(rawUser => { | ||||||
|  |       this.users.set(rawUser.id, new User(this.client, rawUser)) | ||||||
|  |     }) | ||||||
|  |      | ||||||
|  |     if (this.message.guild !== undefined) { | ||||||
|  |       for (const id of payload.mention_roles) { | ||||||
|  |         const role = await this.message.guild.roles.get(id) | ||||||
|  |         if(role !== undefined) this.roles.set(role.id, role) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (payload.mention_channels !== undefined) { | ||||||
|  |       for (const mentionChannel of payload.mention_channels) { | ||||||
|  |         const channel = await this.client.channels.get<GuildTextChannel>(mentionChannel.id) | ||||||
|  |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     const matchChannels = this.message.content.match(MessageMentions.CHANNEL_MENTION) | ||||||
|  |     if (matchChannels !== null) { | ||||||
|  |       for (const id of matchChannels) { | ||||||
|  |         const parsedID = id.substr(2, id.length - 3) | ||||||
|  |         const channel = await this.client.channels.get<GuildTextChannel>(parsedID) | ||||||
|  |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     this.everyone = payload.mention_everyone | ||||||
|  |     return this | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,6 +16,8 @@ export class Role extends Base { | ||||||
|     return `<@&${this.id}>` |     return `<@&${this.id}>` | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   toString(): string { return this.mention } | ||||||
|  | 
 | ||||||
|   constructor (client: Client, data: RolePayload) { |   constructor (client: Client, data: RolePayload) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.id = data.id |     this.id = data.id | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { MessageOption, TextChannelPayload } from '../types/channel.ts' | import { GuildTextChannelPayload, MessageOption, Overwrite, TextChannelPayload } from '../types/channel.ts' | ||||||
| import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' | import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' | ||||||
| import { Channel } from './channel.ts' | import { Channel } from './channel.ts' | ||||||
| import { Embed } from './embed.ts' | import { Embed } from './embed.ts' | ||||||
|  | import { Guild } from "./guild.ts" | ||||||
| import { Message } from './message.ts' | import { Message } from './message.ts' | ||||||
| import { MessageMentions } from './messageMentions.ts' |  | ||||||
| 
 | 
 | ||||||
| type AllMessageOptions = MessageOption | Embed | type AllMessageOptions = MessageOption | Embed | ||||||
| 
 | 
 | ||||||
|  | @ -16,8 +16,6 @@ export class TextChannel extends Channel { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.lastMessageID = data.last_message_id |     this.lastMessageID = data.last_message_id | ||||||
|     this.lastPinTimestamp = data.last_pin_timestamp |     this.lastPinTimestamp = data.last_pin_timestamp | ||||||
|     // TODO: Cache in Gateway Event Code
 |  | ||||||
|     // cache.set('textchannel', this.id, this)
 |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected readFromData (data: TextChannelPayload): void { |   protected readFromData (data: TextChannelPayload): void { | ||||||
|  | @ -46,10 +44,12 @@ export class TextChannel extends Channel { | ||||||
|         allowed_mentions: option?.allowedMention |         allowed_mentions: option?.allowedMention | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
|     return new Message(this.client, resp as any, this, this.client.user as any, new MessageMentions()) |     const res = new Message(this.client, resp, this, this.client.user as any) | ||||||
|  |     await res.mentions.fromPayload(resp) | ||||||
|  |     return res | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async edit ( |   async editMessage ( | ||||||
|     message: Message | string, |     message: Message | string, | ||||||
|     text?: string, |     text?: string, | ||||||
|     option?: MessageOption |     option?: MessageOption | ||||||
|  | @ -76,9 +76,54 @@ export class TextChannel extends Channel { | ||||||
|       } |       } | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     // TODO: Actually construct this object
 |     const res = new Message(this.client, newMsg, this, this.client.user) | ||||||
|     const mentions = new MessageMentions() |     await res.mentions.fromPayload(newMsg) | ||||||
|  |     return res | ||||||
|  |   } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     return new Message(this.client, newMsg, this, this.client.user, mentions) | export class GuildTextChannel extends TextChannel { | ||||||
|  |   guildID: string | ||||||
|  |   name: string | ||||||
|  |   position: number | ||||||
|  |   permissionOverwrites: Overwrite[] | ||||||
|  |   nsfw: boolean | ||||||
|  |   parentID?: string | ||||||
|  |   rateLimit: number | ||||||
|  |   topic?: string | ||||||
|  |   guild: Guild | ||||||
|  | 
 | ||||||
|  |   get mention (): string { | ||||||
|  |     return `<#${this.id}>` | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   toString(): string { | ||||||
|  |     return this.mention | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   constructor (client: Client, data: GuildTextChannelPayload, guild: Guild) { | ||||||
|  |     super(client, data) | ||||||
|  |     this.guildID = data.guild_id | ||||||
|  |     this.name = data.name | ||||||
|  |     this.guild = guild | ||||||
|  |     this.position = data.position | ||||||
|  |     this.permissionOverwrites = data.permission_overwrites | ||||||
|  |     this.nsfw = data.nsfw | ||||||
|  |     this.parentID = data.parent_id | ||||||
|  |     this.topic = data.topic | ||||||
|  |     this.rateLimit = data.rate_limit_per_user | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected readFromData (data: GuildTextChannelPayload): void { | ||||||
|  |     super.readFromData(data) | ||||||
|  |     this.guildID = data.guild_id ?? this.guildID | ||||||
|  |     this.name = data.name ?? this.name | ||||||
|  |     this.position = data.position ?? this.position | ||||||
|  |     this.permissionOverwrites = | ||||||
|  |       data.permission_overwrites ?? this.permissionOverwrites | ||||||
|  |     this.nsfw = data.nsfw ?? this.nsfw | ||||||
|  |     this.parentID = data.parent_id ?? this.parentID | ||||||
|  |     this.topic = data.topic ?? this.topic | ||||||
|  |     this.rateLimit = data.rate_limit_per_user ?? this.rateLimit | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,12 +1,10 @@ | ||||||
| import { CommandClient, Intents } from '../../mod.ts' | import { CommandClient, Intents } from '../../mod.ts' | ||||||
| import PingCommand from './cmds/ping.ts' |  | ||||||
| import AddEmojiCommand from './cmds/addemoji.ts' |  | ||||||
| import UserinfoCommand from './cmds/userinfo.ts' |  | ||||||
| import { TOKEN } from './config.ts' | import { TOKEN } from './config.ts' | ||||||
| 
 | 
 | ||||||
| const client = new CommandClient({ | const client = new CommandClient({ | ||||||
|   prefix: ["pls", "!"], |   prefix: ["pls", "!"], | ||||||
|   spacesAfterPrefix: true |   spacesAfterPrefix: true, | ||||||
|  |   mentionPrefix: true | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('debug', console.log) | client.on('debug', console.log) | ||||||
|  | @ -15,10 +13,23 @@ client.on('ready', () => { | ||||||
|   console.log(`[Login] Logged in as ${client.user?.tag}!`) |   console.log(`[Login] Logged in as ${client.user?.tag}!`) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | // client.on('messageCreate', msg => console.log(`${msg.author.tag}: ${msg.content}`))
 | ||||||
|  | 
 | ||||||
| client.on("commandError", console.error) | client.on("commandError", console.error) | ||||||
| 
 | 
 | ||||||
| client.commands.add(PingCommand) | // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
| client.commands.add(UserinfoCommand) | ;(async() => { | ||||||
| client.commands.add(AddEmojiCommand) |   const files = Deno.readDirSync('./src/test/cmds') | ||||||
|  | 
 | ||||||
|  |   for (const file of files) { | ||||||
|  |     const module = await import(`./cmds/${file.name}`) | ||||||
|  |     // eslint-disable-next-line new-cap
 | ||||||
|  |     const cmd = new module.default() | ||||||
|  |     client.commands.add(cmd) | ||||||
|  |     console.log(`Loaded command ${cmd.name}!`) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   console.log(`Loaded ${client.commands.count} commands!`) | ||||||
| 
 | 
 | ||||||
|   client.connect(TOKEN, Intents.All) |   client.connect(TOKEN, Intents.All) | ||||||
|  | })() | ||||||
							
								
								
									
										18
									
								
								src/test/cmds/mentions.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/test/cmds/mentions.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | import { Command, Embed } from '../../../mod.ts' | ||||||
|  | import { CommandContext } from '../../models/command.ts' | ||||||
|  | 
 | ||||||
|  | export default class PingCommand extends Command { | ||||||
|  |   name = "mentions" | ||||||
|  |   aliases = ["m"] | ||||||
|  | 
 | ||||||
|  |   execute(ctx: CommandContext): void { | ||||||
|  |     const embed = new Embed() | ||||||
|  |       .setTitle('Mentions') | ||||||
|  |       .addField('Users', `${ctx.message.mentions.users.size === 0 ? `None` : ''}${ctx.message.mentions.users.map(u => u.toString()).join(", ")}`) | ||||||
|  |       .addField('Channels', `${ctx.message.mentions.channels.size === 0 ? `None` : ''}${ctx.message.mentions.channels.map(u => u.toString()).join(", ")}`) | ||||||
|  |       .addField('Roles', `${ctx.message.mentions.roles.size === 0 ? `None` : ''}${ctx.message.mentions.roles.map(u => u.toString()).join(", ")}`) | ||||||
|  |       .addField('Everyone?', ctx.message.mentions.everyone === true ? 'Yes' : 'No') | ||||||
|  |       .setColor(0xff0000) | ||||||
|  |     ctx.message.channel.send(embed) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -3,14 +3,17 @@ import { Command, Member, CommandContext, Embed } from '../../../mod.ts' | ||||||
| export default class UserinfoCommand extends Command { | export default class UserinfoCommand extends Command { | ||||||
|     name = "userinfo" |     name = "userinfo" | ||||||
|     guildOnly = true |     guildOnly = true | ||||||
|  |     aliases = [ 'u', 'user' ] | ||||||
| 
 | 
 | ||||||
|     execute(ctx: CommandContext): void { |     async execute(ctx: CommandContext): Promise<void> { | ||||||
|         const member: Member = ctx.message.member as any |         const member: Member = ctx.message.member as any | ||||||
|  |         const roles = await member.roles.array() | ||||||
|         const embed = new Embed() |         const embed = new Embed() | ||||||
|         .setTitle(`User Info`) |         .setTitle(`User Info`) | ||||||
|         .setAuthor({ name: member.user.tag }) |         .setAuthor({ name: member.user.tag }) | ||||||
|         .addField("ID", member.id) |         .addField("ID", member.id) | ||||||
|         .addField("Roles", member.roles.map(r => r.name).join(", ")) |         .addField("Roles", roles.map(r => r.name).join(", ")) | ||||||
|  |         .setColor(0xff00ff) | ||||||
|         ctx.channel.send(embed) |         ctx.channel.send(embed) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -15,8 +15,7 @@ import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | ||||||
| import { NewsChannel } from '../structures/guildNewsChannel.ts' | import { NewsChannel } from '../structures/guildNewsChannel.ts' | ||||||
| import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { GuildTextChannel } from '../structures/guildTextChannel.ts' | import { TextChannel, GuildTextChannel } from '../structures/textChannel.ts' | ||||||
| import { TextChannel } from '../structures/textChannel.ts' |  | ||||||
| 
 | 
 | ||||||
| const getChannelByType = ( | const getChannelByType = ( | ||||||
|   client: Client, |   client: Client, | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								src/utils/mixedPromise.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/utils/mixedPromise.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | export const awaitSync = async(val: any | Promise<any>): Promise<any> => { | ||||||
|  |     return val instanceof Promise ? await val : val | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue