more things

This commit is contained in:
DjDeveloperr 2021-01-01 11:25:23 +05:30
parent e3bce85f09
commit c3fafdfcf0
10 changed files with 138 additions and 24 deletions

View file

@ -5,11 +5,14 @@ import { CategoryChannel } from '../structures/guildCategoryChannel.ts'
import { GuildTextChannel } from '../structures/textChannel.ts' import { GuildTextChannel } from '../structures/textChannel.ts'
import { VoiceChannel } from '../structures/guildVoiceChannel.ts' import { VoiceChannel } from '../structures/guildVoiceChannel.ts'
import { import {
ChannelTypes,
GuildCategoryChannelPayload, GuildCategoryChannelPayload,
GuildChannelPayload,
GuildTextChannelPayload, GuildTextChannelPayload,
GuildVoiceChannelPayload GuildVoiceChannelPayload,
Overwrite
} from '../types/channel.ts' } from '../types/channel.ts'
import { CHANNEL } from '../types/endpoint.ts' import { CHANNEL, GUILD_CHANNELS } from '../types/endpoint.ts'
import { BaseChildManager } from './baseChild.ts' import { BaseChildManager } from './baseChild.ts'
import { ChannelsManager } from './channels.ts' import { ChannelsManager } from './channels.ts'
@ -19,6 +22,19 @@ export type GuildChannelPayloads =
| GuildCategoryChannelPayload | GuildCategoryChannelPayload
export type GuildChannel = GuildTextChannel | VoiceChannel | CategoryChannel export type GuildChannel = GuildTextChannel | VoiceChannel | CategoryChannel
export interface CreateChannelOptions {
name: string
type?: ChannelTypes
topic?: string
bitrate?: number
userLimit?: number
rateLimitPerUser?: number
position?: number
permissionOverwrites?: Overwrite[]
parent?: CategoryChannel | string
nsfw?: boolean
}
export class GuildChannelsManager extends BaseChildManager< export class GuildChannelsManager extends BaseChildManager<
GuildChannelPayloads, GuildChannelPayloads,
GuildChannel GuildChannel
@ -55,4 +71,32 @@ export class GuildChannelsManager extends BaseChildManager<
} }
return true return true
} }
/** Create a new Guild Channel */
async create(options: CreateChannelOptions): Promise<GuildChannel> {
if (options.name === undefined)
throw new Error('name is required for GuildChannelsManager#create')
const res = ((await this.client.rest.post(GUILD_CHANNELS(this.guild.id)),
{
name: options.name,
type: options.type,
topic: options.topic,
bitrate: options.bitrate,
user_limit: options.userLimit,
rate_limit_per_user: options.rateLimitPerUser,
position: options.position,
permission_overwrites: options.permissionOverwrites,
parent_id:
options.parent === undefined
? undefined
: typeof options.parent === 'object'
? options.parent.id
: options.parent,
nsfw: options.nsfw
}) as unknown) as GuildChannelPayload
await this.set(res.id, res)
const channel = await this.get(res.id)
return (channel as unknown) as GuildChannel
}
} }

View file

@ -17,6 +17,13 @@ export class GuildVoiceStatesManager extends BaseManager<
this.guild = guild this.guild = guild
} }
/** Get Client's Voice State in the Guild */
async me(): Promise<VoiceState | undefined> {
const member = await this.guild.me()
return await this.get(member.id)
}
/** Get a Voice State by User ID */
async get(key: string): Promise<VoiceState | undefined> { async get(key: string): Promise<VoiceState | undefined> {
const raw = await this._get(key) const raw = await this._get(key)
if (raw === undefined) return if (raw === undefined) return

View file

@ -3,8 +3,13 @@ import { Emoji } from '../structures/emoji.ts'
import { Guild } from '../structures/guild.ts' import { Guild } from '../structures/guild.ts'
import { Message } from '../structures/message.ts' import { Message } from '../structures/message.ts'
import { MessageReaction } from '../structures/messageReaction.ts' import { MessageReaction } from '../structures/messageReaction.ts'
import { User } from '../structures/user.ts'
import { Reaction } from '../types/channel.ts' import { Reaction } from '../types/channel.ts'
import { MESSAGE_REACTION, MESSAGE_REACTIONS } from '../types/endpoint.ts' import {
MESSAGE_REACTION,
MESSAGE_REACTIONS,
MESSAGE_REACTION_USER
} from '../types/endpoint.ts'
import { BaseManager } from './base.ts' import { BaseManager } from './base.ts'
export class MessageReactionsManager extends BaseManager< export class MessageReactionsManager extends BaseManager<
@ -77,4 +82,23 @@ export class MessageReactionsManager extends BaseManager<
) )
return this return this
} }
/** Remove a specific Emoji from Reactions */
async removeUser(
emoji: Emoji | string,
user: User | string
): Promise<MessageReactionsManager> {
const val = encodeURIComponent(
(typeof emoji === 'object' ? emoji.id ?? emoji.name : emoji) as string
)
await this.client.rest.delete(
MESSAGE_REACTION_USER(
this.message.channel.id,
this.message.id,
val,
typeof user === 'string' ? user : user.id
)
)
return this
}
} }

