diff --git a/structures/channel.ts b/structures/channel.ts index 4ecfd2338..989040752 100644 --- a/structures/channel.ts +++ b/structures/channel.ts @@ -123,15 +123,15 @@ export const create_channel = (data: Channel_Create_Payload, client: Client) => mention: () => `<#${data.id}>`, /** Delete messages from the channel. 2-100. Requires the MANAGE_MESSAGES permission */ delete_messages: (ids: string[], reason?: string) => { - // TODO: Requires the MANAGE_MESSAGES permission. - if (ids.length < 2) { - throw "This endpoint will only accept 2-100 message ids." - } - if (ids.length > 100) { + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_MESSAGES])) + throw new Error(Errors.MISSING_MANAGE_MESSAGES) + if (ids.length < 2) throw new Error(Errors.DELETE_MESSAGES_MIN) + + if (ids.length > 100) console.warn( `This endpoint only accepts a maximum of 100 messages. Deleting the first 100 message ids provided.` ) - } + return client.discordRequestManager.post(endpoints.CHANNEL_BULK_DELETE(data.id), { messages: ids.splice(0, 100), reason @@ -139,17 +139,20 @@ export const create_channel = (data: Channel_Create_Payload, client: Client) => }, /** Gets the invites for this channel. Requires MANAGE_CHANNEL */ get_invites: () => { - // TODO: Requires the MANAGE_CHANNELS permission + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_CHANNELS])) + throw new Error(Errors.MISSING_MANAGE_CHANNELS) return client.discordRequestManager.get(endpoints.CHANNEL_INVITES(data.id)) }, /** Creates a new invite for this channel. Requires CREATE_INSTANT_INVITE */ create_invite: (options: Create_Invite_Options) => { - // TODO: Requires CREATE_INSTANT_INVITE permissin. + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.CREATE_INSTANT_INVITE])) + throw new Error(Errors.MISSING_CREATE_INSTANT_INVITE) return client.discordRequestManager.post(endpoints.CHANNEL_INVITES(data.id), options) }, /** Gets the webhooks for this channel. Requires MANAGE_WEBHOOKS */ get_webhooks: () => { - // TODO: Requires MANAGE_WEBHOOKS + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_WEBHOOKS])) + throw new Error(Errors.MISSING_MANAGE_WEBHOOKS) return client.discordRequestManager.get(endpoints.CHANNEL_WEBHOOKS(data.id)) } } diff --git a/structures/guild.ts b/structures/guild.ts index 32bfa5e9b..180ed4d9a 100644 --- a/structures/guild.ts +++ b/structures/guild.ts @@ -20,6 +20,8 @@ import { create_channel } from "./channel.ts" import { Channel_Create_Options } from "../types/channel.ts" import { Image_Size, Image_Formats } from "../types/cdn.ts" import { Permissions, Permission } from "../types/permission.ts" +import { bot_has_permission } from "../utils/permissions.ts" +import { Errors } from "../types/errors.ts" export const create_guild = (data: Create_Guild_Payload, client: Client) => { const guild = { @@ -98,7 +100,8 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { data.banner ? format_image_url(endpoints.GUILD_BANNER(data.id, data.banner), size, format) : undefined, /** Create a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */ create_channel: (name: string, options: Channel_Create_Options) => { - // TODO: Check if the bot has `MANAGE_CHANNELS` permission before making a channel + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_CHANNELS])) + throw new Error(Errors.MISSING_MANAGE_CHANNELS) return client.discordRequestManager.post(endpoints.GUILD_CHANNELS(data.id), { name, type: options?.type ? ChannelTypes[options.type] : undefined, @@ -135,7 +138,8 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Create an emoji in the server. Emojis and animated emojis have a maximum file size of 256kb. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request and an error message, but not a JSON status code. */ create_emoji: (name: string, image: string, options: Create_Emojis_Options) => { - // TODO: Check if the bot has `MANAGE_EMOJIS` permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_EMOJIS])) + throw new Error(Errors.MISSING_MANAGE_EMOJIS) return client.discordRequestManager.post(endpoints.GUILD_EMOJIS(data.id), { ...options, name, @@ -144,7 +148,8 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Modify the given emoji. Requires the MANAGE_EMOJIS permission. */ edit_emoji: (id: string, options: Edit_Emojis_Options) => { - // TODO: check if the bot has `MANAGE_EMOJIS` permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_EMOJIS])) + throw new Error(Errors.MISSING_MANAGE_EMOJIS) return client.discordRequestManager.patch(endpoints.GUILD_EMOJI(data.id, id), { name: options.name, roles: options.roles @@ -152,12 +157,14 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Delete the given emoji. Requires the MANAGE_EMOJIS permission. Returns 204 No Content on success. */ delete_emoji: (id: string, reason?: string) => { - // TODO: check if the bot has `MANAGE_EMOJIS` permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_EMOJIS])) + throw new Error(Errors.MISSING_MANAGE_EMOJIS) return client.discordRequestManager.delete(endpoints.GUILD_EMOJI(data.id, id), { reason }) }, /** Create a new role for the guild. Requires the MANAGE_ROLES permission. */ create_role: async (options: Create_Role_Options) => { - // TODO: check if the bot has the `MANAGE_ROLES` permission. + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_ROLES])) + throw new Error(Errors.MISSING_MANAGE_ROLES) const role = await client.discordRequestManager.post(endpoints.GUILD_ROLES(data.id), { ...options, permissions: options.permissions?.map(perm => Permissions[perm]) @@ -168,12 +175,14 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Edit a guild role. Requires the MANAGE_ROLES permission. */ edit_role: (id: string, options: Create_Role_Options) => { - // TODO: check if the bot has the `MANAGE_ROLES` permission. + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_ROLES])) + throw new Error(Errors.MISSING_MANAGE_ROLES) return client.discordRequestManager.patch(endpoints.GUILD_ROLE(data.id, id), options) }, /** Delete a guild role. Requires the MANAGE_ROLES permission. */ delete_role: (id: string) => { - // TODO: check if the bot has the `MANAGE_ROLES` permission. + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_ROLES])) + throw new Error(Errors.MISSING_MANAGE_ROLES) return client.discordRequestManager.delete(endpoints.GUILD_ROLE(data.id, id)) }, /** Returns a list of role objects for the guild. @@ -181,27 +190,29 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { * ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your roles will be cached in your guild.** */ get_roles: () => { - // TODO: check if the bot has the `MANAGE_ROLES` permission. + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_ROLES])) + throw new Error(Errors.MISSING_MANAGE_ROLES) return client.discordRequestManager.get(endpoints.GUILD_ROLES(data.id)) }, /** Modify the positions of a set of role objects for the guild. Requires the MANAGE_ROLES permission. */ swap_roles: (rolePositons: Position_Swap) => { - // TODO: check if the bot has the `MANAGE_ROLES` permission. + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_ROLES])) + throw new Error(Errors.MISSING_MANAGE_ROLES) return client.discordRequestManager.patch(endpoints.GUILD_ROLES(data.id), rolePositons) }, /** Check how many members would be removed from the server in a prune operation. Requires the KICK_MEMBERS permission */ get_prune_count: async (days: number) => { - if (days < 1) { - throw `The number of days to count prune for must be 1 or more.` - } - // TODO: check if the bot has `KICK_MEMBERS` permission + if (days < 1) throw new Error(Errors.PRUNE_MIN_DAYS) + if (!bot_has_permission(data.id, client.bot_id, [Permissions.KICK_MEMBERS])) + throw new Error(Errors.MISSING_KICK_MEMBERS) const result = (await client.discordRequestManager.get(endpoints.GUILD_PRUNE(data.id), { days })) as PrunePayload return result.pruned }, /** Begin pruning all members in the given time period */ prune_members: (days: number) => { - if (days < 1) throw `The number of days must be 1 or more.` - // TODO: check if the bot has `KICK_MEMBERS` permission. + if (days < 1) throw new Error(Errors.PRUNE_MIN_DAYS) + if (!bot_has_permission(data.id, client.bot_id, [Permissions.KICK_MEMBERS])) + throw new Error(Errors.MISSING_KICK_MEMBERS) return client.discordRequestManager.post(endpoints.GUILD_PRUNE(data.id), { days }) }, // TODO: REQUEST THIS OVER WEBSOCKET WITH GET_GUILD_MEMBERS ENDPOINT @@ -209,7 +220,9 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { // }, /** Returns the audit logs for the guild. Requires VIEW AUDIT LOGS permission */ get_audit_logs: (options: Get_Audit_Logs_Options) => { - // TODO: check if the bot has VIEW_AUDIT_LOGS permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.VIEW_AUDIT_LOG])) + throw new Error(Errors.MISSING_VIEW_AUDIT_LOG) + return client.discordRequestManager.get(endpoints.GUILD_AUDIT_LOGS(data.id), { ...options, limit: options.limit && options.limit >= 1 && options.limit <= 100 ? options.limit : 50 @@ -217,12 +230,14 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Returns the guild embed object. Requires the MANAGE_GUILD permission. */ get_embed: () => { - // TODO: check if the bot has the MANAGE_GUILD permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.get(endpoints.GUILD_EMBED(data.id)) }, /** Modify a guild embed object for the guild. Requires the MANAGE_GUILD permission. */ edit_embed: (enabled: boolean, channel_id?: string | null) => { - // TODO: Requires the MANAGE_GUILD permission. + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.patch(endpoints.GUILD_EMBED(data.id), { enabled, channel_id }) }, /** Returns the code and uses of the vanity url for this server if it is enabled. Requires the MANAGE_GUILD permission. */ @@ -231,37 +246,44 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Returns a list of integrations for the guild. Requires the MANAGE_GUILD permission. */ get_integrations: () => { - // TODO: requires the MANAGE_GUILD permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.get(endpoints.GUILD_INTEGRATIONS(data.id)) }, /** Modify the behavior and settings of an integration object for the guild. Requires the MANAGE_GUILD permission. */ edit_integration: (id: string, options: Edit_Integration_Options) => { - // TODO: requires the MANAGE_GUILD permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.patch(endpoints.GUILD_INTEGRATION(data.id, id), options) }, /** Delete the attached integration object for the guild with this id. Requires MANAGE_GUILD permission. */ delete_integration: (id: string) => { - // TODO: requires the MANAGE_GUILD permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.delete(endpoints.GUILD_INTEGRATION(data.id, id)) }, /** Sync an integration. Requires teh MANAGE_GUILD permission. */ sync_integration: (id: string) => { - // TODO: requires MANAGE_GUILD + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.post(endpoints.GUILD_INTEGRATION_SYNC(data.id, id)) }, /** Returns a list of ban objects for the users banned from this guild. Requires the BAN_MEMBERS permission. */ get_bans: () => { - // TODO: requires the BAN_MEMBERS permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.BAN_MEMBERS])) + throw new Error(Errors.MISSING_BAN_MEMBERS) return client.discordRequestManager.get(endpoints.GUILD_BANS(data.id)) }, /** Ban a user from the guild and optionally delete previous messages sent by the user. Requires teh BAN_MEMBERS permission. */ ban: (id: string, options: BanOptions) => { - // TODO: requires the BAN_MEMBERS permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.BAN_MEMBERS])) + throw new Error(Errors.MISSING_BAN_MEMBERS) return client.discordRequestManager.put(endpoints.GUILD_BAN(data.id, id), options) }, /** Remove the ban for a user. REquires BAN_MEMBERS permission */ unban: (id: string) => { - // TODO: requires the BAN_MEMBERS permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.BAN_MEMBERS])) + throw new Error(Errors.MISSING_BAN_MEMBERS) return client.discordRequestManager.delete(endpoints.GUILD_BAN(data.id, id)) }, /** Check whether a member has certain permissions in this channel. */ @@ -297,12 +319,14 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Modify a guilds settings. Requires the MANAGE_GUILD permission. */ edit: (options: Guild_Edit_Options) => { - // TODO: requires the MANAGE_GUILD permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.patch(endpoints.GUILD(data.id), options) }, /** Get all the invites for this guild. Requires MANAGE_GUILD permission */ get_invites: () => { - // TODO: requires MANAGE_GUILD permission + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_GUILD])) + throw new Error(Errors.MISSING_MANAGE_GUILD) return client.discordRequestManager.get(endpoints.GUILD_INVITES(data.id)) }, /** Leave a guild */ @@ -315,7 +339,9 @@ export const create_guild = (data: Create_Guild_Payload, client: Client) => { }, /** Returns a list of guild webhooks objects. Requires the MANAGE_WEBHOOKs permission. */ get_webhooks: () => { - // TODO: requires MANAGE_WEBHOOKS + if (!bot_has_permission(data.id, client.bot_id, [Permissions.MANAGE_WEBHOOKS])) + throw new Error(Errors.MISSING_MANAGE_WEBHOOKS) + return client.discordRequestManager.get(endpoints.GUILD_WEBHOOKS(data.id)) } } diff --git a/structures/message.ts b/structures/message.ts index ea8c434b5..6a4e508fe 100644 --- a/structures/message.ts +++ b/structures/message.ts @@ -1,16 +1,19 @@ -import Client from '../module/client.ts' -import { Message_Create_Options } from '../types/message.ts' -import { endpoints } from '../constants/discord.ts' -import { Channel_Types, MessageContent } from '../types/channel.ts' -import { cache } from '../utils/cache.ts' -import { create_user } from './user.ts' -import { User_Payload } from '../types/guild.ts' -import { Channel } from '../types/return-type.ts' +import Client from "../module/client.ts" +import { Message_Create_Options } from "../types/message.ts" +import { endpoints } from "../constants/discord.ts" +import { MessageContent } from "../types/channel.ts" +import { cache } from "../utils/cache.ts" +import { create_user } from "./user.ts" +import { User_Payload } from "../types/guild.ts" +import { Channel } from "../types/return-type.ts" +import { bot_has_permission } from "../utils/permissions.ts" +import { Errors } from "../types/errors.ts" +import { Permissions } from "../types/permission.ts" export const create_message = (data: Message_Create_Options, client: Client) => { const base_message = { raw: () => data, - author: () => create_user({ ...data.author, avatar: data.author.avatar || '' }), + author: () => create_user({ ...data.author, avatar: data.author.avatar || "" }), id: () => data.id, type: () => data.type, timestamp: () => Date.parse(data.timestamp), @@ -39,18 +42,22 @@ export const create_message = (data: Message_Create_Options, client: Client) => channel: () => cache.channels.get(data.channel_id) as Channel, delete: (reason: string) => { - // TODO: Requires MANAGE_MESSAGES - if (data.author.id !== client.bot_id) {} + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_MESSAGES])) + throw new Error(Errors.MISSING_MANAGE_MESSAGES) + if (data.author.id !== client.bot_id) { + } client.discordRequestManager.delete(endpoints.CHANNEL_MESSAGE(data.channel_id, data.id), { reason }) }, /** Pin a message in a channel. Requires MANAGE_MESSAGES. Max pins allowed in a channel = 50. */ pin: () => { - // TODO: Requires MANAGE_MESSAGES + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_MESSAGES])) + throw new Error(Errors.MISSING_MANAGE_MESSAGES) client.discordRequestManager.put(endpoints.CHANNEL_MESSAGE(data.channel_id, data.id)) }, unpin: () => { - // TODO: Requires MANAGE_MESSAGES + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_MESSAGES])) + throw new Error(Errors.MISSING_MANAGE_MESSAGES) client.discordRequestManager.delete(endpoints.CHANNEL_MESSAGE(data.channel_id, data.id)) }, /** Create a reaction for the message. Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. Requires READ_MESSAGE_HISTORY and ADD_REACTIONS */ @@ -63,32 +70,38 @@ export const create_message = (data: Message_Create_Options, client: Client) => }, /** Removes all reactions for all emojis on this message. */ remove_all_reactions: () => { - // TODO: Requires MANAGE_MESSAGES + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_MESSAGES])) + throw new Error(Errors.MISSING_MANAGE_MESSAGES) client.discordRequestManager.delete(endpoints.CHANNEL_MESSAGE_REACTIONS(data.channel_id, data.id)) }, /** Removes all reactions for a single emoji on this message. Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. */ remove_reaction_emoji: (reaction: string) => { - // TODO: Requires MANAGE_MESSAGES + if (data.guild_id && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.MANAGE_MESSAGES])) + throw new Error(Errors.MISSING_MANAGE_MESSAGES) client.discordRequestManager.delete(endpoints.CHANNEL_MESSAGE_REACTION(data.channel_id, data.id, reaction)) }, /** Get a list of users that reacted with this emoji. */ get_reactions: async (reaction: string) => { - const result = await client.discordRequestManager.get(endpoints.CHANNEL_MESSAGE_REACTION(data.channel_id, data.id, reaction)) as User_Payload[] + const result = (await client.discordRequestManager.get( + endpoints.CHANNEL_MESSAGE_REACTION(data.channel_id, data.id, reaction) + )) as User_Payload[] return result.map(res => create_user(res)) }, /** Edit the message. */ edit: async (content: string | MessageContent) => { - if (data.author.id !== client.bot_id) throw 'You can only edit a message that was sent by the bot.' - if (data.type !== Channel_Types.DM) { - // TODO: check if the bot has SEND_MESSAGES permission + if (data.author.id !== client.bot_id) throw "You can only edit a message that was sent by the bot." + + if (typeof content === "string") content = { content } + + if (data.guild_id) { + if (!bot_has_permission(data.guild_id, client.bot_id, [Permissions.SEND_MESSAGES])) + throw new Error(Errors.MISSING_SEND_MESSAGES) + + if (content.tts && !bot_has_permission(data.guild_id, client.bot_id, [Permissions.SEND_TTS_MESSAGES])) + throw new Error(Errors.MISSING_SEND_TTS_MESSAGE) } - if (typeof content === 'string') content = { content } - if (content.tts) { - // TODO: check if the bot has SEND_TTS_MESSAGE - } - - // TODO: Check content length + if (content.content && content.content.length > 2000) throw new Error(Errors.MESSAGE_MAX_LENGTH) const result = await client.discordRequestManager.patch(endpoints.CHANNEL_MESSAGES(data.id), content) return create_message(result, client) diff --git a/types/errors.ts b/types/errors.ts index 76cde6894..ef3ebd373 100644 --- a/types/errors.ts +++ b/types/errors.ts @@ -6,8 +6,19 @@ export enum Errors { MISSING_READ_MESSAGE_HISTORY = "MISSING_READ_MESSAGE_HISTORY", MISSING_MANAGE_NICKNAMES = "MISSING_MANAGE_NICKNAMES", MISSING_MUTE_MEMBERS = "MISSING_MUTE_MEMBERS", - MISSING_DEAFEN_MEMBERS = "MISSING_DEAFEN_MEMBERS", - MISSING_SEND_TTS_MESSAGE = 'MISSING_SEND_TTS_MESSAGE', - MESSAGE_MAX_LENGTH = 'MESSAGE_MAX_LENGTH', - NICKNAMES_MAX_LENGTH = "NICKNAMES_MAX_LENGTH" + MISSING_DEAFEN_MEMBERS = "MISSING_DEAFEN_MEMBERS", + MISSING_SEND_TTS_MESSAGE = "MISSING_SEND_TTS_MESSAGE", + MISSING_MANAGE_MESSAGES = "MISSING_MANAGE_MESSAGES", + MISSING_MANAGE_CHANNELS = "MISSING_MANAGE_CHANNELS", + MISSING_CREATE_INSTANT_INVITE = "MISSING_CREATE_INSTANT_INVITE", + MISSING_MANAGE_WEBHOOKS = "MISSING_MANAGE_WEBHOOKS", + MISSING_MANAGE_EMOJIS = "MISSING_MANAGE_EMOJIS", + MISSING_BAN_MEMBERS = "MISSING_BAN_MEMBERS", + MISSING_MANAGE_GUILD = "MISSING_MANAGE_GUILD", + MISSING_VIEW_AUDIT_LOG = "MISSING_VIEW_AUDIT_LOG", + DELETE_MESSAGES_MIN = "DELETE_MESSAGES_MIN", + DELETE_MESSAGES_MAX = "DELETE_MESSAGES_MAX", + MESSAGE_MAX_LENGTH = "MESSAGE_MAX_LENGTH", + NICKNAMES_MAX_LENGTH = "NICKNAMES_MAX_LENGTH", + PRUNE_MIN_DAYS = "PRUNE_MIN_DAYS" }