From be906d6f572c9c2f74a87910c82e28d446cdcd28 Mon Sep 17 00:00:00 2001 From: Skillz Date: Fri, 14 Feb 2020 14:05:05 -0500 Subject: [PATCH] channels p1 --- constants/discord.ts | 4 ++ structures/channel.ts | 126 +++++++++++++++++++++++++++++++++++++++++- structures/user.ts | 2 +- types/channel.ts | 51 +++++++++++++++++ types/guild.ts | 11 ++++ 5 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 types/channel.ts diff --git a/constants/discord.ts b/constants/discord.ts index 32eb1e340..9977bdf1d 100644 --- a/constants/discord.ts +++ b/constants/discord.ts @@ -7,6 +7,10 @@ export const baseEndpoints = { export const endpoints = { GATEWAY_BOT: `${baseEndpoints.BASE_URL}/gateway/bot`, + // Channel Endpoints + CHANNEL_MESSAGE: (id: string, message_id: string) => `${baseEndpoints.BASE_URL}/channels/${id}/messages/${message_id}`, + CHANNEL_MESSAGES: (id: string) => `${baseEndpoints.BASE_URL}/channels/${id}` + // Guild Endpoints GUILD: (id: string) => `${baseEndpoints.BASE_URL}/guilds/${id}`, GUILD_AUDIT_LOGS: (id: string) => `${baseEndpoints.BASE_URL}/guilds/${id}/audit-logs`, diff --git a/structures/channel.ts b/structures/channel.ts index 696770aba..811807a7d 100644 --- a/structures/channel.ts +++ b/structures/channel.ts @@ -1,3 +1,125 @@ -export const createChannel = (data: unknown) => { - console.log(data) +import { Channel_Create_Options, Channel_Types } from '../types/channel' +import { Guild, Permission, Permissions } from '../types/guild' +import Client from '../module/client' +import { endpoints } from '../constants/discord' + +export interface MessageContent { + /** The message contents, up to 2000 characters */ + content?: string + /** A nonce that can be used for optimistic message sending. */ + nonce?: number | string + /** Whether this is a TextToSpeech message */ + tts?: boolean + /** The contents of the file being sent */ + file?: File_Content + /** Embed object */ + embed?: Embed_Object + /** JSON encoded body of any additional request fields. */ + payload_json?: string +} + +export const create_channel = (data: Channel_Create_Options, guild: Guild, client: Client) => { + const base_channel = { + id: data.id, + type: () => data.type, + guild_id: () => data.guild_id + } + + const base_text_channel = { + messages: new Map(), + last_message_id: () => data.last_message_id, + get_message: async (id: string) => { + // TODO: check if the user has VIEW_CHANNEL and READ_MESSAGE_HISTORY + const result = await client.RequestManager.get(endpoints.CHANNEL_MESSAGE(data.id, id)) + return create_message(result, client) + }, + get_messages: async (options?: Get_Messages_After | Get_Messages_Before | Get_Messages_Around | Get_Messages) => { + // TODO: check if the user has VIEW_CHANNEL and READ_MESSAGE_HISTORY + if (!options.limit || options.limit <= 100) { + const result = await client.RequestManager.get(endpoints.CHANNEL_MESSAGES(data.id), options) + return result.map(res => create_message(res, client)) + } + + const fetch_messages = () => {} + const + return client.RequestManager.get(endpoints.CHANNEL_MESSAGES(data.id), options) + }, + send_message: async (content: string | MessageContent) => { + if (data.type !== Channel_Types.DM) { + // TODO: check if the bot has SEND_MESSAGES permission + } + + if (typeof content === 'string') content = { content } + if (content.tts) { + // TODO: check if the bot has SEND_TTS_MESSAGE + } + + const result = await client.RequestManager.post(endpoints.CHANNEL_MESSAGES(data.id), content) + return create_message(result, client) + } + } + + // If it is a dm channel + if (data.type === Channel_Types.DM) + return { + ...base_channel, + ...base_text_channel + } + + // GUILD CHANNEL ONLY + const base_guild_channel = { + ...base_channel, + nsfw: () => data.nsfw!, + position: () => data.position!, + parent_id: () => data.parent_id, + // TODO: fix this from being number on allow and deny to being array of strings + permission_overwrites: () => data.permission_overwrites, + has_permissions: (id: string, permissions: Permission[]) => { + if (id === guild.owner_id) return true + + const member = guild.members.get(id) + if (!member) + throw 'Invalid member id provided. This member was not found in the cache. Please fetch them with getMember on guild.' + + let permissionBits = member.roles().reduce((bits, role_id) => { + const role = guild.roles.get(role_id) + if (!role) return bits + + bits |= role.permissions + + return bits + }, 0) + + data.permission_overwrites?.forEach(overwrite => { + permissionBits = (permissionBits & ~overwrite.deny) | overwrite.allow + }) + + return permissions.every(permission => permissionBits & Permissions[permission]) + } + } + + // Guild Text Channel + if ([Channel_Types.GUILD_TEXT, Channel_Types.GUILD_NEWS].includes(data.type)) + return { + ...base_guild_channel, + ...base_text_channel, + mention: () => `<#${data.id}>` + } + + if (data.type === Channel_Types.GUILD_CATEGORY) + return { + ...base_guild_channel, + children_ids: () => + Object.keys(guild.channels).filter(channel => guild.channels.get(channel).parent_id === data.id) + } + + if (data.type === Channel_Types.GUILD_VOICE) + return { + ...base_guild_channel + } + + return { + ...data, + mention: () => `<#${data.id}>` + } } diff --git a/structures/user.ts b/structures/user.ts index 3231c3333..f9d884fe8 100644 --- a/structures/user.ts +++ b/structures/user.ts @@ -31,4 +31,4 @@ export interface UserPayload { export const enum PremiumType { NitroClassic = 1, Nitro -} \ No newline at end of file +} diff --git a/types/channel.ts b/types/channel.ts new file mode 100644 index 000000000..96ff23b04 --- /dev/null +++ b/types/channel.ts @@ -0,0 +1,51 @@ +import { Raw_Overwrite } from './guild' + +export interface Channel_Create_Options { + /** The id of this channel */ + id: string + /** The type of the channel */ + type: Channel_Type + /** The id of the guild */ + guild_id?: string + /** Sorting position of the channel */ + position?: number + /** Explicit permission overwrites for members and roles */ + permission_overwrites?: Raw_Overwrite[] + /** The name of the channel (2-100 characters) */ + name?: string + /** The channel topic (0-1024 characters) */ + topic?: string + /** Whether the channel is nsfw */ + nsfw?: boolean + /** The id of the last message sent in this channel (may not point to an existing or valid message) */ + last_message_id?: string | null + /** The bitrate (in bits) of the voice channel */ + bitrate?: number + /** The user limit of the voice channel */ + user_limit?: number + /** Amount of seconds a user has to wait before sending another message (0-21600) Bots and users with the permission MANAGE_MESSAGES or MANAGE_CHANNEL are unaffected. */ + rate_limit_per_user?: number + /** The parent category id */ + parent_id?: string | null + /** When the last pinned message was pinned */ + last_pin_timestamp?: string +} + +export type Channel_Type = 0 | 1 | 2 | 4 | 5 | 6 + +export enum Channel_Types { + /** A text channel within a server */ + GUILD_TEXT, + /** A direct message between users */ + DM, + /** A voice channel within a server */ + GUILD_VOICE, + /** A direct message between multiple users. */ + GROUP_DM, + /** An organizational category that contains channels */ + GUILD_CATEGORY, + /** A channel that users can follow and crosspost into their own server. */ + GUILD_NEWS, + /** A channel in which game developers can sell their game on Discord. */ + GUILD_STORE +} diff --git a/types/guild.ts b/types/guild.ts index dddfb56f3..7f45b3bb0 100644 --- a/types/guild.ts +++ b/types/guild.ts @@ -503,6 +503,17 @@ export interface Overwrite { deny: Permission[] } +export interface Raw_Overwrite { + /** The role or user id */ + id: string + /** Whether this is a role or a member */ + type: 'role' | 'member' + /** The permissions that this id is allowed to do. (This will mark it as a green check.) */ + allow: number + /** The permissions that this id is NOT allowed to do. (This will mark it as a red x.) */ + deny: number +} + export enum ChannelTypes { text, dm,