View file

@ -1,5 +1,6 @@
import { Client } from '../models/client.ts' import { Client } from '../models/client.ts'
import { MessageReaction } from '../structures/messageReaction.ts' import { MessageReaction } from '../structures/messageReaction.ts'
import { User } from '../structures/user.ts'
import { UsersManager } from './users.ts' import { UsersManager } from './users.ts'
export class ReactionUsersManager extends UsersManager { export class ReactionUsersManager extends UsersManager {
@ -10,4 +11,14 @@ export class ReactionUsersManager extends UsersManager {
this.cacheName = `reaction_users:${reaction.message.id}` this.cacheName = `reaction_users:${reaction.message.id}`
this.reaction = reaction this.reaction = reaction
} }
/** Remove all Users from this Reaction */
async removeAll(): Promise<void> {
await this.reaction.message.reactions.removeEmoji(this.reaction.emoji)
}
/** Remove a specific User from this Reaction */
async remove(user: User | string): Promise<void> {
await this.reaction.message.reactions.removeUser(this.reaction.emoji, user)
}
} }

View file

@ -134,7 +134,7 @@ export class Client extends EventEmitter {
handler: (interaction: Interaction) => any handler: (interaction: Interaction) => any
}> }>
_decoratedSlashModules?: SlashModule[] _decoratedSlashModules?: string[]
_id?: string _id?: string
/** Shard on which this Client is */ /** Shard on which this Client is */
@ -291,6 +291,7 @@ export class Client extends EventEmitter {
} }
} }
/** Event decorator to create an Event handler from function */
export function event(name?: keyof ClientEvents) { export function event(name?: keyof ClientEvents) {
return function (client: Client | Extension, prop: keyof ClientEvents) { return function (client: Client | Extension, prop: keyof ClientEvents) {
const listener = ((client as unknown) as { const listener = ((client as unknown) as {
@ -311,7 +312,7 @@ export function slash(name?: string, guild?: string) {
if (client._decoratedSlash === undefined) client._decoratedSlash = [] if (client._decoratedSlash === undefined) client._decoratedSlash = []
const item = (client as { [name: string]: any })[prop] const item = (client as { [name: string]: any })[prop]
if (typeof item !== 'function') { if (typeof item !== 'function') {
client._decoratedSlash.push(item) throw new Error('@slash decorator requires a function')
} else } else
client._decoratedSlash.push({ client._decoratedSlash.push({
name: name ?? prop, name: name ?? prop,
@ -327,8 +328,7 @@ export function subslash(parent: string, name?: string, guild?: string) {
if (client._decoratedSlash === undefined) client._decoratedSlash = [] if (client._decoratedSlash === undefined) client._decoratedSlash = []
const item = (client as { [name: string]: any })[prop] const item = (client as { [name: string]: any })[prop]
if (typeof item !== 'function') { if (typeof item !== 'function') {
item.parent = parent throw new Error('@subslash decorator requires a function')
client._decoratedSlash.push(item)
} else } else
client._decoratedSlash.push({ client._decoratedSlash.push({
parent, parent,
@ -350,9 +350,7 @@ export function groupslash(
if (client._decoratedSlash === undefined) client._decoratedSlash = [] if (client._decoratedSlash === undefined) client._decoratedSlash = []
const item = (client as { [name: string]: any })[prop] const item = (client as { [name: string]: any })[prop]
if (typeof item !== 'function') { if (typeof item !== 'function') {
item.parent = parent throw new Error('@groupslash decorator requires a function')
item.group = group
client._decoratedSlash.push(item)
} else } else
client._decoratedSlash.push({ client._decoratedSlash.push({
group, group,

View file

@ -382,6 +382,7 @@ export class CommandClient extends Client implements CommandClientOptions {
} }
} }
/** Command decorator */
export function command(options?: CommandOptions) { export function command(options?: CommandOptions) {
return function (target: CommandClient | Extension, name: string) { return function (target: CommandClient | Extension, name: string) {
if (target._decoratedCommands === undefined) target._decoratedCommands = {} if (target._decoratedCommands === undefined) target._decoratedCommands = {}
@ -390,10 +391,8 @@ export function command(options?: CommandOptions) {
[name: string]: (ctx: CommandContext) => any [name: string]: (ctx: CommandContext) => any
})[name] })[name]
if (prop instanceof Command) { if (typeof prop !== 'function')
target._decoratedCommands[prop.name] = prop throw new Error('@command decorator can only be used on functions')
return
}
const command = new Command() const command = new Command()

View file

@ -14,11 +14,11 @@ import { RESTManager } from './rest.ts'
import { SlashModule } from './slashModule.ts' import { SlashModule } from './slashModule.ts'
import { verify as edverify } from 'https://deno.land/x/ed25519/mod.ts' import { verify as edverify } from 'https://deno.land/x/ed25519/mod.ts'
import { Buffer } from 'https://deno.land/std@0.80.0/node/buffer.ts' import { Buffer } from 'https://deno.land/std@0.80.0/node/buffer.ts'
import { import type {
Request as ORequest, Request as ORequest,
Response as OResponse Response as OResponse
} from 'https://deno.land/x/opine@1.0.0/src/types.ts' } from 'https://deno.land/x/opine@1.0.0/src/types.ts'
import { Context } from 'https://deno.land/x/oak@v6.4.0/mod.ts' import type { Context } from 'https://deno.land/x/oak@v6.4.0/mod.ts'
export class SlashCommand { export class SlashCommand {
slash: SlashCommandsManager slash: SlashCommandsManager
@ -353,7 +353,7 @@ export class SlashClient {
handler: (interaction: Interaction) => any handler: (interaction: Interaction) => any
}> }>
_decoratedSlashModules?: SlashModule[] _decoratedSlashModules?: string[]
constructor(options: SlashOptions) { constructor(options: SlashOptions) {
let id = options.id let id = options.id
@ -378,7 +378,14 @@ export class SlashClient {
if (this.client?._decoratedSlashModules !== undefined) { if (this.client?._decoratedSlashModules !== undefined) {
this.client._decoratedSlashModules.forEach((e) => { this.client._decoratedSlashModules.forEach((e) => {
this.modules.push(e) const mod = ((this.client as unknown) as {
[name: string]: SlashModule
})[e]
if (!(mod instanceof SlashModule))
throw new Error(
'@slashModule can only be used on SlashModule instances'
)
this.modules.push(mod)
}) })
} }
@ -390,7 +397,12 @@ export class SlashClient {
if (this._decoratedSlashModules !== undefined) { if (this._decoratedSlashModules !== undefined) {
this._decoratedSlashModules.forEach((e) => { this._decoratedSlashModules.forEach((e) => {
this.modules.push(e) const mod = ((this as unknown) as { [name: string]: SlashModule })[e]
if (!(mod instanceof SlashModule))
throw new Error(
'@slashModule can only be used on SlashModule instances'
)
this.modules.push(mod)
}) })
} }
@ -418,11 +430,13 @@ export class SlashClient {
return this return this
} }
/** Load a Slash Module */
loadModule(module: SlashModule): SlashClient { loadModule(module: SlashModule): SlashClient {
this.modules.push(module) this.modules.push(module)
return this return this
} }
/** Get all Handlers. Including Slash Modules */
getHandlers(): SlashCommandHandler[] { getHandlers(): SlashCommandHandler[] {
let res = this.handlers let res = this.handlers
for (const mod of this.modules) { for (const mod of this.modules) {
@ -438,6 +452,7 @@ export class SlashClient {
return res return res
} }
/** Get Handler for an Interaction. Supports nested sub commands and sub command groups. */
private _getCommand(i: Interaction): SlashCommandHandler | undefined { private _getCommand(i: Interaction): SlashCommandHandler | undefined {
return this.getHandlers().find((e) => { return this.getHandlers().find((e) => {
const hasGroupOrParent = e.group !== undefined || e.parent !== undefined const hasGroupOrParent = e.group !== undefined || e.parent !== undefined
@ -467,6 +482,10 @@ export class SlashClient {
if (interaction.type !== InteractionType.APPLICATION_COMMAND) return if (interaction.type !== InteractionType.APPLICATION_COMMAND) return
const cmd = this._getCommand(interaction) const cmd = this._getCommand(interaction)
if (cmd?.group !== undefined)
interaction.data.options = interaction.data.options[0].options ?? []
if (cmd?.parent !== undefined)
interaction.data.options = interaction.data.options[0].options ?? []
if (cmd === undefined) return if (cmd === undefined) return

View file

@ -13,8 +13,6 @@ export class GroupDMChannel extends Channel {
this.name = data.name this.name = data.name
this.icon = data.icon this.icon = data.icon
this.ownerID = data.owner_id this.ownerID = data.owner_id
// TODO: Cache in Gateway Event Code
// cache.set('groupchannel', this.id, this)
} }
readFromData(data: GroupDMChannelPayload): void { readFromData(data: GroupDMChannelPayload): void {

View file

@ -8,9 +8,13 @@ import {
IntegrationExpireBehavior IntegrationExpireBehavior
} from '../types/guild.ts' } from '../types/guild.ts'
import { Base } from './base.ts' import { Base } from './base.ts'
import { RolesManager } from '../managers/roles.ts' import { CreateGuildRoleOptions, RolesManager } from '../managers/roles.ts'
import { InviteManager } from '../managers/invites.ts' import { InviteManager } from '../managers/invites.ts'
import { GuildChannelsManager } from '../managers/guildChannels.ts' import {
CreateChannelOptions,
GuildChannel,
GuildChannelsManager
} from '../managers/guildChannels.ts'
import { MembersManager } from '../managers/members.ts' import { MembersManager } from '../managers/members.ts'
import { Role } from './role.ts' import { Role } from './role.ts'
import { GuildEmojisManager } from '../managers/guildEmojis.ts' import { GuildEmojisManager } from '../managers/guildEmojis.ts'
@ -297,6 +301,16 @@ export class Guild extends Base {
return raw.map((e) => new GuildIntegration(this.client, e)) return raw.map((e) => new GuildIntegration(this.client, e))
} }
/** Create a new Guild Channel */
async createChannel(options: CreateChannelOptions): Promise<GuildChannel> {
return this.channels.create(options)
}
/** Create a new Guild Role */
async createRole(options?: CreateGuildRoleOptions): Promise<Role> {
return this.roles.create(options)
}
/** /**
* Chunks the Guild Members, i.e. cache them. * Chunks the Guild Members, i.e. cache them.
* @param options Options regarding the Members Request * @param options Options regarding the Members Request

View file

@ -32,7 +32,7 @@ const GUILD_BANS = (guildID: string): string =>
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/bans` `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/bans`
const GUILD_CHANNEL = (channelID: string): string => const GUILD_CHANNEL = (channelID: string): string =>
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/channels/${channelID}` `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/channels/${channelID}`
const GUILD_CHANNELS = (guildID: string, channelID: string): string => const GUILD_CHANNELS = (guildID: string): string =>
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/channels` `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/channels`
const GUILD_MEMBER = (guildID: string, memberID: string): string => const GUILD_MEMBER = (guildID: string, memberID: string): string =>
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/members/${memberID}` `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/members/${memberID}`