diff --git a/LICENSE b/LICENSE index c4a1919..c52f6d0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Helloyunho +Copyright (c) 2020 Harmony Org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 52f1bc9..90af8c8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![banner](banner.png) -[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) [![Discord](https://img.shields.io/discord/591914197219016707.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/WVN2JF2FRv) **An easy to use Discord API Library for Deno.** * Lightweight and easy to use. @@ -22,6 +22,7 @@ Note: Library is yet under development and not completely usable. You're still a - [Usage](#usage) - [Docs](#docs) +- [Discord](#discord) - [Maintainer](#maintainer) - [Contributing](#contributing) - [License](#license) @@ -92,6 +93,10 @@ client.connect('super secret token comes here', Intents.All) Not made yet. +## Discord + +[![Widget for the Discord Server](https://discord.com/api/guilds/783319033205751809/widget.png?style=banner1)](https://discord.gg/WVN2JF2FRv) + ## Maintainer [@Helloyunho](https://github.com/Helloyunho) @@ -106,4 +111,4 @@ Small note: If editing the README, please conform to the [standard-readme](https ## License -[MIT © 2020 Helloyunho](LICENSE) +[MIT © 2020 Harmony Org](LICENSE) diff --git a/src/gateway/handlers/index.ts b/src/gateway/handlers/index.ts index 2168667..f67a7bc 100644 --- a/src/gateway/handlers/index.ts +++ b/src/gateway/handlers/index.ts @@ -45,6 +45,8 @@ import { messageReactionRemoveAll } from './messageReactionRemoveAll.ts' import { messageReactionRemoveEmoji } from './messageReactionRemoveEmoji.ts' import { guildMembersChunk } from './guildMembersChunk.ts' import { presenceUpdate } from './presenceUpdate.ts' +import { inviteCreate } from './inviteCreate.ts' +import { inviteDelete } from './inviteDelete.ts' export const gatewayHandlers: { [eventCode in GatewayEvents]: GatewayEventHandler | undefined @@ -70,8 +72,8 @@ export const gatewayHandlers: { GUILD_ROLE_CREATE: guildRoleCreate, GUILD_ROLE_UPDATE: guildRoleUpdate, GUILD_ROLE_DELETE: guildRoleDelete, - INVITE_CREATE: undefined, - INVITE_DELETE: undefined, + INVITE_CREATE: inviteCreate, + INVITE_DELETE: inviteDelete, MESSAGE_CREATE: messageCreate, MESSAGE_UPDATE: messageUpdate, MESSAGE_DELETE: messageDelete, diff --git a/src/gateway/handlers/inviteCreate.ts b/src/gateway/handlers/inviteCreate.ts new file mode 100644 index 0000000..b1e0f5d --- /dev/null +++ b/src/gateway/handlers/inviteCreate.ts @@ -0,0 +1,40 @@ +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { InviteCreatePayload } from '../../types/gateway.ts' +import { ChannelPayload, GuildPayload, InvitePayload } from '../../../mod.ts' + +export const inviteCreate: GatewayEventHandler = async ( + gateway: Gateway, + d: InviteCreatePayload +) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id!) + + // Weird case, shouldn't happen + if (guild === undefined) return + + /** + * TODO(DjDeveloperr): Add _get method in BaseChildManager + */ + const cachedChannel = await gateway.client.channels._get(d.channel_id) + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const cachedGuild: GuildPayload | undefined = + d.guild_id === undefined + ? undefined + : await guild.client.guilds._get(d.guild_id) + + const dataConverted: InvitePayload = { + code: d.code, + guild: cachedGuild, + // had to use `as ChannelPayload` because the _get method returned `ChannelPayload | undefined` which errored + channel: (cachedChannel as unknown) as ChannelPayload, + inviter: d.inviter, + target_user: d.target_user, + target_user_type: d.target_user_type, + } + + await guild.invites.set(d.code, dataConverted) + const invite = await guild.invites.get(d.code) + gateway.client.emit('inviteCreate', invite) +} diff --git a/src/gateway/handlers/inviteDelete.ts b/src/gateway/handlers/inviteDelete.ts new file mode 100644 index 0000000..8e77d13 --- /dev/null +++ b/src/gateway/handlers/inviteDelete.ts @@ -0,0 +1,34 @@ +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { InviteDeletePayload } from '../../types/gateway.ts' +import { PartialInvitePayload } from '../../types/invite.ts' +import { Channel } from '../../../mod.ts' + +export const inviteDelete: GatewayEventHandler = async ( + gateway: Gateway, + d: InviteDeletePayload +) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id!) + + // Weird case, shouldn't happen + if (guild === undefined) return + + const cachedInvite = await guild.invites.get(d.code) + const cachedChannel = await gateway.client.channels.get(d.channel_id) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const cachedGuild = await gateway.client.guilds.get(d.guild_id!) + + // TODO(DjDeveloperr): Make it support self-bots and make Guild not always defined + if (cachedInvite === undefined) { + const uncachedInvite: PartialInvitePayload = { + guild: (cachedGuild as unknown) as Guild, + channel: (cachedChannel as unknown) as Channel, + code: d.code, + } + return gateway.client.emit('inviteDeleteUncached', uncachedInvite) + } else { + await guild.invites.delete(d.code) + gateway.client.emit('inviteDelete', cachedInvite) + } +} diff --git a/src/managers/invites.ts b/src/managers/invites.ts new file mode 100644 index 0000000..6af3896 --- /dev/null +++ b/src/managers/invites.ts @@ -0,0 +1,41 @@ +import { Client } from '../models/client.ts' +import { Guild } from '../structures/guild.ts' +import { Invite } from '../structures/invite.ts' +import { GUILD_INVITES } from '../types/endpoint.ts' +import { InvitePayload } from '../types/invite.ts' +import { BaseManager } from './base.ts' + +export class InviteManager extends BaseManager { + guild: Guild + + constructor(client: Client, guild: Guild) { + super(client, `invites:${guild.id}`, Invite) + this.guild = guild + } + + async get(key: string): Promise { + const raw = await this._get(key) + if (raw === undefined) return + return new Invite(this.client, raw) + } + + async fetch(id: string): Promise { + return await new Promise((resolve, reject) => { + this.client.rest + .get(GUILD_INVITES(this.guild.id)) + .then(async (data) => { + this.set(id, data as InvitePayload) + const newInvite = await this.get(data.code) + resolve(newInvite) + }) + .catch((e) => reject(e)) + }) + } + + async fromPayload(invites: InvitePayload[]): Promise { + for (const invite of invites) { + await this.set(invite.code, invite) + } + return true + } +} diff --git a/src/structures/guild.ts b/src/structures/guild.ts index 0a5c4c9..d21ceb1 100644 --- a/src/structures/guild.ts +++ b/src/structures/guild.ts @@ -10,6 +10,7 @@ import { import { PresenceUpdatePayload } from '../types/gateway.ts' import { Base } from './base.ts' import { RolesManager } from '../managers/roles.ts' +import { InviteManager } from '../managers/invites.ts' import { GuildChannelsManager } from '../managers/guildChannels.ts' import { MembersManager } from '../managers/members.ts' import { Role } from './role.ts' @@ -132,6 +133,7 @@ export class Guild extends Base { explicitContentFilter?: string roles: RolesManager emojis: GuildEmojisManager + invites: InviteManager features?: GuildFeatures[] mfaLevel?: string applicationID?: string @@ -174,6 +176,7 @@ export class Guild extends Base { ) this.roles = new RolesManager(this.client, this) this.emojis = new GuildEmojisManager(this.client, this.client.emojis, this) + this.invites = new InviteManager(this.client, this) if (!this.unavailable) { this.name = data.name diff --git a/src/test/cmd.ts b/src/test/cmd.ts index 202a859..44772bb 100644 --- a/src/test/cmd.ts +++ b/src/test/cmd.ts @@ -6,6 +6,7 @@ import { CommandContext, Extension, } from '../../mod.ts' +import { Invite } from '../structures/invite.ts' import { TOKEN } from './config.ts' const client = new CommandClient({ @@ -62,6 +63,19 @@ client.on('webhooksUpdate', (guild, channel) => { console.log(`Webhooks Updated in #${channel.name} from ${guild.name}`) }) +client.on('commandError', console.error) +client.on('inviteCreate', (invite: Invite) => { + console.log(`Invite Create: ${invite.code}`) +}) + +client.on('inviteDelete', (invite: Invite) => { + console.log(`Invite Delete: ${invite.code}`) +}) + +client.on('inviteDeleteUncached', (invite: Invite) => { + console.log(invite) +}) + client.on('commandError', console.error) class ChannelLog extends Extension { diff --git a/src/types/invite.ts b/src/types/invite.ts index 6120980..8969897 100644 --- a/src/types/invite.ts +++ b/src/types/invite.ts @@ -1,3 +1,4 @@ +import { Channel, Guild } from "../../mod.ts" import { ChannelPayload } from './channel.ts' import { GuildPayload } from './guild.ts' import { UserPayload } from './user.ts' @@ -12,3 +13,9 @@ export interface InvitePayload { approximate_presence_count?: number approximate_member_count?: number } + +export interface PartialInvitePayload { + code: string + channel: Channel + guild?: Guild +} \ No newline at end of file