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()
|
this.client,
|
||||||
|
data as MessagePayload,
|
||||||
resolve(
|
channel as TextChannel,
|
||||||
new Message(
|
author
|
||||||
this.client,
|
|
||||||
data as MessagePayload,
|
|
||||||
channel as TextChannel,
|
|
||||||
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,19 +52,29 @@ 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()
|
||||||
return this.list.find((cmd: Command): boolean => {
|
return this.list.find((cmd: Command): boolean => {
|
||||||
const name =
|
const name =
|
||||||
|
@ -79,8 +91,17 @@ 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
|
||||||
if (typeof search === 'string') return this.find(search) !== undefined
|
if (typeof search === 'string') return this.find(search) !== undefined
|
||||||
else {
|
else {
|
||||||
|
@ -97,7 +118,7 @@ export class CommandsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add a Command */
|
/** Add a Command */
|
||||||
add (cmd: Command | typeof Command): boolean {
|
add(cmd: Command | typeof Command): boolean {
|
||||||
// eslint-disable-next-line new-cap
|
// eslint-disable-next-line new-cap
|
||||||
if (!(cmd instanceof Command)) cmd = new cmd()
|
if (!(cmd instanceof Command)) cmd = new cmd()
|
||||||
if (this.exists(cmd)) return false
|
if (this.exists(cmd)) return false
|
||||||
|
@ -106,11 +127,46 @@ export class CommandsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Delete a Command */
|
/** Delete a Command */
|
||||||
delete (cmd: string | Command): boolean {
|
delete(cmd: string | Command): boolean {
|
||||||
const find = typeof cmd === 'string' ? this.find(cmd) : cmd
|
const find = typeof cmd === 'string' ? this.find(cmd) : cmd
|
||||||
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[]
|
||||||
|
@ -58,7 +65,7 @@ export class CommandClient extends Client implements CommandClientOptions {
|
||||||
commands: CommandsManager = new CommandsManager(this)
|
commands: CommandsManager = new CommandsManager(this)
|
||||||
texts: CommandTexts = DefaultCommandTexts
|
texts: CommandTexts = DefaultCommandTexts
|
||||||
|
|
||||||
constructor (options: CommandClientOptions) {
|
constructor(options: CommandClientOptions) {
|
||||||
super(options)
|
super(options)
|
||||||
this.prefix = options.prefix
|
this.prefix = options.prefix
|
||||||
this.mentionPrefix =
|
this.mentionPrefix =
|
||||||
|
@ -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
|
||||||
|
@ -89,29 +108,52 @@ 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 })
|
||||||
|
@ -170,7 +217,7 @@ export class CommandClient extends Client implements CommandClientOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendProcessedText (msg: Message, text: CommandText, replaces: Replaces): any {
|
sendProcessedText(msg: Message, text: CommandText, replaces: Replaces): any {
|
||||||
if (typeof text === 'string') {
|
if (typeof text === 'string') {
|
||||||
text = massReplace(text, replaces)
|
text = massReplace(text, replaces)
|
||||||
return msg.channel.send(text)
|
return msg.channel.send(text)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
||||||
client.connect(TOKEN, Intents.All)
|
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)
|
||||||
|
})()
|
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…
Reference in a new issue