feat(slash): many new things

This commit is contained in:
DjDeveloperr 2020-12-10 12:25:52 +05:30
parent d14fe15d68
commit 6e014b353e
7 changed files with 256 additions and 7 deletions

View File

@ -54,6 +54,7 @@ import {
EveryTextChannelTypes
} from '../../utils/getChannelByType.ts'
import { interactionCreate } from './interactionCreate.ts'
import { Interaction } from '../../structures/slash.ts'
export const gatewayHandlers: {
[eventCode in GatewayEvents]: GatewayEventHandler | undefined
@ -328,4 +329,8 @@ export interface ClientEvents extends EventTypes {
* @param channel Channel of which Webhooks were updated
*/
webhooksUpdate: (guild: Guild, channel: GuildTextChannel) => void
/**
* A Slash Command was triggered
*/
interactionCreate: (interaction: Interaction) => void
}

View File

@ -1,4 +1,6 @@
import { Member } from '../../structures/member.ts'
import { Interaction } from '../../structures/slash.ts'
import { GuildTextChannel } from '../../structures/textChannel.ts'
import { InteractionPayload } from '../../types/slash.ts'
import { Gateway, GatewayEventHandler } from '../index.ts'
@ -6,6 +8,22 @@ export const interactionCreate: GatewayEventHandler = async (
gateway: Gateway,
d: InteractionPayload
) => {
const interaction = new Interaction(gateway.client, d)
const guild = await gateway.client.guilds.get(d.guild_id)
if (guild === undefined) return
await guild.members.set(d.member.user.id, d.member)
const member = ((await guild.members.get(
d.member.user.id
)) as unknown) as Member
const channel =
(await gateway.client.channels.get<GuildTextChannel>(d.channel_id)) ??
(await gateway.client.channels.fetch<GuildTextChannel>(d.channel_id))
const interaction = new Interaction(gateway.client, d, {
member,
guild,
channel
})
gateway.client.emit('interactionCreate', interaction)
}

View File

@ -12,6 +12,7 @@ import { EmojisManager } from '../managers/emojis.ts'
import { ActivityGame, ClientActivity } from '../types/presence.ts'
import { ClientEvents } from '../gateway/handlers/index.ts'
import { Extension } from './extensions.ts'
import { SlashClient } from './slashClient.ts'
/** OS related properties sent with Gateway Identify */
export interface ClientProperties {
@ -72,6 +73,8 @@ export class Client extends EventEmitter {
fetchUncachedReactions: boolean = false
/** Client Properties */
clientProperties: ClientProperties
/** Slash-Commands Management client */
slash: SlashClient
users: UsersManager = new UsersManager(this)
guilds: GuildManager = new GuildManager(this)
@ -133,6 +136,8 @@ export class Client extends EventEmitter {
device: 'harmony'
}
: options.clientProperties
this.slash = new SlashClient(this)
}
/**

144
src/models/slashClient.ts Normal file
View File

@ -0,0 +1,144 @@
import { Guild } from '../structures/guild.ts'
import { Interaction } from '../structures/slash.ts'
import {
APPLICATION_COMMAND,
APPLICATION_COMMANDS,
APPLICATION_GUILD_COMMAND,
APPLICATION_GUILD_COMMANDS
} from '../types/endpoint.ts'
import {
SlashCommandOption,
SlashCommandPartial,
SlashCommandPayload
} from '../types/slash.ts'
import { Collection } from '../utils/collection.ts'
import { Client } from './client.ts'
export interface SlashOptions {
enabled?: boolean
}
export class SlashCommand {
id: string
applicationID: string
name: string
description: string
options: SlashCommandOption[]
constructor(data: SlashCommandPayload) {
this.id = data.id
this.applicationID = data.application_id
this.name = data.name
this.description = data.description
this.options = data.options
}
}
export class SlashCommands {
client: Client
slash: SlashClient
constructor(client: Client) {
this.client = client
this.slash = client.slash
}
/** Get all Global Slash Commands */
async all(): Promise<Collection<string, SlashCommand>> {
const col = new Collection<string, SlashCommand>()
const res = (await this.client.rest.get(
APPLICATION_COMMANDS(this.client.user?.id as string)
)) as SlashCommandPayload[]
if (!Array.isArray(res)) return col
for (const raw of res) {
col.set(raw.id, new SlashCommand(raw))
}
return col
}
/** Get a Guild's Slash Commands */
async guild(
guild: Guild | string
): Promise<Collection<string, SlashCommand>> {
const col = new Collection<string, SlashCommand>()
const res = (await this.client.rest.get(
APPLICATION_GUILD_COMMANDS(
this.client.user?.id as string,
typeof guild === 'string' ? guild : guild.id
)
)) as SlashCommandPayload[]
if (!Array.isArray(res)) return col
for (const raw of res) {
col.set(raw.id, new SlashCommand(raw))
}
return col
}
/** Create a Slash Command (global or Guild) */
async create(
data: SlashCommandPartial,
guild?: Guild | string
): Promise<SlashCommand> {
const payload = await this.client.rest.post(
guild === undefined
? APPLICATION_COMMANDS(this.client.user?.id as string)
: APPLICATION_GUILD_COMMANDS(
this.client.user?.id as string,
typeof guild === 'string' ? guild : guild.id
),
data
)
return new SlashCommand(payload)
}
async edit(
id: string,
data: SlashCommandPayload,
guild?: Guild
): Promise<SlashCommands> {
await this.client.rest.patch(
guild === undefined
? APPLICATION_COMMAND(this.client.user?.id as string, id)
: APPLICATION_GUILD_COMMAND(
this.client.user?.id as string,
typeof guild === 'string' ? guild : guild.id,
id
),
data
)
return this
}
}
export class SlashClient {
client: Client
enabled: boolean = true
commands: SlashCommands
constructor(client: Client, options?: SlashOptions) {
this.client = client
this.commands = new SlashCommands(client)
if (options !== undefined) {
this.enabled = options.enabled ?? true
}
this.client.on('interactionCreate', (interaction) =>
this.process(interaction)
)
}
process(interaction: Interaction): any {}
handle(fn: (interaction: Interaction) => any): SlashClient {
this.process = fn
return this
}
}

View File

@ -1,6 +1,5 @@
import { Client } from '../models/client.ts'
import { INTERACTION_CALLBACK } from '../types/endpoint.ts'
import { MemberPayload } from '../types/guild.ts'
import {
InteractionData,
InteractionPayload,
@ -8,6 +7,10 @@ import {
InteractionResponseType
} from '../types/slash.ts'
import { Embed } from './embed.ts'
import { Guild } from './guild.ts'
import { Member } from './member.ts'
import { GuildTextChannel } from './textChannel.ts'
import { User } from './user.ts'
export interface InteractionResponse {
type?: InteractionResponseType
@ -21,17 +24,37 @@ export class Interaction {
client: Client
type: number
token: string
member: MemberPayload
id: string
data: InteractionData
channel: GuildTextChannel
guild: Guild
member: Member
constructor(client: Client, data: InteractionPayload) {
constructor(
client: Client,
data: InteractionPayload,
others: {
channel: GuildTextChannel
guild: Guild
member: Member
}
) {
this.client = client
this.type = data.type
this.token = data.token
this.member = data.member
this.member = others.member
this.id = data.id
this.data = data.data
this.guild = others.guild
this.channel = others.channel
}
get user(): User {
return this.member.user
}
get name(): string {
return this.data.name
}
async respond(data: InteractionResponse): Promise<Interaction> {

View File

@ -1,15 +1,62 @@
import { Client, Intents } from '../../mod.ts'
import { SlashCommandOptionType } from '../types/slash.ts'
import { TOKEN } from './config.ts'
const client = new Client()
client.on('ready', () => {
console.log('Logged in!')
client.slash.commands
.create(
{
name: 'eval',
description: 'Run some JS code!',
options: [
{
name: 'code',
description: 'Code to run',
type: SlashCommandOptionType.STRING,
required: true
}
]
},
'783319033205751809'
)
.then(console.log)
})
client.on('interactionCreate', async (d) => {
if (d.name === 'eval') {
if (d.user.id !== '422957901716652033') {
d.respond({
content: 'This command can only be used by owner!'
})
} else {
const code = d.data.options.find((e) => e.name === 'code')
?.value as string
try {
// eslint-disable-next-line no-eval
let evaled = eval(code)
if (evaled instanceof Promise) evaled = await evaled
if (typeof evaled === 'object') evaled = Deno.inspect(evaled)
let res = `${evaled}`.substring(0, 1990)
while (client.token !== undefined && res.includes(client.token)) {
res = res.replace(client.token, '[REMOVED]')
}
d.respond({
content: '```js\n' + `${res}` + '\n```'
})
} catch (e) {
d.respond({
content: '```js\n' + `${e.stack}` + '\n```'
})
}
}
return
}
await d.respond({
content: `Hi, ${d.member.user.username}!`
content: `Hi, ${d.member.user.username}!`,
flags: 64
})
})

View File

@ -24,6 +24,8 @@ export interface InteractionPayload {
member: MemberPayload
id: string
data: InteractionData
guild_id: string
channel_id: string
}
export interface SlashCommandChoice {
@ -50,12 +52,17 @@ export interface SlashCommandOption {
choices?: SlashCommandChoice[]
}
export interface SlashCommandPayload {
export interface SlashCommandPartial {
name: string
description: string
options: SlashCommandOption[]
}
export interface SlashCommandPayload extends SlashCommandPartial {
id: string
application_id: string
}
export enum InteractionResponseType {
PONG = 1,
ACKNOWLEDGE = 2,