mirror of
https://github.com/discordeno/discordeno.git
synced 2026-05-30 15:30:07 +00:00
refactor(helpers): separate functions into files (#667)
* refactor(helpers): separate functions into files * idk * idk
This commit is contained in:
13
mod.ts
13
mod.ts
@@ -1,22 +1,17 @@
|
||||
export * from "./src/bot.ts";
|
||||
export * from "./src/cache.ts";
|
||||
export * from "./src/helpers/channel.ts";
|
||||
export * from "./src/helpers/guild.ts";
|
||||
export * from "./src/helpers/member.ts";
|
||||
export * from "./src/helpers/message.ts";
|
||||
export * from "./src/helpers/oauth.ts";
|
||||
export * from "./src/helpers/webhook.ts";
|
||||
export * from "./src/handlers/mod.ts";
|
||||
export * from "./src/helpers/mod.ts";
|
||||
export * from "./src/rest/mod.ts";
|
||||
export * from "./src/structures/channel.ts";
|
||||
export * from "./src/structures/guild.ts";
|
||||
export * from "./src/structures/member.ts";
|
||||
export * from "./src/structures/message.ts";
|
||||
export * from "./src/structures/mod.ts";
|
||||
export * from "./src/structures/role.ts";
|
||||
export * from "./src/bot.ts";
|
||||
export * from "./src/rest/mod.ts";
|
||||
export * from "./src/types/mod.ts";
|
||||
export * from "./src/util/cache.ts";
|
||||
export * from "./src/util/collection.ts";
|
||||
export * from "./src/util/permissions.ts";
|
||||
export * from "./src/util/utils.ts";
|
||||
export * from "./src/ws/mod.ts";
|
||||
export * from "./src/handlers/mod.ts";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getGatewayBot } from "./helpers/gateway.ts";
|
||||
import { getGatewayBot } from "./helpers/misc/get_gateway_bot.ts";
|
||||
import {
|
||||
BotConfig,
|
||||
DiscordBotGatewayData,
|
||||
|
||||
@@ -5,25 +5,22 @@ import { handleChannelUpdate } from "./channels/CHANNEL_UPDATE.ts";
|
||||
import { handleApplicationCommandCreate } from "./commands/APPLICATION_COMMAND_CREATE.ts";
|
||||
import { handleApplicationCommandDelete } from "./commands/APPLICATION_COMMAND_DELETE.ts";
|
||||
import { handleApplicationCommandUpdate } from "./commands/APPLICATION_COMMAND_UPDATE.ts";
|
||||
import { handleGuildEmojisUpdate } from "./emojis/GUILD_EMOJIS_UPDATE.ts";
|
||||
import { handleGuildBanAdd } from "./guilds/GUILD_BAN_ADD.ts";
|
||||
import { handleGuildBanRemove } from "./guilds/GUILD_BAN_REMOVE.ts";
|
||||
import { handleGuildCreate } from "./guilds/GUILD_CREATE.ts";
|
||||
import { handleGuildDelete } from "./guilds/GUILD_DELETE.ts";
|
||||
import { handleGuildEmojisUpdate } from "./guilds/GUILD_EMOJIS_UPDATE.ts";
|
||||
import { handleGuildIntegrationsUpdate } from "./guilds/GUILD_INTEGRATIONS_UPDATE.ts";
|
||||
import { handleGuildMembersChunk } from "./guilds/GUILD_MEMBERS_CHUNK.ts";
|
||||
import { handleGuildMemberAdd } from "./guilds/GUILD_MEMBER_ADD.ts";
|
||||
import { handleGuildMemberRemove } from "./guilds/GUILD_MEMBER_REMOVE.ts";
|
||||
import { handleGuildMemberUpdate } from "./guilds/GUILD_MEMBER_UPDATE.ts";
|
||||
import { handleGuildRoleCreate } from "./guilds/GUILD_ROLE_CREATE.ts";
|
||||
import { handleGuildRoleDelete } from "./guilds/GUILD_ROLE_DELETE.ts";
|
||||
import { handleGuildRoleUpdate } from "./guilds/GUILD_ROLE_UPDATE.ts";
|
||||
import { handleGuildUpdate } from "./guilds/GUILD_UPDATE.ts";
|
||||
import { handleIntegrationCreate } from "./integrations/INTEGRATION_CREATE.ts";
|
||||
import { handleIntegrationDelete } from "./integrations/INTEGRATION_DELETE.ts";
|
||||
import { handleIntegrationUpdate } from "./integrations/INTEGRATION_UPDATE.ts";
|
||||
import { handleInteractionCreate } from "./interactions/INTERACTION_CREATE.ts";
|
||||
import { handleInviteCreate } from "./invites/INVITE_CREATE.ts";
|
||||
import { handleGuildMembersChunk } from "./members/GUILD_MEMBERS_CHUNK.ts";
|
||||
import { handleGuildMemberAdd } from "./members/GUILD_MEMBER_ADD.ts";
|
||||
import { handleGuildMemberRemove } from "./members/GUILD_MEMBER_REMOVE.ts";
|
||||
import { handleGuildMemberUpdate } from "./members/GUILD_MEMBER_UPDATE.ts";
|
||||
import { handleMessageCreate } from "./messages/MESSAGE_CREATE.ts";
|
||||
import { handleMessageDelete } from "./messages/MESSAGE_DELETE.ts";
|
||||
import { handleMessageDeleteBulk } from "./messages/MESSAGE_DELETE_BULK.ts";
|
||||
@@ -36,6 +33,9 @@ import { handlePresenceUpdate } from "./presence/PRESENCE_UPDATE.ts";
|
||||
import { handleTypingStart } from "./presence/TYPING_START.ts";
|
||||
import { handleUserUpdate } from "./presence/USER_UPDATE.ts";
|
||||
import { handleReady } from "./READY.ts";
|
||||
import { handleGuildRoleCreate } from "./roles/GUILD_ROLE_CREATE.ts";
|
||||
import { handleGuildRoleDelete } from "./roles/GUILD_ROLE_DELETE.ts";
|
||||
import { handleGuildRoleUpdate } from "./roles/GUILD_ROLE_UPDATE.ts";
|
||||
import { handleVoiceServerUpdate } from "./voice/VOICE_SERVER_UPDATE.ts";
|
||||
import { handleVoiceStateUpdate } from "./voice/VOICE_STATE_UPDATE.ts";
|
||||
import { handleWebhooksUpdate } from "./webhooks/WEBHOOKS_UPDATE.ts";
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import {
|
||||
DiscordPayload,
|
||||
GuildRoleDeletePayload,
|
||||
GuildRolePayload,
|
||||
} from "../../types/mod.ts";
|
||||
import { DiscordPayload, GuildRolePayload } from "../../types/mod.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import {
|
||||
DiscordPayload,
|
||||
GuildRoleDeletePayload,
|
||||
GuildRolePayload,
|
||||
} from "../../types/mod.ts";
|
||||
import { DiscordPayload, GuildRolePayload } from "../../types/mod.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
|
||||
@@ -1,469 +0,0 @@
|
||||
import { cacheHandlers } from "../cache.ts";
|
||||
import { RequestManager } from "../rest/request_manager.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import {
|
||||
ChannelEditOptions,
|
||||
ChannelTypes,
|
||||
CreateInviteOptions,
|
||||
Errors,
|
||||
FollowedChannelPayload,
|
||||
GetMessages,
|
||||
GetMessagesAfter,
|
||||
GetMessagesAround,
|
||||
GetMessagesBefore,
|
||||
InvitePayload,
|
||||
MessageContent,
|
||||
MessageCreateOptions,
|
||||
Permission,
|
||||
Permissions,
|
||||
RawOverwrite,
|
||||
WebhookPayload,
|
||||
} from "../types/mod.ts";
|
||||
import { endpoints } from "../util/constants.ts";
|
||||
import {
|
||||
botHasChannelPermissions,
|
||||
calculateBits,
|
||||
requireBotChannelPermissions,
|
||||
requireBotGuildPermissions,
|
||||
} from "../util/permissions.ts";
|
||||
|
||||
/** Checks if a channel overwrite for a user id or a role id has permission in this channel */
|
||||
export function channelOverwriteHasPermission(
|
||||
guildID: string,
|
||||
id: string,
|
||||
overwrites: RawOverwrite[],
|
||||
permissions: Permission[],
|
||||
) {
|
||||
const overwrite = overwrites.find((perm) => perm.id === id) ||
|
||||
overwrites.find((perm) => perm.id === guildID);
|
||||
|
||||
return permissions.every((perm) => {
|
||||
if (overwrite) {
|
||||
const allowBits = overwrite.allow;
|
||||
const denyBits = overwrite.deny;
|
||||
if (BigInt(denyBits) & BigInt(Permissions[perm])) return false;
|
||||
if (BigInt(allowBits) & BigInt(Permissions[perm])) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/** Fetch a single message from the server. Requires VIEW_CHANNEL and READ_MESSAGE_HISTORY */
|
||||
export async function getMessage(channelID: string, id: string) {
|
||||
await requireBotChannelPermissions(channelID, [
|
||||
"VIEW_CHANNEL",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
]);
|
||||
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_MESSAGE(channelID, id),
|
||||
)) as MessageCreateOptions;
|
||||
|
||||
return structures.createMessageStruct(result);
|
||||
}
|
||||
|
||||
/** Fetches between 2-100 messages. Requires VIEW_CHANNEL and READ_MESSAGE_HISTORY */
|
||||
export async function getMessages(
|
||||
channelID: string,
|
||||
options?:
|
||||
| GetMessagesAfter
|
||||
| GetMessagesBefore
|
||||
| GetMessagesAround
|
||||
| GetMessages,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, [
|
||||
"VIEW_CHANNEL",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
]);
|
||||
|
||||
if (options?.limit && options.limit > 100) return;
|
||||
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_MESSAGES(channelID),
|
||||
options,
|
||||
)) as MessageCreateOptions[];
|
||||
|
||||
return Promise.all(
|
||||
result.map((res) => structures.createMessageStruct(res)),
|
||||
);
|
||||
}
|
||||
|
||||
/** Get pinned messages in this channel. */
|
||||
export async function getPins(channelID: string) {
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_PINS(channelID),
|
||||
)) as MessageCreateOptions[];
|
||||
|
||||
return Promise.all(
|
||||
result.map((res) => structures.createMessageStruct(res)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a typing indicator for the specified channel. Generally bots should **NOT** implement this route.
|
||||
* However, if a bot is responding to a command and expects the computation to take a few seconds,
|
||||
* this endpoint may be called to let the user know that the bot is processing their message.
|
||||
*/
|
||||
export async function startTyping(channelID: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
// If the channel is cached, we can do extra checks/safety
|
||||
if (channel) {
|
||||
if (
|
||||
![
|
||||
ChannelTypes.DM,
|
||||
ChannelTypes.GUILD_NEWS,
|
||||
ChannelTypes.GUILD_TEXT,
|
||||
].includes(channel.type)
|
||||
) {
|
||||
throw new Error(Errors.CHANNEL_NOT_TEXT_BASED);
|
||||
}
|
||||
|
||||
const hasSendMessagesPerm = await botHasChannelPermissions(
|
||||
channelID,
|
||||
["SEND_MESSAGES"],
|
||||
);
|
||||
if (
|
||||
!hasSendMessagesPerm
|
||||
) {
|
||||
throw new Error(Errors.MISSING_SEND_MESSAGES);
|
||||
}
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(endpoints.CHANNEL_TYPING(channelID));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Send a message to the channel. Requires SEND_MESSAGES permission. */
|
||||
export async function sendMessage(
|
||||
channelID: string,
|
||||
content: string | MessageContent,
|
||||
) {
|
||||
if (typeof content === "string") content = { content };
|
||||
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
if (channel) {
|
||||
if (
|
||||
![
|
||||
ChannelTypes.DM,
|
||||
ChannelTypes.GUILD_NEWS,
|
||||
ChannelTypes.GUILD_TEXT,
|
||||
].includes(channel.type)
|
||||
) {
|
||||
throw new Error(Errors.CHANNEL_NOT_TEXT_BASED);
|
||||
}
|
||||
|
||||
const requiredPerms: Set<Permission> = new Set([
|
||||
"SEND_MESSAGES",
|
||||
"VIEW_CHANNEL",
|
||||
]);
|
||||
|
||||
if (content.tts) requiredPerms.add("SEND_TTS_MESSAGES");
|
||||
if (content.embed) requiredPerms.add("EMBED_LINKS");
|
||||
if (content.replyMessageID || content.mentions?.repliedUser) {
|
||||
requiredPerms.add("READ_MESSAGE_HISTORY");
|
||||
}
|
||||
|
||||
await requireBotChannelPermissions(channelID, [...requiredPerms]);
|
||||
}
|
||||
|
||||
// Use ... for content length due to unicode characters and js .length handling
|
||||
if (content.content && [...content.content].length > 2000) {
|
||||
throw new Error(Errors.MESSAGE_MAX_LENGTH);
|
||||
}
|
||||
|
||||
if (content.mentions) {
|
||||
if (content.mentions.users?.length) {
|
||||
if (content.mentions.parse?.includes("users")) {
|
||||
content.mentions.parse = content.mentions.parse.filter(
|
||||
(p) => p !== "users",
|
||||
);
|
||||
}
|
||||
|
||||
if (content.mentions.users.length > 100) {
|
||||
content.mentions.users = content.mentions.users.slice(0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (content.mentions.roles?.length) {
|
||||
if (content.mentions.parse?.includes("roles")) {
|
||||
content.mentions.parse = content.mentions.parse.filter(
|
||||
(p) => p !== "roles",
|
||||
);
|
||||
}
|
||||
|
||||
if (content.mentions.roles.length > 100) {
|
||||
content.mentions.roles = content.mentions.roles.slice(0, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = (await RequestManager.post(
|
||||
endpoints.CHANNEL_MESSAGES(channelID),
|
||||
{
|
||||
...content,
|
||||
allowed_mentions: content.mentions
|
||||
? {
|
||||
...content.mentions,
|
||||
replied_user: content.mentions.repliedUser,
|
||||
}
|
||||
: undefined,
|
||||
...(content.replyMessageID
|
||||
? {
|
||||
message_reference: {
|
||||
message_id: content.replyMessageID,
|
||||
fail_if_not_exists: content.failReplyIfNotExists === true,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
)) as MessageCreateOptions;
|
||||
|
||||
return structures.createMessageStruct(result);
|
||||
}
|
||||
|
||||
/** Delete messages from the channel. 2-100. Requires the MANAGE_MESSAGES permission */
|
||||
export async function deleteMessages(
|
||||
channelID: string,
|
||||
ids: string[],
|
||||
reason?: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["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.`,
|
||||
);
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.CHANNEL_BULK_DELETE(channelID),
|
||||
{
|
||||
messages: ids.splice(0, 100),
|
||||
reason,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Gets the invites for this channel. Requires MANAGE_CHANNEL */
|
||||
export async function getChannelInvites(channelID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_CHANNELS"]);
|
||||
|
||||
const result = await RequestManager.get(endpoints.CHANNEL_INVITES(channelID));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a new invite for this channel. Requires CREATE_INSTANT_INVITE */
|
||||
export async function createInvite(
|
||||
channelID: string,
|
||||
options: CreateInviteOptions,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["CREATE_INSTANT_INVITE"]);
|
||||
|
||||
if (options.max_age && (options.max_age > 604800 || options.max_age < 0)) {
|
||||
console.log(
|
||||
`The max age for invite created in ${channelID} was not between 0-604800. Using default values instead.`,
|
||||
);
|
||||
options.max_age = undefined;
|
||||
}
|
||||
|
||||
if (options.max_uses && (options.max_uses > 100 || options.max_uses < 0)) {
|
||||
console.log(
|
||||
`The max uses for invite created in ${channelID} was not between 0-100. Using default values instead.`,
|
||||
);
|
||||
options.max_uses = undefined;
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.CHANNEL_INVITES(channelID),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns an invite for the given code. */
|
||||
export async function getInvite(inviteCode: string) {
|
||||
const result = await RequestManager.get(endpoints.INVITE(inviteCode));
|
||||
|
||||
return result as InvitePayload;
|
||||
}
|
||||
|
||||
/** Deletes an invite for the given code. Requires `MANAGE_CHANNELS` or `MANAGE_GUILD` permission */
|
||||
export async function deleteInvite(channelID: string, inviteCode: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
|
||||
if (!channel) throw new Error(Errors.CHANNEL_NOT_FOUND);
|
||||
|
||||
const hasPerm = await botHasChannelPermissions(channel, [
|
||||
"MANAGE_CHANNELS",
|
||||
]);
|
||||
|
||||
if (!hasPerm) {
|
||||
await requireBotGuildPermissions(channel!.guildID, ["MANAGE_GUILD"]);
|
||||
}
|
||||
|
||||
const result = await RequestManager.delete(endpoints.INVITE(inviteCode));
|
||||
|
||||
return result as InvitePayload;
|
||||
}
|
||||
|
||||
/** Gets the webhooks for this channel. Requires MANAGE_WEBHOOKS */
|
||||
export async function getChannelWebhooks(channelID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const result = await RequestManager.get(
|
||||
endpoints.CHANNEL_WEBHOOKS(channelID),
|
||||
);
|
||||
|
||||
return result as WebhookPayload[];
|
||||
}
|
||||
|
||||
interface EditChannelRequest {
|
||||
amount: number;
|
||||
timestamp: number;
|
||||
channelID: string;
|
||||
items: {
|
||||
channelID: string;
|
||||
options: ChannelEditOptions;
|
||||
}[];
|
||||
}
|
||||
|
||||
const editChannelNameTopicQueue = new Map<string, EditChannelRequest>();
|
||||
let editChannelProcessing = false;
|
||||
|
||||
function processEditChannelQueue() {
|
||||
if (!editChannelProcessing) return;
|
||||
|
||||
const now = Date.now();
|
||||
editChannelNameTopicQueue.forEach((request) => {
|
||||
if (now > request.timestamp) return;
|
||||
// 10 minutes have passed so we can reset this channel again
|
||||
if (!request.items.length) {
|
||||
return editChannelNameTopicQueue.delete(request.channelID);
|
||||
}
|
||||
request.amount = 0;
|
||||
// There are items to process for this request
|
||||
const details = request.items.shift();
|
||||
|
||||
if (!details) return;
|
||||
|
||||
editChannel(details.channelID, details.options);
|
||||
const secondDetails = request.items.shift();
|
||||
if (!secondDetails) return;
|
||||
|
||||
return editChannel(secondDetails.channelID, secondDetails.options);
|
||||
});
|
||||
|
||||
if (editChannelNameTopicQueue.size) {
|
||||
setTimeout(() => processEditChannelQueue(), 600000);
|
||||
} else {
|
||||
editChannelProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update a channel's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */
|
||||
export async function editChannel(
|
||||
channelID: string,
|
||||
options: ChannelEditOptions,
|
||||
reason?: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_CHANNELS"]);
|
||||
|
||||
if (options.name || options.topic) {
|
||||
const request = editChannelNameTopicQueue.get(channelID);
|
||||
if (!request) {
|
||||
// If this hasnt been done before simply add 1 for it
|
||||
editChannelNameTopicQueue.set(channelID, {
|
||||
channelID: channelID,
|
||||
amount: 1,
|
||||
// 10 minutes from now
|
||||
timestamp: Date.now() + 600000,
|
||||
items: [],
|
||||
});
|
||||
} else if (request.amount === 1) {
|
||||
// Start queuing future requests to this channel
|
||||
request.amount = 2;
|
||||
request.timestamp = Date.now() + 600000;
|
||||
} else {
|
||||
// 2 have already been used add to queue
|
||||
request.items.push({ channelID, options });
|
||||
if (editChannelProcessing) return;
|
||||
editChannelProcessing = true;
|
||||
processEditChannelQueue();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...options,
|
||||
// deno-lint-ignore camelcase
|
||||
rate_limit_per_user: options.rateLimitPerUser,
|
||||
// deno-lint-ignore camelcase
|
||||
parent_id: options.parentID,
|
||||
// deno-lint-ignore camelcase
|
||||
user_limit: options.userLimit,
|
||||
// deno-lint-ignore camelcase
|
||||
permission_overwrites: options.overwrites?.map((overwrite) => {
|
||||
return {
|
||||
...overwrite,
|
||||
allow: calculateBits(overwrite.allow),
|
||||
deny: calculateBits(overwrite.deny),
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
const result = await RequestManager.patch(endpoints.CHANNEL_BASE(channelID), {
|
||||
...payload,
|
||||
reason,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Follow a News Channel to send messages to a target channel. Requires the `MANAGE_WEBHOOKS` permission in the target channel. Returns the webhook id. */
|
||||
export async function followChannel(
|
||||
sourceChannelID: string,
|
||||
targetChannelID: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(targetChannelID, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const data = (await RequestManager.post(
|
||||
endpoints.CHANNEL_FOLLOW(sourceChannelID),
|
||||
{
|
||||
webhook_channel_id: targetChannelID,
|
||||
},
|
||||
)) as FollowedChannelPayload;
|
||||
|
||||
return data.webhook_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a channel is synchronized with its parent/category channel or not.
|
||||
* @param channelID The ID of the channel to test for synchronization
|
||||
* @return Returns `true` if the channel is synchronized, otherwise `false`. Returns `false` if the channel is not cached.
|
||||
*/
|
||||
export async function isChannelSynced(channelID: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
if (!channel?.parentID) return false;
|
||||
|
||||
const parentChannel = await cacheHandlers.get("channels", channel.parentID);
|
||||
if (!parentChannel) return false;
|
||||
|
||||
return channel.permissionOverwrites?.every((overwrite) => {
|
||||
const permission = parentChannel.permissionOverwrites?.find(
|
||||
(ow) => ow.id === overwrite.id,
|
||||
);
|
||||
if (!permission) return false;
|
||||
return !(
|
||||
overwrite.allow !== permission.allow || overwrite.deny !== permission.deny
|
||||
);
|
||||
});
|
||||
}
|
||||
9
src/helpers/channels/category_children_ids.ts
Normal file
9
src/helpers/channels/category_children_ids.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
|
||||
/** Gets an array of all the channels ids that are the children of this category. */
|
||||
export function categoryChildrenIDs(guildID: string, id: string) {
|
||||
return cacheHandlers.filter(
|
||||
"channels",
|
||||
(channel) => channel.parentID === id && channel.guildID === guildID,
|
||||
);
|
||||
}
|
||||
22
src/helpers/channels/channel_overwrite_has_permission.ts
Normal file
22
src/helpers/channels/channel_overwrite_has_permission.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Permission, Permissions, RawOverwrite } from "../../types/mod.ts";
|
||||
|
||||
/** Checks if a channel overwrite for a user id or a role id has permission in this channel */
|
||||
export function channelOverwriteHasPermission(
|
||||
guildID: string,
|
||||
id: string,
|
||||
overwrites: RawOverwrite[],
|
||||
permissions: Permission[],
|
||||
) {
|
||||
const overwrite = overwrites.find((perm) => perm.id === id) ||
|
||||
overwrites.find((perm) => perm.id === guildID);
|
||||
|
||||
return permissions.every((perm) => {
|
||||
if (overwrite) {
|
||||
const allowBits = overwrite.allow;
|
||||
const denyBits = overwrite.deny;
|
||||
if (BigInt(denyBits) & BigInt(Permissions[perm])) return false;
|
||||
if (BigInt(allowBits) & BigInt(Permissions[perm])) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
50
src/helpers/channels/create_guild_channel.ts
Normal file
50
src/helpers/channels/create_guild_channel.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
ChannelCreateOptions,
|
||||
ChannelCreatePayload,
|
||||
ChannelTypes,
|
||||
Permission,
|
||||
} from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import {
|
||||
calculateBits,
|
||||
requireBotGuildPermissions,
|
||||
} from "../../util/permissions.ts";
|
||||
|
||||
/** Create a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */
|
||||
export async function createGuildChannel(
|
||||
guildID: string,
|
||||
name: string,
|
||||
options?: ChannelCreateOptions,
|
||||
) {
|
||||
const requiredPerms: Set<Permission> = new Set(["MANAGE_CHANNELS"]);
|
||||
|
||||
options?.permissionOverwrites?.forEach((overwrite) => {
|
||||
overwrite.allow.forEach(requiredPerms.add, requiredPerms);
|
||||
overwrite.deny.forEach(requiredPerms.add, requiredPerms);
|
||||
});
|
||||
|
||||
await requireBotGuildPermissions(guildID, [...requiredPerms]);
|
||||
|
||||
const result = (await RequestManager.post(
|
||||
endpoints.GUILD_CHANNELS(guildID),
|
||||
{
|
||||
...options,
|
||||
name,
|
||||
permission_overwrites: options?.permissionOverwrites?.map((perm) => ({
|
||||
...perm,
|
||||
|
||||
allow: calculateBits(perm.allow),
|
||||
deny: calculateBits(perm.deny),
|
||||
})),
|
||||
type: options?.type || ChannelTypes.GUILD_TEXT,
|
||||
},
|
||||
)) as ChannelCreatePayload;
|
||||
|
||||
const channelStruct = await structures.createChannelStruct(result);
|
||||
await cacheHandlers.set("channels", channelStruct.id, channelStruct);
|
||||
|
||||
return channelStruct;
|
||||
}
|
||||
32
src/helpers/channels/delete_channel.ts
Normal file
32
src/helpers/channels/delete_channel.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Delete a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */
|
||||
export async function deleteChannel(
|
||||
guildID: string,
|
||||
channelID: string,
|
||||
reason?: string,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_CHANNELS"]);
|
||||
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
|
||||
if (guild?.rulesChannelID === channelID) {
|
||||
throw new Error(Errors.RULES_CHANNEL_CANNOT_BE_DELETED);
|
||||
}
|
||||
|
||||
if (guild?.publicUpdatesChannelID === channelID) {
|
||||
throw new Error(Errors.UPDATES_CHANNEL_CANNOT_BE_DELETED);
|
||||
}
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_BASE(channelID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
18
src/helpers/channels/delete_channel_overwrite.ts
Normal file
18
src/helpers/channels/delete_channel_overwrite.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Delete the channel permission overwrites for a user or role in this channel. Requires `MANAGE_ROLES` permission. */
|
||||
export async function deleteChannelOverwrite(
|
||||
guildID: string,
|
||||
channelID: string,
|
||||
overwriteID: string,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_ROLES"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_OVERWRITE(channelID, overwriteID),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
109
src/helpers/channels/edit_channel.ts
Normal file
109
src/helpers/channels/edit_channel.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { ChannelEditOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import {
|
||||
calculateBits,
|
||||
requireBotChannelPermissions,
|
||||
} from "../../util/permissions.ts";
|
||||
|
||||
/** Update a channel's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */
|
||||
export async function editChannel(
|
||||
channelID: string,
|
||||
options: ChannelEditOptions,
|
||||
reason?: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_CHANNELS"]);
|
||||
|
||||
if (options.name || options.topic) {
|
||||
const request = editChannelNameTopicQueue.get(channelID);
|
||||
if (!request) {
|
||||
// If this hasnt been done before simply add 1 for it
|
||||
editChannelNameTopicQueue.set(channelID, {
|
||||
channelID: channelID,
|
||||
amount: 1,
|
||||
// 10 minutes from now
|
||||
timestamp: Date.now() + 600000,
|
||||
items: [],
|
||||
});
|
||||
} else if (request.amount === 1) {
|
||||
// Start queuing future requests to this channel
|
||||
request.amount = 2;
|
||||
request.timestamp = Date.now() + 600000;
|
||||
} else {
|
||||
// 2 have already been used add to queue
|
||||
request.items.push({ channelID, options });
|
||||
if (editChannelProcessing) return;
|
||||
editChannelProcessing = true;
|
||||
processEditChannelQueue();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...options,
|
||||
// deno-lint-ignore camelcase
|
||||
rate_limit_per_user: options.rateLimitPerUser,
|
||||
// deno-lint-ignore camelcase
|
||||
parent_id: options.parentID,
|
||||
// deno-lint-ignore camelcase
|
||||
user_limit: options.userLimit,
|
||||
// deno-lint-ignore camelcase
|
||||
permission_overwrites: options.overwrites?.map((overwrite) => {
|
||||
return {
|
||||
...overwrite,
|
||||
allow: calculateBits(overwrite.allow),
|
||||
deny: calculateBits(overwrite.deny),
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
const result = await RequestManager.patch(endpoints.CHANNEL_BASE(channelID), {
|
||||
...payload,
|
||||
reason,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
interface EditChannelRequest {
|
||||
amount: number;
|
||||
timestamp: number;
|
||||
channelID: string;
|
||||
items: {
|
||||
channelID: string;
|
||||
options: ChannelEditOptions;
|
||||
}[];
|
||||
}
|
||||
|
||||
const editChannelNameTopicQueue = new Map<string, EditChannelRequest>();
|
||||
let editChannelProcessing = false;
|
||||
|
||||
function processEditChannelQueue() {
|
||||
if (!editChannelProcessing) return;
|
||||
|
||||
const now = Date.now();
|
||||
editChannelNameTopicQueue.forEach((request) => {
|
||||
if (now > request.timestamp) return;
|
||||
// 10 minutes have passed so we can reset this channel again
|
||||
if (!request.items.length) {
|
||||
return editChannelNameTopicQueue.delete(request.channelID);
|
||||
}
|
||||
request.amount = 0;
|
||||
// There are items to process for this request
|
||||
const details = request.items.shift();
|
||||
|
||||
if (!details) return;
|
||||
|
||||
editChannel(details.channelID, details.options);
|
||||
const secondDetails = request.items.shift();
|
||||
if (!secondDetails) return;
|
||||
|
||||
return editChannel(secondDetails.channelID, secondDetails.options);
|
||||
});
|
||||
|
||||
if (editChannelNameTopicQueue.size) {
|
||||
setTimeout(() => processEditChannelQueue(), 600000);
|
||||
} else {
|
||||
editChannelProcessing = false;
|
||||
}
|
||||
}
|
||||
28
src/helpers/channels/edit_channel_overwrite.ts
Normal file
28
src/helpers/channels/edit_channel_overwrite.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Overwrite } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import {
|
||||
calculateBits,
|
||||
requireBotGuildPermissions,
|
||||
} from "../../util/permissions.ts";
|
||||
|
||||
/** Edit the channel permission overwrites for a user or role in this channel. Requires `MANAGE_ROLES` permission. */
|
||||
export async function editChannelOverwrite(
|
||||
guildID: string,
|
||||
channelID: string,
|
||||
overwriteID: string,
|
||||
options: Omit<Overwrite, "id">,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_ROLES"]);
|
||||
|
||||
const result = await RequestManager.put(
|
||||
endpoints.CHANNEL_OVERWRITE(channelID, overwriteID),
|
||||
{
|
||||
allow: calculateBits(options.allow),
|
||||
deny: calculateBits(options.deny),
|
||||
type: options.type,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
21
src/helpers/channels/follow_channel.ts
Normal file
21
src/helpers/channels/follow_channel.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { FollowedChannelPayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Follow a News Channel to send messages to a target channel. Requires the `MANAGE_WEBHOOKS` permission in the target channel. Returns the webhook id. */
|
||||
export async function followChannel(
|
||||
sourceChannelID: string,
|
||||
targetChannelID: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(targetChannelID, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const data = (await RequestManager.post(
|
||||
endpoints.CHANNEL_FOLLOW(sourceChannelID),
|
||||
{
|
||||
webhook_channel_id: targetChannelID,
|
||||
},
|
||||
)) as FollowedChannelPayload;
|
||||
|
||||
return data.webhook_id;
|
||||
}
|
||||
25
src/helpers/channels/get_channel.ts
Normal file
25
src/helpers/channels/get_channel.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { ChannelCreatePayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Fetches a single channel object from the api.
|
||||
*
|
||||
* ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your channels will be cached in your guild.**
|
||||
*/
|
||||
export async function getChannel(channelID: string, addToCache = true) {
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_BASE(channelID),
|
||||
)) as ChannelCreatePayload;
|
||||
|
||||
const channelStruct = await structures.createChannelStruct(
|
||||
result,
|
||||
result.guild_id,
|
||||
);
|
||||
if (addToCache) {
|
||||
await cacheHandlers.set("channels", channelStruct.id, channelStruct);
|
||||
}
|
||||
|
||||
return channelStruct;
|
||||
}
|
||||
15
src/helpers/channels/get_channel_webhooks.ts
Normal file
15
src/helpers/channels/get_channel_webhooks.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { WebhookPayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Gets the webhooks for this channel. Requires MANAGE_WEBHOOKS */
|
||||
export async function getChannelWebhooks(channelID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const result = await RequestManager.get(
|
||||
endpoints.CHANNEL_WEBHOOKS(channelID),
|
||||
);
|
||||
|
||||
return result as WebhookPayload[];
|
||||
}
|
||||
24
src/helpers/channels/get_channels.ts
Normal file
24
src/helpers/channels/get_channels.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { ChannelCreatePayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns a list of guild channel objects.
|
||||
*
|
||||
* ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your channels will be cached in your guild.**
|
||||
*/
|
||||
export async function getChannels(guildID: string, addToCache = true) {
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.GUILD_CHANNELS(guildID),
|
||||
) as ChannelCreatePayload[]);
|
||||
|
||||
return Promise.all(result.map(async (res) => {
|
||||
const channelStruct = await structures.createChannelStruct(res, guildID);
|
||||
if (addToCache) {
|
||||
await cacheHandlers.set("channels", channelStruct.id, channelStruct);
|
||||
}
|
||||
|
||||
return channelStruct;
|
||||
}));
|
||||
}
|
||||
15
src/helpers/channels/get_pins.ts
Normal file
15
src/helpers/channels/get_pins.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { MessageCreateOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Get pinned messages in this channel. */
|
||||
export async function getPins(channelID: string) {
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_PINS(channelID),
|
||||
)) as MessageCreateOptions[];
|
||||
|
||||
return Promise.all(
|
||||
result.map((res) => structures.createMessageStruct(res)),
|
||||
);
|
||||
}
|
||||
20
src/helpers/channels/is_channel_synced.ts
Normal file
20
src/helpers/channels/is_channel_synced.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
|
||||
/** Checks whether a channel is synchronized with its parent/category channel or not. */
|
||||
export async function isChannelSynced(channelID: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
if (!channel?.parentID) return false;
|
||||
|
||||
const parentChannel = await cacheHandlers.get("channels", channel.parentID);
|
||||
if (!parentChannel) return false;
|
||||
|
||||
return channel.permissionOverwrites?.every((overwrite) => {
|
||||
const permission = parentChannel.permissionOverwrites?.find(
|
||||
(ow) => ow.id === overwrite.id,
|
||||
);
|
||||
if (!permission) return false;
|
||||
return !(
|
||||
overwrite.allow !== permission.allow || overwrite.deny !== permission.deny
|
||||
);
|
||||
});
|
||||
}
|
||||
40
src/helpers/channels/start_typing.ts
Normal file
40
src/helpers/channels/start_typing.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { ChannelTypes, Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { botHasChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/**
|
||||
* Trigger a typing indicator for the specified channel. Generally bots should **NOT** implement this route.
|
||||
* However, if a bot is responding to a command and expects the computation to take a few seconds,
|
||||
* this endpoint may be called to let the user know that the bot is processing their message.
|
||||
*/
|
||||
export async function startTyping(channelID: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
// If the channel is cached, we can do extra checks/safety
|
||||
if (channel) {
|
||||
if (
|
||||
![
|
||||
ChannelTypes.DM,
|
||||
ChannelTypes.GUILD_NEWS,
|
||||
ChannelTypes.GUILD_TEXT,
|
||||
].includes(channel.type)
|
||||
) {
|
||||
throw new Error(Errors.CHANNEL_NOT_TEXT_BASED);
|
||||
}
|
||||
|
||||
const hasSendMessagesPerm = await botHasChannelPermissions(
|
||||
channelID,
|
||||
["SEND_MESSAGES"],
|
||||
);
|
||||
if (
|
||||
!hasSendMessagesPerm
|
||||
) {
|
||||
throw new Error(Errors.MISSING_SEND_MESSAGES);
|
||||
}
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(endpoints.CHANNEL_TYPING(channelID));
|
||||
|
||||
return result;
|
||||
}
|
||||
20
src/helpers/channels/swap_channels.ts
Normal file
20
src/helpers/channels/swap_channels.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { PositionSwap } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Modify the positions of channels on the guild. Requires MANAGE_CHANNELS permisison. */
|
||||
export async function swapChannels(
|
||||
guildID: string,
|
||||
channelPositions: PositionSwap[],
|
||||
) {
|
||||
if (channelPositions.length < 2) {
|
||||
throw "You must provide at least two channels to be swapped.";
|
||||
}
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.GUILD_CHANNELS(guildID),
|
||||
channelPositions,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
31
src/helpers/commands/create_slash_command.ts
Normal file
31
src/helpers/commands/create_slash_command.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { CreateSlashCommandOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { validateSlashCommands } from "../../util/utils.ts";
|
||||
|
||||
/**
|
||||
* There are two kinds of Slash Commands: global commands and guild commands. Global commands are available for every guild that adds your app; guild commands are specific to the guild you specify when making them. Command names are unique per application within each scope (global and guild). That means:
|
||||
*
|
||||
* - Your app **cannot** have two global commands with the same name
|
||||
* - Your app **cannot** have two guild commands within the same name **on the same guild**
|
||||
* - Your app **can** have a global and guild command with the same name
|
||||
* - Multiple apps **can** have commands with the same names
|
||||
*
|
||||
* Global commands are cached for **1 hour**. That means that new global commands will fan out slowly across all guilds, and will be guaranteed to be updated in an hour.
|
||||
* Guild commands update **instantly**. We recommend you use guild commands for quick testing, and global commands when they're ready for public use.
|
||||
*/
|
||||
export async function createSlashCommand(options: CreateSlashCommandOptions) {
|
||||
validateSlashCommands([options], true);
|
||||
|
||||
const result = await RequestManager.post(
|
||||
options.guildID
|
||||
? endpoints.COMMANDS_GUILD(applicationID, options.guildID)
|
||||
: endpoints.COMMANDS(applicationID),
|
||||
{
|
||||
...options,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
13
src/helpers/commands/delete_slash_command.ts
Normal file
13
src/helpers/commands/delete_slash_command.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Deletes a slash command. */
|
||||
export function deleteSlashCommand(id: string, guildID?: string) {
|
||||
if (!guildID) {
|
||||
return RequestManager.delete(endpoints.COMMANDS_ID(applicationID, id));
|
||||
}
|
||||
return RequestManager.delete(
|
||||
endpoints.COMMANDS_GUILD_ID(applicationID, guildID, id),
|
||||
);
|
||||
}
|
||||
18
src/helpers/commands/delete_slash_response.ts
Normal file
18
src/helpers/commands/delete_slash_response.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** To delete your response to a slash command. If a message id is not provided, it will default to deleting the original response. */
|
||||
export async function deleteSlashResponse(token: string, messageID?: string) {
|
||||
const result = await RequestManager.delete(
|
||||
messageID
|
||||
? endpoints.INTERACTION_ID_TOKEN_MESSAGEID(
|
||||
applicationID,
|
||||
token,
|
||||
messageID,
|
||||
)
|
||||
: endpoints.INTERACTION_ORIGINAL_ID_TOKEN(applicationID, token),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
70
src/helpers/commands/edit_slash_response.ts
Normal file
70
src/helpers/commands/edit_slash_response.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
EditSlashResponseOptions,
|
||||
Errors,
|
||||
MessageCreateOptions,
|
||||
} from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** To edit your response to a slash command. If a messageID is not provided it will default to editing the original response. */
|
||||
export async function editSlashResponse(
|
||||
token: string,
|
||||
options: EditSlashResponseOptions,
|
||||
) {
|
||||
if (options.content && options.content.length > 2000) {
|
||||
throw Error(Errors.MESSAGE_MAX_LENGTH);
|
||||
}
|
||||
|
||||
if (options.embeds && options.embeds.length > 10) {
|
||||
options.embeds.splice(10);
|
||||
}
|
||||
|
||||
if (options.allowed_mentions) {
|
||||
if (options.allowed_mentions.users?.length) {
|
||||
if (options.allowed_mentions.parse.includes("users")) {
|
||||
options.allowed_mentions.parse = options.allowed_mentions.parse.filter(
|
||||
(p) => p !== "users",
|
||||
);
|
||||
}
|
||||
|
||||
if (options.allowed_mentions.users.length > 100) {
|
||||
options.allowed_mentions.users = options.allowed_mentions.users.slice(
|
||||
0,
|
||||
100,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.allowed_mentions.roles?.length) {
|
||||
if (options.allowed_mentions.parse.includes("roles")) {
|
||||
options.allowed_mentions.parse = options.allowed_mentions.parse.filter(
|
||||
(p) => p !== "roles",
|
||||
);
|
||||
}
|
||||
|
||||
if (options.allowed_mentions.roles.length > 100) {
|
||||
options.allowed_mentions.roles = options.allowed_mentions.roles.slice(
|
||||
0,
|
||||
100,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
options.messageID
|
||||
? endpoints.WEBHOOK_MESSAGE(applicationID, token, options.messageID)
|
||||
: endpoints.INTERACTION_ORIGINAL_ID_TOKEN(applicationID, token),
|
||||
options,
|
||||
);
|
||||
|
||||
// If the original message was edited, this will not return a message
|
||||
if (!options.messageID) return result;
|
||||
|
||||
const message = await structures.createMessageStruct(
|
||||
result as MessageCreateOptions,
|
||||
);
|
||||
return message;
|
||||
}
|
||||
48
src/helpers/commands/execute_slash_command.ts
Normal file
48
src/helpers/commands/execute_slash_command.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { SlashCommandResponseOptions } from "../../types/mod.ts";
|
||||
import { cache } from "../../util/cache.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/**
|
||||
* Send a response to a users slash command. The command data will have the id and token necessary to respond.
|
||||
* Interaction `tokens` are valid for **15 minutes** and can be used to send followup messages.
|
||||
*
|
||||
* NOTE: By default we will suppress mentions. To enable mentions, just pass any mentions object.
|
||||
*/
|
||||
export async function executeSlashCommand(
|
||||
id: string,
|
||||
token: string,
|
||||
options: SlashCommandResponseOptions,
|
||||
) {
|
||||
// If its already been executed, we need to send a followup response
|
||||
if (cache.executedSlashCommands.has(token)) {
|
||||
return RequestManager.post(endpoints.WEBHOOK(applicationID, token), {
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
// Expire in 15 minutes
|
||||
cache.executedSlashCommands.set(token, id);
|
||||
setTimeout(
|
||||
() => cache.executedSlashCommands.delete(token),
|
||||
900000,
|
||||
);
|
||||
|
||||
// If the user wants this as a private message mark it ephemeral
|
||||
if (options.private) {
|
||||
options.data.flags = 64;
|
||||
}
|
||||
|
||||
// If no mentions are provided, force disable mentions
|
||||
if (!options.data.allowed_mentions) {
|
||||
options.data.allowed_mentions = { parse: [] };
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.INTERACTION_ID_TOKEN(id, token),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
15
src/helpers/commands/get_slash_command.ts
Normal file
15
src/helpers/commands/get_slash_command.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { SlashCommand } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Fetchs the global command for the given ID. If a guildID is provided, the guild command will be fetched. */
|
||||
export async function getSlashCommand(commandID: string, guildID?: string) {
|
||||
const result = await RequestManager.get(
|
||||
guildID
|
||||
? endpoints.COMMANDS_GUILD_ID(applicationID, guildID, commandID)
|
||||
: endpoints.COMMANDS_ID(applicationID, commandID),
|
||||
);
|
||||
|
||||
return result as SlashCommand;
|
||||
}
|
||||
16
src/helpers/commands/get_slash_commands.ts
Normal file
16
src/helpers/commands/get_slash_commands.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { SlashCommand } from "../../types/mod.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Fetch all of the global commands for your application. */
|
||||
export async function getSlashCommands(guildID?: string) {
|
||||
const result = (await RequestManager.get(
|
||||
guildID
|
||||
? endpoints.COMMANDS_GUILD(applicationID, guildID)
|
||||
: endpoints.COMMANDS(applicationID),
|
||||
)) as SlashCommand[];
|
||||
|
||||
return new Collection(result.map((command) => [command.name, command]));
|
||||
}
|
||||
25
src/helpers/commands/upsert_slash_command.ts
Normal file
25
src/helpers/commands/upsert_slash_command.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { UpsertSlashCommandOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { validateSlashCommands } from "../../util/utils.ts";
|
||||
|
||||
/**
|
||||
* Edit an existing slash command. If this command did not exist, it will create it.
|
||||
*/
|
||||
export async function upsertSlashCommand(
|
||||
commandID: string,
|
||||
options: UpsertSlashCommandOptions,
|
||||
guildID?: string,
|
||||
) {
|
||||
validateSlashCommands([options]);
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
guildID
|
||||
? endpoints.COMMANDS_GUILD_ID(applicationID, guildID, commandID)
|
||||
: endpoints.COMMANDS_ID(applicationID, commandID),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
26
src/helpers/commands/upsert_slash_commands.ts
Normal file
26
src/helpers/commands/upsert_slash_commands.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { applicationID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { UpsertSlashCommandsOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { validateSlashCommands } from "../../util/utils.ts";
|
||||
|
||||
/**
|
||||
* Bulk edit existing slash commands. If a command does not exist, it will create it.
|
||||
*
|
||||
* **NOTE:** Any slash commands that are not specified in this function will be **deleted**. If you don't provide the commandID and rename your command, the command gets a new ID.
|
||||
*/
|
||||
export async function upsertSlashCommands(
|
||||
options: UpsertSlashCommandsOptions[],
|
||||
guildID?: string,
|
||||
) {
|
||||
validateSlashCommands(options);
|
||||
|
||||
const result = await RequestManager.put(
|
||||
guildID
|
||||
? endpoints.COMMANDS_GUILD(applicationID, guildID)
|
||||
: endpoints.COMMANDS(applicationID),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
27
src/helpers/emojis/create_emoji.ts
Normal file
27
src/helpers/emojis/create_emoji.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { CreateEmojisOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
import { urlToBase64 } from "../../util/utils.ts";
|
||||
|
||||
/** 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. If a URL is provided to the image parameter, Discordeno will automatically convert it to a base64 string internally. */
|
||||
export async function createEmoji(
|
||||
guildID: string,
|
||||
name: string,
|
||||
image: string,
|
||||
options: CreateEmojisOptions,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_EMOJIS"]);
|
||||
|
||||
if (image && !image.startsWith("data:image/")) {
|
||||
image = await urlToBase64(image);
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(endpoints.GUILD_EMOJIS(guildID), {
|
||||
...options,
|
||||
name,
|
||||
image,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
19
src/helpers/emojis/delete_emoji.ts
Normal file
19
src/helpers/emojis/delete_emoji.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Delete the given emoji. Requires the MANAGE_EMOJIS permission. Returns 204 No Content on success. */
|
||||
export async function deleteEmoji(
|
||||
guildID: string,
|
||||
id: string,
|
||||
reason?: string,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_EMOJIS"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.GUILD_EMOJI(guildID, id),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
23
src/helpers/emojis/edit_emoji.ts
Normal file
23
src/helpers/emojis/edit_emoji.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { EditEmojisOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Modify the given emoji. Requires the MANAGE_EMOJIS permission. */
|
||||
export async function editEmoji(
|
||||
guildID: string,
|
||||
id: string,
|
||||
options: EditEmojisOptions,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_EMOJIS"]);
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.GUILD_EMOJI(guildID, id),
|
||||
{
|
||||
name: options.name,
|
||||
roles: options.roles,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
4
src/helpers/emojis/emoji_url.ts
Normal file
4
src/helpers/emojis/emoji_url.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/** Creates a url to the emoji from the Discord CDN. */
|
||||
export function emojiURL(id: string, animated = false) {
|
||||
return `https://cdn.discordapp.com/emojis/${id}.${animated ? "gif" : "png"}`;
|
||||
}
|
||||
32
src/helpers/emojis/get_emoji.ts
Normal file
32
src/helpers/emojis/get_emoji.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Emoji, Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/**
|
||||
* Returns an emoji for the given guild and emoji ID.
|
||||
*
|
||||
* ⚠️ **If you need this, you are probably doing something wrong. Always use cache.guilds.get()?.emojis
|
||||
*/
|
||||
export async function getEmoji(
|
||||
guildID: string,
|
||||
emojiID: string,
|
||||
addToCache = true,
|
||||
) {
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.GUILD_EMOJI(guildID, emojiID),
|
||||
)) as Emoji;
|
||||
|
||||
if (addToCache) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
guild.emojis.set(result.id ?? result.name, result);
|
||||
cacheHandlers.set(
|
||||
"guilds",
|
||||
guildID,
|
||||
guild,
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
26
src/helpers/emojis/get_emojis.ts
Normal file
26
src/helpers/emojis/get_emojis.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Emoji, Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/**
|
||||
* Returns a list of emojis for the given guild.
|
||||
*
|
||||
* ⚠️ **If you need this, you are probably doing something wrong. Always use cache.guilds.get()?.emojis
|
||||
*/
|
||||
export async function getEmojis(guildID: string, addToCache = true) {
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.GUILD_EMOJIS(guildID),
|
||||
)) as Emoji[];
|
||||
|
||||
if (addToCache) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
|
||||
result.forEach((emoji) => guild.emojis.set(emoji.id ?? emoji.name, emoji));
|
||||
|
||||
cacheHandlers.set("guilds", guildID, guild);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
1044
src/helpers/guild.ts
1044
src/helpers/guild.ts
File diff suppressed because it is too large
Load Diff
14
src/helpers/guilds/create_guild.ts
Normal file
14
src/helpers/guilds/create_guild.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { CreateGuildPayload, CreateServerOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Create a new guild. Returns a guild object on success. Fires a Guild Create Gateway event. This endpoint can be used only by bots in less than 10 guilds. */
|
||||
export async function createGuild(options: CreateServerOptions) {
|
||||
const guild = (await RequestManager.post(
|
||||
endpoints.GUILDS,
|
||||
options,
|
||||
)) as CreateGuildPayload;
|
||||
|
||||
return structures.createGuildStruct(guild, 0);
|
||||
}
|
||||
10
src/helpers/guilds/delete_server.ts
Normal file
10
src/helpers/guilds/delete_server.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Delete a guild permanently. User must be owner. Returns 204 No Content on success. Fires a Guild Delete Gateway event.
|
||||
*/
|
||||
export async function deleteServer(guildID: string) {
|
||||
const result = await RequestManager.delete(endpoints.GUILDS_BASE(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
29
src/helpers/guilds/edit_guild.ts
Normal file
29
src/helpers/guilds/edit_guild.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { GuildEditOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
import { urlToBase64 } from "../../util/utils.ts";
|
||||
|
||||
/** Modify a guilds settings. Requires the MANAGE_GUILD permission. */
|
||||
export async function editGuild(guildID: string, options: GuildEditOptions) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
if (options.icon && !options.icon.startsWith("data:image/")) {
|
||||
options.icon = await urlToBase64(options.icon);
|
||||
}
|
||||
|
||||
if (options.banner && !options.banner.startsWith("data:image/")) {
|
||||
options.banner = await urlToBase64(options.banner);
|
||||
}
|
||||
|
||||
if (options.splash && !options.splash.startsWith("data:image/")) {
|
||||
options.splash = await urlToBase64(options.splash);
|
||||
}
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.GUILDS_BASE(guildID),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
19
src/helpers/guilds/edit_widget.ts
Normal file
19
src/helpers/guilds/edit_widget.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Modify a guild widget object for the guild. Requires the MANAGE_GUILD permission. */
|
||||
export async function editWidget(
|
||||
guildID: string,
|
||||
enabled: boolean,
|
||||
channelID?: string | null,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.patch(endpoints.GUILD_WIDGET(guildID), {
|
||||
enabled,
|
||||
channel_id: channelID,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
24
src/helpers/guilds/get_audit_logs.ts
Normal file
24
src/helpers/guilds/get_audit_logs.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { AuditLogs, GetAuditLogsOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Returns the audit logs for the guild. Requires VIEW AUDIT LOGS permission */
|
||||
export async function getAuditLogs(
|
||||
guildID: string,
|
||||
options: GetAuditLogsOptions,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["VIEW_AUDIT_LOG"]);
|
||||
|
||||
const result = await RequestManager.get(endpoints.GUILD_AUDIT_LOGS(guildID), {
|
||||
...options,
|
||||
action_type: options.action_type
|
||||
? AuditLogs[options.action_type]
|
||||
: undefined,
|
||||
limit: options.limit && options.limit >= 1 && options.limit <= 100
|
||||
? options.limit
|
||||
: 50,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
9
src/helpers/guilds/get_available_voice_regions.ts
Normal file
9
src/helpers/guilds/get_available_voice_regions.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns an array of voice regions that can be used when creating servers. */
|
||||
export async function getAvailableVoiceRegions() {
|
||||
const result = await RequestManager.get(endpoints.VOICE_REGIONS);
|
||||
|
||||
return result;
|
||||
}
|
||||
15
src/helpers/guilds/get_ban.ts
Normal file
15
src/helpers/guilds/get_ban.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { BannedUser } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Returns a ban object for the given user or a 404 not found if the ban cannot be found. Requires the BAN_MEMBERS permission. */
|
||||
export async function getBan(guildID: string, memberID: string) {
|
||||
await requireBotGuildPermissions(guildID, ["BAN_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.get(
|
||||
endpoints.GUILD_BAN(guildID, memberID),
|
||||
);
|
||||
|
||||
return result as BannedUser;
|
||||
}
|
||||
18
src/helpers/guilds/get_bans.ts
Normal file
18
src/helpers/guilds/get_bans.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { BannedUser } from "../../types/mod.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Returns a list of ban objects for the users banned from this guild. Requires the BAN_MEMBERS permission. */
|
||||
export async function getBans(guildID: string) {
|
||||
await requireBotGuildPermissions(guildID, ["BAN_MEMBERS"]);
|
||||
|
||||
const results = (await RequestManager.get(
|
||||
endpoints.GUILD_BANS(guildID),
|
||||
)) as BannedUser[];
|
||||
|
||||
return new Collection<string, BannedUser>(
|
||||
results.map((res) => [res.user.id, res]),
|
||||
);
|
||||
}
|
||||
18
src/helpers/guilds/get_guild.ts
Normal file
18
src/helpers/guilds/get_guild.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { UpdateGuildPayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/**
|
||||
* ⚠️ **If you need this, you are probably doing something wrong. Always use cache.guilds.get()
|
||||
*
|
||||
* Advanced Devs:
|
||||
* This function fetches a guild's data. This is not the same data as a GUILD_CREATE.
|
||||
* So it does not cache the guild, you must do it manually.
|
||||
* */
|
||||
export async function getGuild(guildID: string, counts = true) {
|
||||
const result = await RequestManager.get(endpoints.GUILDS_BASE(guildID), {
|
||||
with_counts: counts,
|
||||
});
|
||||
|
||||
return result as UpdateGuildPayload;
|
||||
}
|
||||
9
src/helpers/guilds/get_guild_preview.ts
Normal file
9
src/helpers/guilds/get_guild_preview.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns the guild preview object for the given id. If the bot is not in the guild, then the guild must be Discoverable. */
|
||||
export async function getGuildPreview(guildID: string) {
|
||||
const result = await RequestManager.get(endpoints.GUILD_PREVIEW(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
22
src/helpers/guilds/get_prune_count.ts
Normal file
22
src/helpers/guilds/get_prune_count.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors, PruneOptions, PrunePayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
import { camelKeysToSnakeCase, urlToBase64 } from "../../util/utils.ts";
|
||||
|
||||
/** Check how many members would be removed from the server in a prune operation. Requires the KICK_MEMBERS permission */
|
||||
export async function getPruneCount(guildID: string, options?: PruneOptions) {
|
||||
if (options?.days && options.days < 1) throw new Error(Errors.PRUNE_MIN_DAYS);
|
||||
if (options?.days && options.days > 30) {
|
||||
throw new Error(Errors.PRUNE_MAX_DAYS);
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, ["KICK_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.get(
|
||||
endpoints.GUILD_PRUNE(guildID),
|
||||
camelKeysToSnakeCase(options ?? {}),
|
||||
) as PrunePayload;
|
||||
|
||||
return result.pruned;
|
||||
}
|
||||
9
src/helpers/guilds/get_vainty_url.ts
Normal file
9
src/helpers/guilds/get_vainty_url.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns the code and uses of the vanity url for this server if it is enabled. Requires the MANAGE_GUILD permission. */
|
||||
export async function getVanityURL(guildID: string) {
|
||||
const result = await RequestManager.get(endpoints.GUILD_VANITY_URL(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
9
src/helpers/guilds/get_voice_regions.ts
Normal file
9
src/helpers/guilds/get_voice_regions.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns a list of voice region objects for the guild. Unlike the similar /voice route, this returns VIP servers when the guild is VIP-enabled. */
|
||||
export async function getVoiceRegions(guildID: string) {
|
||||
const result = await RequestManager.get(endpoints.GUILD_REGIONS(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
15
src/helpers/guilds/get_widget.ts
Normal file
15
src/helpers/guilds/get_widget.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns the widget for the guild. */
|
||||
export async function getWidget(guildID: string, options?: { force: boolean }) {
|
||||
if (!options?.force) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
if (!guild?.widgetEnabled) throw new Error(Errors.GUILD_WIDGET_NOT_ENABLED);
|
||||
}
|
||||
|
||||
return RequestManager.get(`${endpoints.GUILD_WIDGET(guildID)}.json`);
|
||||
}
|
||||
21
src/helpers/guilds/get_widget_image_url.ts
Normal file
21
src/helpers/guilds/get_widget_image_url.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns the widget image URL for the guild. */
|
||||
export async function getWidgetImageURL(
|
||||
guildID: string,
|
||||
options?: {
|
||||
style?: "shield" | "banner1" | "banner2" | "banner3" | "banner4";
|
||||
force?: boolean;
|
||||
},
|
||||
) {
|
||||
if (!options?.force) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
if (!guild.widgetEnabled) throw new Error(Errors.GUILD_WIDGET_NOT_ENABLED);
|
||||
}
|
||||
|
||||
return `${endpoints.GUILD_WIDGET(guildID)}.png?style=${options?.style ??
|
||||
"shield"}`;
|
||||
}
|
||||
12
src/helpers/guilds/get_widget_settings.ts
Normal file
12
src/helpers/guilds/get_widget_settings.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Returns the guild widget object. Requires the MANAGE_GUILD permission. */
|
||||
export async function getWidgetSettings(guildID: string) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.get(endpoints.GUILD_WIDGET(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
19
src/helpers/guilds/guild_banner_url.ts
Normal file
19
src/helpers/guilds/guild_banner_url.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Guild } from "../../structures/mod.ts";
|
||||
import { ImageFormats, ImageSize } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { formatImageURL } from "../../util/utils.ts";
|
||||
|
||||
/** The full URL of the banner from Discords CDN. Undefined if no banner is set. */
|
||||
export function guildBannerURL(
|
||||
guild: Guild,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return guild.banner
|
||||
? formatImageURL(
|
||||
endpoints.GUILD_BANNER(guild.id, guild.banner),
|
||||
size,
|
||||
format,
|
||||
)
|
||||
: undefined;
|
||||
}
|
||||
15
src/helpers/guilds/guild_icon_url.ts
Normal file
15
src/helpers/guilds/guild_icon_url.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Guild } from "../../structures/mod.ts";
|
||||
import { ImageFormats, ImageSize } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { formatImageURL } from "../../util/utils.ts";
|
||||
|
||||
/** The full URL of the icon from Discords CDN. Undefined when no icon is set. */
|
||||
export function guildIconURL(
|
||||
guild: Guild,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return guild.icon
|
||||
? formatImageURL(endpoints.GUILD_ICON(guild.id, guild.icon), size, format)
|
||||
: undefined;
|
||||
}
|
||||
19
src/helpers/guilds/guild_splash_url.ts
Normal file
19
src/helpers/guilds/guild_splash_url.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Guild } from "../../structures/mod.ts";
|
||||
import { ImageFormats, ImageSize } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { formatImageURL } from "../../util/utils.ts";
|
||||
|
||||
/** The full URL of the splash from Discords CDN. Undefined if no splash is set. */
|
||||
export function guildSplashURL(
|
||||
guild: Guild,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return guild.splash
|
||||
? formatImageURL(
|
||||
endpoints.GUILD_SPLASH(guild.id, guild.splash),
|
||||
size,
|
||||
format,
|
||||
)
|
||||
: undefined;
|
||||
}
|
||||
9
src/helpers/guilds/leave_guild.ts
Normal file
9
src/helpers/guilds/leave_guild.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Leave a guild */
|
||||
export async function leaveGuild(guildID: string) {
|
||||
const result = await RequestManager.delete(endpoints.GUILD_LEAVE(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
14
src/helpers/integrations/delete_integration.ts
Normal file
14
src/helpers/integrations/delete_integration.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Delete the attached integration object for the guild with this id. Requires MANAGE_GUILD permission. */
|
||||
export async function deleteIntegration(guildID: string, id: string) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.GUILD_INTEGRATION(guildID, id),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
20
src/helpers/integrations/edit_integration.ts
Normal file
20
src/helpers/integrations/edit_integration.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { EditIntegrationOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Modify the behavior and settings of an integration object for the guild. Requires the MANAGE_GUILD permission. */
|
||||
export async function editIntegration(
|
||||
guildID: string,
|
||||
id: string,
|
||||
options: EditIntegrationOptions,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.GUILD_INTEGRATION(guildID, id),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
14
src/helpers/integrations/get_integrations.ts
Normal file
14
src/helpers/integrations/get_integrations.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Returns a list of integrations for the guild. Requires the MANAGE_GUILD permission. */
|
||||
export async function getIntegrations(guildID: string) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.get(
|
||||
endpoints.GUILD_INTEGRATIONS(guildID),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
14
src/helpers/integrations/sync_integration.ts
Normal file
14
src/helpers/integrations/sync_integration.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Sync an integration. Requires the MANAGE_GUILD permission. */
|
||||
export async function syncIntegration(guildID: string, id: string) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.GUILD_INTEGRATION_SYNC(guildID, id),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
33
src/helpers/invites/create_invite.ts
Normal file
33
src/helpers/invites/create_invite.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { CreateInviteOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Creates a new invite for this channel. Requires CREATE_INSTANT_INVITE */
|
||||
export async function createInvite(
|
||||
channelID: string,
|
||||
options: CreateInviteOptions,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["CREATE_INSTANT_INVITE"]);
|
||||
|
||||
if (options.max_age && (options.max_age > 604800 || options.max_age < 0)) {
|
||||
console.log(
|
||||
`The max age for invite created in ${channelID} was not between 0-604800. Using default values instead.`,
|
||||
);
|
||||
options.max_age = undefined;
|
||||
}
|
||||
|
||||
if (options.max_uses && (options.max_uses > 100 || options.max_uses < 0)) {
|
||||
console.log(
|
||||
`The max uses for invite created in ${channelID} was not between 0-100. Using default values instead.`,
|
||||
);
|
||||
options.max_uses = undefined;
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.CHANNEL_INVITES(channelID),
|
||||
options,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
27
src/helpers/invites/delete_invite.ts
Normal file
27
src/helpers/invites/delete_invite.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors, InvitePayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import {
|
||||
botHasChannelPermissions,
|
||||
requireBotGuildPermissions,
|
||||
} from "../../util/permissions.ts";
|
||||
|
||||
/** Deletes an invite for the given code. Requires `MANAGE_CHANNELS` or `MANAGE_GUILD` permission */
|
||||
export async function deleteInvite(channelID: string, inviteCode: string) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
|
||||
if (!channel) throw new Error(Errors.CHANNEL_NOT_FOUND);
|
||||
|
||||
const hasPerm = await botHasChannelPermissions(channel, [
|
||||
"MANAGE_CHANNELS",
|
||||
]);
|
||||
|
||||
if (!hasPerm) {
|
||||
await requireBotGuildPermissions(channel!.guildID, ["MANAGE_GUILD"]);
|
||||
}
|
||||
|
||||
const result = await RequestManager.delete(endpoints.INVITE(inviteCode));
|
||||
|
||||
return result as InvitePayload;
|
||||
}
|
||||
12
src/helpers/invites/get_channel_invites.ts
Normal file
12
src/helpers/invites/get_channel_invites.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Gets the invites for this channel. Requires MANAGE_CHANNEL */
|
||||
export async function getChannelInvites(channelID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_CHANNELS"]);
|
||||
|
||||
const result = await RequestManager.get(endpoints.CHANNEL_INVITES(channelID));
|
||||
|
||||
return result;
|
||||
}
|
||||
10
src/helpers/invites/get_invite.ts
Normal file
10
src/helpers/invites/get_invite.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { InvitePayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns an invite for the given code. */
|
||||
export async function getInvite(inviteCode: string) {
|
||||
const result = await RequestManager.get(endpoints.INVITE(inviteCode));
|
||||
|
||||
return result as InvitePayload;
|
||||
}
|
||||
12
src/helpers/invites/get_invites.ts
Normal file
12
src/helpers/invites/get_invites.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Get all the invites for this guild. Requires MANAGE_GUILD permission */
|
||||
export async function getInvites(guildID: string) {
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await RequestManager.get(endpoints.GUILD_INVITES(guildID));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
import { botID } from "../bot.ts";
|
||||
import { cacheHandlers } from "../cache.ts";
|
||||
import { RequestManager } from "../rest/request_manager.ts";
|
||||
import { Member, structures } from "../structures/mod.ts";
|
||||
import {
|
||||
ChannelCreatePayload,
|
||||
DMChannelCreatePayload,
|
||||
EditMemberOptions,
|
||||
Errors,
|
||||
ImageFormats,
|
||||
ImageSize,
|
||||
MemberCreatePayload,
|
||||
MessageContent,
|
||||
Permission,
|
||||
} from "../types/mod.ts";
|
||||
import { endpoints } from "../util/constants.ts";
|
||||
import {
|
||||
highestRole,
|
||||
isHigherPosition,
|
||||
requireBotChannelPermissions,
|
||||
requireBotGuildPermissions,
|
||||
} from "../util/permissions.ts";
|
||||
import { formatImageURL, urlToBase64 } from "../util/utils.ts";
|
||||
import { sendMessage } from "./channel.ts";
|
||||
|
||||
/** The users custom avatar or the default avatar if you don't have a member object. */
|
||||
export function rawAvatarURL(
|
||||
userID: string,
|
||||
discriminator: string,
|
||||
avatar?: string | null,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return avatar
|
||||
? formatImageURL(endpoints.USER_AVATAR(userID, avatar), size, format)
|
||||
: endpoints.USER_DEFAULT_AVATAR(Number(discriminator) % 5);
|
||||
}
|
||||
|
||||
/** The users custom avatar or the default avatar */
|
||||
export function avatarURL(
|
||||
member: Member,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return rawAvatarURL(
|
||||
member.id,
|
||||
member.discriminator,
|
||||
member.avatar,
|
||||
size,
|
||||
format,
|
||||
);
|
||||
}
|
||||
|
||||
/** Add a role to the member */
|
||||
export async function addRole(
|
||||
guildID: string,
|
||||
memberID: string,
|
||||
roleID: string,
|
||||
reason?: string,
|
||||
) {
|
||||
const isHigherRolePosition = await isHigherPosition(
|
||||
guildID,
|
||||
botID,
|
||||
roleID,
|
||||
);
|
||||
if (!isHigherRolePosition) {
|
||||
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_ROLES"]);
|
||||
|
||||
const result = await RequestManager.put(
|
||||
endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Remove a role from the member */
|
||||
export async function removeRole(
|
||||
guildID: string,
|
||||
memberID: string,
|
||||
roleID: string,
|
||||
reason?: string,
|
||||
) {
|
||||
const isHigherRolePosition = await isHigherPosition(
|
||||
guildID,
|
||||
botID,
|
||||
roleID,
|
||||
);
|
||||
if (
|
||||
!isHigherRolePosition
|
||||
) {
|
||||
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, ["MANAGE_ROLES"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.GUILD_MEMBER_ROLE(guildID, memberID, roleID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Send a message to a users DM. Note: this takes 2 API calls. 1 is to fetch the users dm channel. 2 is to send a message to that channel. */
|
||||
export async function sendDirectMessage(
|
||||
memberID: string,
|
||||
content: string | MessageContent,
|
||||
) {
|
||||
let dmChannel = await cacheHandlers.get("channels", memberID);
|
||||
if (!dmChannel) {
|
||||
// If not available in cache create a new one.
|
||||
const dmChannelData = await RequestManager.post(
|
||||
endpoints.USER_DM,
|
||||
{ recipient_id: memberID },
|
||||
) as DMChannelCreatePayload;
|
||||
const channelStruct = await structures.createChannelStruct(
|
||||
dmChannelData as unknown as ChannelCreatePayload,
|
||||
);
|
||||
// Recreate the channel and add it undert he users id
|
||||
await cacheHandlers.set("channels", memberID, channelStruct);
|
||||
dmChannel = channelStruct;
|
||||
}
|
||||
|
||||
// If it does exist try sending a message to this user
|
||||
return sendMessage(dmChannel.id, content);
|
||||
}
|
||||
|
||||
/** Kick a member from the server */
|
||||
export async function kick(guildID: string, memberID: string, reason?: string) {
|
||||
const botsHighestRole = await highestRole(guildID, botID);
|
||||
const membersHighestRole = await highestRole(guildID, memberID);
|
||||
if (
|
||||
botsHighestRole && membersHighestRole &&
|
||||
botsHighestRole.position <= membersHighestRole.position
|
||||
) {
|
||||
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, ["KICK_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.GUILD_MEMBER(guildID, memberID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Edit the member */
|
||||
export async function editMember(
|
||||
guildID: string,
|
||||
memberID: string,
|
||||
options: EditMemberOptions,
|
||||
) {
|
||||
const requiredPerms: Set<Permission> = new Set();
|
||||
|
||||
if (options.nick) {
|
||||
if (options.nick.length > 32) {
|
||||
throw new Error(Errors.NICKNAMES_MAX_LENGTH);
|
||||
}
|
||||
requiredPerms.add("MANAGE_NICKNAMES");
|
||||
}
|
||||
|
||||
if (options.roles) requiredPerms.add("MANAGE_ROLES");
|
||||
|
||||
if (
|
||||
typeof options.mute !== "undefined" ||
|
||||
typeof options.deaf !== "undefined" ||
|
||||
(typeof options.channel_id !== "undefined" || "null")
|
||||
) {
|
||||
const memberVoiceState = (await cacheHandlers.get("guilds", guildID))
|
||||
?.voiceStates.get(memberID);
|
||||
|
||||
if (!memberVoiceState?.channelID) {
|
||||
throw new Error(Errors.MEMBER_NOT_IN_VOICE_CHANNEL);
|
||||
}
|
||||
|
||||
if (typeof options.mute !== "undefined") {
|
||||
requiredPerms.add("MUTE_MEMBERS");
|
||||
}
|
||||
|
||||
if (typeof options.deaf !== "undefined") {
|
||||
requiredPerms.add("DEAFEN_MEMBERS");
|
||||
}
|
||||
|
||||
if (options.channel_id) {
|
||||
const requiredVoicePerms: Set<Permission> = new Set([
|
||||
"CONNECT",
|
||||
"MOVE_MEMBERS",
|
||||
]);
|
||||
if (memberVoiceState) {
|
||||
await requireBotChannelPermissions(
|
||||
memberVoiceState?.channelID,
|
||||
[...requiredVoicePerms],
|
||||
);
|
||||
}
|
||||
await requireBotChannelPermissions(
|
||||
options.channel_id,
|
||||
[...requiredVoicePerms],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, [...requiredPerms]);
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.GUILD_MEMBER(guildID, memberID),
|
||||
options,
|
||||
) as MemberCreatePayload;
|
||||
const member = await structures.createMemberStruct(result, guildID);
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a member from a voice channel to another.
|
||||
* @param guildID the id of the guild which the channel exists in
|
||||
* @param memberID the id of the member to move.
|
||||
* @param channelID id of channel to move user to (if they are connected to voice)
|
||||
*/
|
||||
export function moveMember(
|
||||
guildID: string,
|
||||
memberID: string,
|
||||
channelID: string,
|
||||
) {
|
||||
return editMember(guildID, memberID, { channel_id: channelID });
|
||||
}
|
||||
|
||||
/** Kicks a member from a voice channel */
|
||||
export function kickFromVoiceChannel(guildID: string, memberID: string) {
|
||||
return editMember(guildID, memberID, { channel_id: null });
|
||||
}
|
||||
|
||||
/** Modifies the bot's username or avatar.
|
||||
* NOTE: username: if changed may cause the bot's discriminator to be randomized.
|
||||
*/
|
||||
export async function editBotProfile(username?: string, botAvatarURL?: string) {
|
||||
// Nothing was edited
|
||||
if (!username && !botAvatarURL) return;
|
||||
// Check username requirements if username was provided
|
||||
if (username) {
|
||||
if (username.length > 32) {
|
||||
throw new Error(Errors.USERNAME_MAX_LENGTH);
|
||||
}
|
||||
if (username.length < 2) {
|
||||
throw new Error(Errors.USERNAME_MIN_LENGTH);
|
||||
}
|
||||
if (["@", "#", ":", "```"].some((char) => username.includes(char))) {
|
||||
throw new Error(Errors.USERNAME_INVALID_CHARACTER);
|
||||
}
|
||||
if (["discordtag", "everyone", "here"].includes(username)) {
|
||||
throw new Error(Errors.USERNAME_INVALID_USERNAME);
|
||||
}
|
||||
}
|
||||
|
||||
const avatar = botAvatarURL ? await urlToBase64(botAvatarURL) : undefined;
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.USER_BOT,
|
||||
{
|
||||
username: username?.trim(),
|
||||
avatar,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Edit the nickname of the bot in this guild */
|
||||
export async function editBotNickname(
|
||||
guildID: string,
|
||||
nickname: string | null,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["CHANGE_NICKNAME"]);
|
||||
|
||||
const response = await RequestManager.patch(
|
||||
endpoints.USER_NICK(guildID),
|
||||
{ nick: nickname },
|
||||
) as { nick: string };
|
||||
|
||||
return response.nick;
|
||||
}
|
||||
18
src/helpers/members/avatar_url.ts
Normal file
18
src/helpers/members/avatar_url.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Member } from "../../structures/mod.ts";
|
||||
import { ImageFormats, ImageSize } from "../../types/mod.ts";
|
||||
import { rawAvatarURL } from "./raw_avatar_url.ts";
|
||||
|
||||
/** The users custom avatar or the default avatar */
|
||||
export function avatarURL(
|
||||
member: Member,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return rawAvatarURL(
|
||||
member.id,
|
||||
member.discriminator,
|
||||
member.avatar,
|
||||
size,
|
||||
format,
|
||||
);
|
||||
}
|
||||
19
src/helpers/members/ban_member.ts
Normal file
19
src/helpers/members/ban_member.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { BanOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Ban a user from the guild and optionally delete previous messages sent by the user. Requires the BAN_MEMBERS permission. */
|
||||
export async function ban(guildID: string, id: string, options: BanOptions) {
|
||||
await requireBotGuildPermissions(guildID, ["BAN_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.put(endpoints.GUILD_BAN(guildID, id), {
|
||||
...options,
|
||||
delete_message_days: options.days,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { ban as banMember };
|
||||
9
src/helpers/members/disconnect_member.ts
Normal file
9
src/helpers/members/disconnect_member.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { editMember } from "./edit_member.ts";
|
||||
|
||||
/** Kicks a member from a voice channel */
|
||||
export function kickFromVoiceChannel(guildID: string, memberID: string) {
|
||||
return editMember(guildID, memberID, { channel_id: null });
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { kickFromVoiceChannel as disconnectMember };
|
||||
18
src/helpers/members/edit_bot_nickname.ts
Normal file
18
src/helpers/members/edit_bot_nickname.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Edit the nickname of the bot in this guild */
|
||||
export async function editBotNickname(
|
||||
guildID: string,
|
||||
nickname: string | null,
|
||||
) {
|
||||
await requireBotGuildPermissions(guildID, ["CHANGE_NICKNAME"]);
|
||||
|
||||
const response = await RequestManager.patch(
|
||||
endpoints.USER_NICK(guildID),
|
||||
{ nick: nickname },
|
||||
) as { nick: string };
|
||||
|
||||
return response.nick;
|
||||
}
|
||||
38
src/helpers/members/edit_bot_profile.ts
Normal file
38
src/helpers/members/edit_bot_profile.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { urlToBase64 } from "../../util/utils.ts";
|
||||
|
||||
/** Modifies the bot's username or avatar.
|
||||
* NOTE: username: if changed may cause the bot's discriminator to be randomized.
|
||||
*/
|
||||
export async function editBotProfile(username?: string, botAvatarURL?: string) {
|
||||
// Nothing was edited
|
||||
if (!username && !botAvatarURL) return;
|
||||
// Check username requirements if username was provided
|
||||
if (username) {
|
||||
if (username.length > 32) {
|
||||
throw new Error(Errors.USERNAME_MAX_LENGTH);
|
||||
}
|
||||
if (username.length < 2) {
|
||||
throw new Error(Errors.USERNAME_MIN_LENGTH);
|
||||
}
|
||||
if (["@", "#", ":", "```"].some((char) => username.includes(char))) {
|
||||
throw new Error(Errors.USERNAME_INVALID_CHARACTER);
|
||||
}
|
||||
if (["discordtag", "everyone", "here"].includes(username)) {
|
||||
throw new Error(Errors.USERNAME_INVALID_USERNAME);
|
||||
}
|
||||
}
|
||||
|
||||
const avatar = botAvatarURL ? await urlToBase64(botAvatarURL) : undefined;
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.USER_BOT,
|
||||
{
|
||||
username: username?.trim(),
|
||||
avatar,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
80
src/helpers/members/edit_member.ts
Normal file
80
src/helpers/members/edit_member.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
EditMemberOptions,
|
||||
Errors,
|
||||
MemberCreatePayload,
|
||||
Permission,
|
||||
} from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import {
|
||||
requireBotChannelPermissions,
|
||||
requireBotGuildPermissions,
|
||||
} from "../../util/permissions.ts";
|
||||
|
||||
/** Edit the member */
|
||||
export async function editMember(
|
||||
guildID: string,
|
||||
memberID: string,
|
||||
options: EditMemberOptions,
|
||||
) {
|
||||
const requiredPerms: Set<Permission> = new Set();
|
||||
|
||||
if (options.nick) {
|
||||
if (options.nick.length > 32) {
|
||||
throw new Error(Errors.NICKNAMES_MAX_LENGTH);
|
||||
}
|
||||
requiredPerms.add("MANAGE_NICKNAMES");
|
||||
}
|
||||
|
||||
if (options.roles) requiredPerms.add("MANAGE_ROLES");
|
||||
|
||||
if (
|
||||
typeof options.mute !== "undefined" ||
|
||||
typeof options.deaf !== "undefined" ||
|
||||
(typeof options.channel_id !== "undefined" || "null")
|
||||
) {
|
||||
const memberVoiceState = (await cacheHandlers.get("guilds", guildID))
|
||||
?.voiceStates.get(memberID);
|
||||
|
||||
if (!memberVoiceState?.channelID) {
|
||||
throw new Error(Errors.MEMBER_NOT_IN_VOICE_CHANNEL);
|
||||
}
|
||||
|
||||
if (typeof options.mute !== "undefined") {
|
||||
requiredPerms.add("MUTE_MEMBERS");
|
||||
}
|
||||
|
||||
if (typeof options.deaf !== "undefined") {
|
||||
requiredPerms.add("DEAFEN_MEMBERS");
|
||||
}
|
||||
|
||||
if (options.channel_id) {
|
||||
const requiredVoicePerms: Set<Permission> = new Set([
|
||||
"CONNECT",
|
||||
"MOVE_MEMBERS",
|
||||
]);
|
||||
if (memberVoiceState) {
|
||||
await requireBotChannelPermissions(
|
||||
memberVoiceState?.channelID,
|
||||
[...requiredVoicePerms],
|
||||
);
|
||||
}
|
||||
await requireBotChannelPermissions(
|
||||
options.channel_id,
|
||||
[...requiredVoicePerms],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, [...requiredPerms]);
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.GUILD_MEMBER(guildID, memberID),
|
||||
options,
|
||||
) as MemberCreatePayload;
|
||||
const member = await structures.createMemberStruct(result, guildID);
|
||||
|
||||
return member;
|
||||
}
|
||||
31
src/helpers/members/fetch_members.ts
Normal file
31
src/helpers/members/fetch_members.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { identifyPayload } from "../../bot.ts";
|
||||
import { Guild, Member } from "../../structures/mod.ts";
|
||||
import { Errors, FetchMembersOptions, Intents } from "../../types/mod.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { requestAllMembers } from "../../ws/shard_manager.ts";
|
||||
|
||||
/**
|
||||
* ⚠️ BEGINNER DEVS!! YOU SHOULD ALMOST NEVER NEED THIS AND YOU CAN GET FROM cache.members.get()
|
||||
*
|
||||
* ADVANCED:
|
||||
* Highly recommended to use this function to fetch members instead of getMember from REST.
|
||||
* REST: 50/s global(across all shards) rate limit with ALL requests this included
|
||||
* GW(this function): 120/m(PER shard) rate limit. Meaning if you have 8 shards your limit is now 960/m.
|
||||
*/
|
||||
export function fetchMembers(guild: Guild, options?: FetchMembersOptions) {
|
||||
// You can request 1 member without the intent
|
||||
if (
|
||||
(!options?.limit || options.limit > 1) &&
|
||||
!(identifyPayload.intents && Intents.GUILD_MEMBERS)
|
||||
) {
|
||||
throw new Error(Errors.MISSING_INTENT_GUILD_MEMBERS);
|
||||
}
|
||||
|
||||
if (options?.userIDs?.length) {
|
||||
options.limit = options.userIDs.length;
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
return requestAllMembers(guild, resolve, options);
|
||||
}) as Promise<Collection<string, Member>>;
|
||||
}
|
||||
27
src/helpers/members/get_member.ts
Normal file
27
src/helpers/members/get_member.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { MemberCreatePayload } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Returns a guild member object for the specified user.
|
||||
*
|
||||
* ⚠️ **ADVANCED USE ONLY: Your members will be cached in your guild most likely. Only use this when you are absolutely sure the member is not cached.**
|
||||
*/
|
||||
export async function getMember(
|
||||
guildID: string,
|
||||
id: string,
|
||||
options?: { force?: boolean },
|
||||
) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild && !options?.force) return;
|
||||
|
||||
const data = (await RequestManager.get(
|
||||
endpoints.GUILD_MEMBER(guildID, id),
|
||||
)) as MemberCreatePayload;
|
||||
|
||||
const memberStruct = await structures.createMemberStruct(data, guildID);
|
||||
await cacheHandlers.set("members", memberStruct.id, memberStruct);
|
||||
|
||||
return memberStruct;
|
||||
}
|
||||
82
src/helpers/members/get_members.ts
Normal file
82
src/helpers/members/get_members.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { identifyPayload } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Member, structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
Errors,
|
||||
GetMemberOptions,
|
||||
Intents,
|
||||
MemberCreatePayload,
|
||||
} from "../../types/mod.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/**
|
||||
* ⚠️ BEGINNER DEVS!! YOU SHOULD ALMOST NEVER NEED THIS AND YOU CAN GET FROM cache.members.get()
|
||||
*
|
||||
* ADVANCED:
|
||||
* Highly recommended to **NOT** use this function to get members instead use fetchMembers().
|
||||
* REST(this function): 50/s global(across all shards) rate limit with ALL requests this included
|
||||
* GW(fetchMembers): 120/m(PER shard) rate limit. Meaning if you have 8 shards your limit is 960/m.
|
||||
*/
|
||||
export async function getMembers(guildID: string, options?: GetMemberOptions) {
|
||||
if (!(identifyPayload.intents && Intents.GUILD_MEMBERS)) {
|
||||
throw new Error(Errors.MISSING_INTENT_GUILD_MEMBERS);
|
||||
}
|
||||
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
|
||||
const members = new Collection<string, Member>();
|
||||
|
||||
let membersLeft = options?.limit ?? guild.memberCount;
|
||||
let loops = 1;
|
||||
while (
|
||||
(options?.limit ?? guild.memberCount) > members.size &&
|
||||
membersLeft > 0
|
||||
) {
|
||||
if (options?.limit && options.limit > 1000) {
|
||||
console.log(
|
||||
`Paginating get members from REST. #${loops} / ${
|
||||
Math.ceil(
|
||||
(options?.limit ?? 1) / 1000,
|
||||
)
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
const result = (await RequestManager.get(
|
||||
`${endpoints.GUILD_MEMBERS(guildID)}?limit=${
|
||||
membersLeft > 1000 ? 1000 : membersLeft
|
||||
}${options?.after ? `&after=${options.after}` : ""}`,
|
||||
)) as MemberCreatePayload[];
|
||||
|
||||
const memberStructures = await Promise.all(
|
||||
result.map(async (member) => {
|
||||
const memberStruct = await structures.createMemberStruct(
|
||||
member,
|
||||
guildID,
|
||||
);
|
||||
|
||||
await cacheHandlers.set("members", memberStruct.id, memberStruct);
|
||||
|
||||
return memberStruct;
|
||||
}),
|
||||
) as Member[];
|
||||
|
||||
if (!memberStructures.length) break;
|
||||
|
||||
memberStructures.forEach((member) => members.set(member.id, member));
|
||||
|
||||
options = {
|
||||
limit: options?.limit,
|
||||
after: memberStructures[memberStructures.length - 1].id,
|
||||
};
|
||||
|
||||
membersLeft -= 1000;
|
||||
|
||||
loops++;
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
21
src/helpers/members/get_members_by_query.ts
Normal file
21
src/helpers/members/get_members_by_query.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { Member } from "../../structures/mod.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { requestAllMembers } from "../../ws/shard_manager.ts";
|
||||
|
||||
/** Returns guild member objects for the specified user by their nickname/username.
|
||||
*
|
||||
* ⚠️ **ADVANCED USE ONLY: Your members will be cached in your guild most likely. Only use this when you are absolutely sure the member is not cached.**
|
||||
*/
|
||||
export async function getMembersByQuery(
|
||||
guildID: string,
|
||||
name: string,
|
||||
limit = 1,
|
||||
) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) return;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
return requestAllMembers(guild, resolve, { query: name, limit });
|
||||
}) as Promise<Collection<string, Member>>;
|
||||
}
|
||||
32
src/helpers/members/kick_member.ts
Normal file
32
src/helpers/members/kick_member.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { botID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import {
|
||||
highestRole,
|
||||
requireBotGuildPermissions,
|
||||
} from "../../util/permissions.ts";
|
||||
|
||||
/** Kick a member from the server */
|
||||
export async function kick(guildID: string, memberID: string, reason?: string) {
|
||||
const botsHighestRole = await highestRole(guildID, botID);
|
||||
const membersHighestRole = await highestRole(guildID, memberID);
|
||||
if (
|
||||
botsHighestRole && membersHighestRole &&
|
||||
botsHighestRole.position <= membersHighestRole.position
|
||||
) {
|
||||
throw new Error(Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await requireBotGuildPermissions(guildID, ["KICK_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.GUILD_MEMBER(guildID, memberID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { kick as kickMember };
|
||||
15
src/helpers/members/move_member.ts
Normal file
15
src/helpers/members/move_member.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { editMember } from "./edit_member.ts";
|
||||
|
||||
/**
|
||||
* Move a member from a voice channel to another.
|
||||
* @param guildID the id of the guild which the channel exists in
|
||||
* @param memberID the id of the member to move.
|
||||
* @param channelID id of channel to move user to (if they are connected to voice)
|
||||
*/
|
||||
export function moveMember(
|
||||
guildID: string,
|
||||
memberID: string,
|
||||
channelID: string,
|
||||
) {
|
||||
return editMember(guildID, memberID, { channel_id: channelID });
|
||||
}
|
||||
27
src/helpers/members/prune_members.ts
Normal file
27
src/helpers/members/prune_members.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors, PruneOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
import { camelKeysToSnakeCase } from "../../util/utils.ts";
|
||||
|
||||
/**
|
||||
* Begin a prune operation. Requires the KICK_MEMBERS permission. Returns an object with one 'pruned' key indicating the number of members that were removed in the prune operation. For large guilds it's recommended to set the computePruneCount option to false, forcing 'pruned' to null. Fires multiple Guild Member Remove Gateway events.
|
||||
*
|
||||
* By default, prune will not remove users with roles. You can optionally include specific roles in your prune by providing the roles (resolved to include_roles internally) parameter. Any inactive user that has a subset of the provided role(s) will be included in the prune and users with additional roles will not.
|
||||
*/
|
||||
export async function pruneMembers(
|
||||
guildID: string,
|
||||
options: PruneOptions,
|
||||
) {
|
||||
if (options.days && options.days < 1) throw new Error(Errors.PRUNE_MIN_DAYS);
|
||||
if (options.days && options.days > 30) throw new Error(Errors.PRUNE_MAX_DAYS);
|
||||
|
||||
await requireBotGuildPermissions(guildID, ["KICK_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.GUILD_PRUNE(guildID),
|
||||
camelKeysToSnakeCase(options),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
16
src/helpers/members/raw_avatar_url.ts
Normal file
16
src/helpers/members/raw_avatar_url.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ImageFormats, ImageSize } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { formatImageURL } from "../../util/utils.ts";
|
||||
|
||||
/** The users custom avatar or the default avatar if you don't have a member object. */
|
||||
export function rawAvatarURL(
|
||||
userID: string,
|
||||
discriminator: string,
|
||||
avatar?: string | null,
|
||||
size: ImageSize = 128,
|
||||
format?: ImageFormats,
|
||||
) {
|
||||
return avatar
|
||||
? formatImageURL(endpoints.USER_AVATAR(userID, avatar), size, format)
|
||||
: endpoints.USER_DEFAULT_AVATAR(Number(discriminator) % 5);
|
||||
}
|
||||
34
src/helpers/members/send_direct_message.ts
Normal file
34
src/helpers/members/send_direct_message.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
ChannelCreatePayload,
|
||||
DMChannelCreatePayload,
|
||||
MessageContent,
|
||||
} from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { sendMessage } from "../messages/send_message.ts";
|
||||
|
||||
/** Send a message to a users DM. Note: this takes 2 API calls. 1 is to fetch the users dm channel. 2 is to send a message to that channel. */
|
||||
export async function sendDirectMessage(
|
||||
memberID: string,
|
||||
content: string | MessageContent,
|
||||
) {
|
||||
let dmChannel = await cacheHandlers.get("channels", memberID);
|
||||
if (!dmChannel) {
|
||||
// If not available in cache create a new one.
|
||||
const dmChannelData = await RequestManager.post(
|
||||
endpoints.USER_DM,
|
||||
{ recipient_id: memberID },
|
||||
) as DMChannelCreatePayload;
|
||||
const channelStruct = await structures.createChannelStruct(
|
||||
dmChannelData as unknown as ChannelCreatePayload,
|
||||
);
|
||||
// Recreate the channel and add it undert he users id
|
||||
await cacheHandlers.set("channels", memberID, channelStruct);
|
||||
dmChannel = channelStruct;
|
||||
}
|
||||
|
||||
// If it does exist try sending a message to this user
|
||||
return sendMessage(dmChannel.id, content);
|
||||
}
|
||||
15
src/helpers/members/unban_member.ts
Normal file
15
src/helpers/members/unban_member.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotGuildPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Remove the ban for a user. Requires BAN_MEMBERS permission */
|
||||
export async function unban(guildID: string, id: string) {
|
||||
await requireBotGuildPermissions(guildID, ["BAN_MEMBERS"]);
|
||||
|
||||
const result = await RequestManager.delete(endpoints.GUILD_BAN(guildID, id));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { unban as unbanMember };
|
||||
@@ -1,253 +0,0 @@
|
||||
import { botID } from "../bot.ts";
|
||||
import { cacheHandlers } from "../cache.ts";
|
||||
import { RequestManager } from "../rest/request_manager.ts";
|
||||
import { Message, structures } from "../structures/mod.ts";
|
||||
import {
|
||||
DiscordGetReactionsParams,
|
||||
Errors,
|
||||
MessageContent,
|
||||
MessageCreateOptions,
|
||||
Permission,
|
||||
UserPayload,
|
||||
} from "../types/mod.ts";
|
||||
import { Collection } from "../util/collection.ts";
|
||||
import { endpoints } from "../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../util/permissions.ts";
|
||||
import { delay } from "../util/utils.ts";
|
||||
|
||||
/** Delete a message with the channel id and message id only. */
|
||||
export async function deleteMessageByID(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reason?: string,
|
||||
delayMilliseconds = 0,
|
||||
) {
|
||||
const message = await cacheHandlers.get("messages", messageID);
|
||||
if (message) return deleteMessage(message, reason, delayMilliseconds);
|
||||
|
||||
if (delayMilliseconds) await delay(delayMilliseconds);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE(channelID, messageID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Delete a message */
|
||||
export async function deleteMessage(
|
||||
message: Message,
|
||||
reason?: string,
|
||||
delayMilliseconds = 0,
|
||||
) {
|
||||
if (message.author.id !== botID) {
|
||||
// This needs to check the channels permission not the guild permission
|
||||
await requireBotChannelPermissions(message.channelID, ["MANAGE_MESSAGES"]);
|
||||
}
|
||||
|
||||
if (delayMilliseconds) await delay(delayMilliseconds);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE(message.channelID, message.id),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Pin a message in a channel. Requires MANAGE_MESSAGES. Max pins allowed in a channel = 50. */
|
||||
export async function pin(channelID: string, messageID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_MESSAGES"]);
|
||||
|
||||
const result = await RequestManager.put(
|
||||
endpoints.CHANNEL_PIN(channelID, messageID),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Unpin a message in a channel. Requires MANAGE_MESSAGES. */
|
||||
export async function unpin(channelID: string, messageID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_MESSAGES"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_PIN(channelID, messageID),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
export async function addReaction(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, [
|
||||
"ADD_REACTIONS",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
]);
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
reaction = reaction.substring(3, reaction.length - 1);
|
||||
}
|
||||
|
||||
const result = await RequestManager.put(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION_ME(channelID, messageID, reaction),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: add a return?
|
||||
/** Adds multiple reactions to a message. If `ordered` is true(default is false), it will add the reactions one at a time in the order provided. Note: Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. Requires READ_MESSAGE_HISTORY and ADD_REACTIONS */
|
||||
export async function addReactions(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reactions: string[],
|
||||
ordered = false,
|
||||
) {
|
||||
if (!ordered) {
|
||||
await Promise.all(
|
||||
reactions.map((reaction) => addReaction(channelID, messageID, reaction)),
|
||||
);
|
||||
} else {
|
||||
for (const reaction of reactions) {
|
||||
await addReaction(channelID, messageID, reaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes a reaction from the bot on this message. Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. */
|
||||
export async function removeReaction(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
) {
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
reaction = reaction.substring(3, reaction.length - 1);
|
||||
}
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION_ME(channelID, messageID, reaction),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Removes a reaction from the specified user on this message. Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. */
|
||||
export async function removeUserReaction(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
userID: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_MESSAGES"]);
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
reaction = reaction.substring(3, reaction.length - 1);
|
||||
}
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION_USER(
|
||||
channelID,
|
||||
messageID,
|
||||
reaction,
|
||||
userID,
|
||||
),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Removes all reactions for all emojis on this message. */
|
||||
export async function removeAllReactions(channelID: string, messageID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_MESSAGES"]);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE_REACTIONS(channelID, messageID),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Removes all reactions for a single emoji on this message. Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. */
|
||||
export async function removeReactionEmoji(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_MESSAGES"]);
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
reaction = reaction.substring(3, reaction.length - 1);
|
||||
}
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Get a list of users that reacted with this emoji. */
|
||||
export async function getReactions(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
options?: DiscordGetReactionsParams,
|
||||
) {
|
||||
const users = (await RequestManager.get(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction),
|
||||
options,
|
||||
)) as UserPayload[];
|
||||
|
||||
return new Collection(users.map((user) => [user.id, user]));
|
||||
}
|
||||
|
||||
/** Edit the message. */
|
||||
export async function editMessage(
|
||||
message: Message,
|
||||
content: string | MessageContent,
|
||||
) {
|
||||
if (message.author.id !== botID) {
|
||||
throw "You can only edit a message that was sent by the bot.";
|
||||
}
|
||||
|
||||
if (typeof content === "string") content = { content };
|
||||
|
||||
const requiredPerms: Permission[] = ["SEND_MESSAGES"];
|
||||
|
||||
if (content.tts) requiredPerms.push("SEND_TTS_MESSAGES");
|
||||
|
||||
await requireBotChannelPermissions(message.channelID, requiredPerms);
|
||||
|
||||
if (content.content && content.content.length > 2000) {
|
||||
throw new Error(Errors.MESSAGE_MAX_LENGTH);
|
||||
}
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.CHANNEL_MESSAGE(message.channelID, message.id),
|
||||
content,
|
||||
);
|
||||
|
||||
return structures.createMessageStruct(result as MessageCreateOptions);
|
||||
}
|
||||
|
||||
/** Crosspost a message in a News Channel to following channels. */
|
||||
export async function publishMessage(channelID: string, messageID: string) {
|
||||
const data = (await RequestManager.post(
|
||||
endpoints.CHANNEL_MESSAGE_CROSSPOST(channelID, messageID),
|
||||
)) as MessageCreateOptions;
|
||||
|
||||
return structures.createMessageStruct(data);
|
||||
}
|
||||
27
src/helpers/messages/add_reaction.ts
Normal file
27
src/helpers/messages/add_reaction.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** 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 */
|
||||
export async function addReaction(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, [
|
||||
"ADD_REACTIONS",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
]);
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
reaction = reaction.substring(3, reaction.length - 1);
|
||||
}
|
||||
|
||||
const result = await RequestManager.put(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION_ME(channelID, messageID, reaction),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
19
src/helpers/messages/add_reactions.ts
Normal file
19
src/helpers/messages/add_reactions.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { addReaction } from "./add_reaction.ts";
|
||||
|
||||
/** Adds multiple reactions to a message. If `ordered` is true(default is false), it will add the reactions one at a time in the order provided. Note: Reaction takes the form of **name:id** for custom guild emoji, or Unicode characters. Requires READ_MESSAGE_HISTORY and ADD_REACTIONS */
|
||||
export async function addReactions(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reactions: string[],
|
||||
ordered = false,
|
||||
) {
|
||||
if (!ordered) {
|
||||
await Promise.all(
|
||||
reactions.map((reaction) => addReaction(channelID, messageID, reaction)),
|
||||
);
|
||||
} else {
|
||||
for (const reaction of reactions) {
|
||||
await addReaction(channelID, messageID, reaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/helpers/messages/delete_message.ts
Normal file
27
src/helpers/messages/delete_message.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { botID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Message } from "../../structures/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
import { delay } from "../../util/utils.ts";
|
||||
|
||||
/** Delete a message */
|
||||
export async function deleteMessage(
|
||||
message: Message,
|
||||
reason?: string,
|
||||
delayMilliseconds = 0,
|
||||
) {
|
||||
if (message.author.id !== botID) {
|
||||
// This needs to check the channels permission not the guild permission
|
||||
await requireBotChannelPermissions(message.channelID, ["MANAGE_MESSAGES"]);
|
||||
}
|
||||
|
||||
if (delayMilliseconds) await delay(delayMilliseconds);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE(message.channelID, message.id),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
25
src/helpers/messages/delete_message_by_id.ts
Normal file
25
src/helpers/messages/delete_message_by_id.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { delay } from "../../util/utils.ts";
|
||||
import { deleteMessage } from "./delete_message.ts";
|
||||
|
||||
/** Delete a message with the channel id and message id only. */
|
||||
export async function deleteMessageByID(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reason?: string,
|
||||
delayMilliseconds = 0,
|
||||
) {
|
||||
const message = await cacheHandlers.get("messages", messageID);
|
||||
if (message) return deleteMessage(message, reason, delayMilliseconds);
|
||||
|
||||
if (delayMilliseconds) await delay(delayMilliseconds);
|
||||
|
||||
const result = await RequestManager.delete(
|
||||
endpoints.CHANNEL_MESSAGE(channelID, messageID),
|
||||
{ reason },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
33
src/helpers/messages/delete_messages.ts
Normal file
33
src/helpers/messages/delete_messages.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Errors } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Delete messages from the channel. 2-100. Requires the MANAGE_MESSAGES permission */
|
||||
export async function deleteMessages(
|
||||
channelID: string,
|
||||
ids: string[],
|
||||
reason?: string,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, ["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.`,
|
||||
);
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.CHANNEL_BULK_DELETE(channelID),
|
||||
{
|
||||
messages: ids.splice(0, 100),
|
||||
reason,
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
40
src/helpers/messages/edit_message.ts
Normal file
40
src/helpers/messages/edit_message.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { botID } from "../../bot.ts";
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { Message, structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
Errors,
|
||||
MessageContent,
|
||||
MessageCreateOptions,
|
||||
Permission,
|
||||
} from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Edit the message. */
|
||||
export async function editMessage(
|
||||
message: Message,
|
||||
content: string | MessageContent,
|
||||
) {
|
||||
if (message.author.id !== botID) {
|
||||
throw "You can only edit a message that was sent by the bot.";
|
||||
}
|
||||
|
||||
if (typeof content === "string") content = { content };
|
||||
|
||||
const requiredPerms: Permission[] = ["SEND_MESSAGES"];
|
||||
|
||||
if (content.tts) requiredPerms.push("SEND_TTS_MESSAGES");
|
||||
|
||||
await requireBotChannelPermissions(message.channelID, requiredPerms);
|
||||
|
||||
if (content.content && content.content.length > 2000) {
|
||||
throw new Error(Errors.MESSAGE_MAX_LENGTH);
|
||||
}
|
||||
|
||||
const result = await RequestManager.patch(
|
||||
endpoints.CHANNEL_MESSAGE(message.channelID, message.id),
|
||||
content,
|
||||
);
|
||||
|
||||
return structures.createMessageStruct(result as MessageCreateOptions);
|
||||
}
|
||||
19
src/helpers/messages/get_message.ts
Normal file
19
src/helpers/messages/get_message.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { MessageCreateOptions } from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Fetch a single message from the server. Requires VIEW_CHANNEL and READ_MESSAGE_HISTORY */
|
||||
export async function getMessage(channelID: string, id: string) {
|
||||
await requireBotChannelPermissions(channelID, [
|
||||
"VIEW_CHANNEL",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
]);
|
||||
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_MESSAGE(channelID, id),
|
||||
)) as MessageCreateOptions;
|
||||
|
||||
return structures.createMessageStruct(result);
|
||||
}
|
||||
37
src/helpers/messages/get_messages.ts
Normal file
37
src/helpers/messages/get_messages.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import {
|
||||
GetMessages,
|
||||
GetMessagesAfter,
|
||||
GetMessagesAround,
|
||||
GetMessagesBefore,
|
||||
MessageCreateOptions,
|
||||
} from "../../types/mod.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Fetches between 2-100 messages. Requires VIEW_CHANNEL and READ_MESSAGE_HISTORY */
|
||||
export async function getMessages(
|
||||
channelID: string,
|
||||
options?:
|
||||
| GetMessagesAfter
|
||||
| GetMessagesBefore
|
||||
| GetMessagesAround
|
||||
| GetMessages,
|
||||
) {
|
||||
await requireBotChannelPermissions(channelID, [
|
||||
"VIEW_CHANNEL",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
]);
|
||||
|
||||
if (options?.limit && options.limit > 100) return;
|
||||
|
||||
const result = (await RequestManager.get(
|
||||
endpoints.CHANNEL_MESSAGES(channelID),
|
||||
options,
|
||||
)) as MessageCreateOptions[];
|
||||
|
||||
return Promise.all(
|
||||
result.map((res) => structures.createMessageStruct(res)),
|
||||
);
|
||||
}
|
||||
19
src/helpers/messages/get_reactions.ts
Normal file
19
src/helpers/messages/get_reactions.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { DiscordGetReactionsParams, UserPayload } from "../../types/mod.ts";
|
||||
import { Collection } from "../../util/collection.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
|
||||
/** Get a list of users that reacted with this emoji. */
|
||||
export async function getReactions(
|
||||
channelID: string,
|
||||
messageID: string,
|
||||
reaction: string,
|
||||
options?: DiscordGetReactionsParams,
|
||||
) {
|
||||
const users = (await RequestManager.get(
|
||||
endpoints.CHANNEL_MESSAGE_REACTION(channelID, messageID, reaction),
|
||||
options,
|
||||
)) as UserPayload[];
|
||||
|
||||
return new Collection(users.map((user) => [user.id, user]));
|
||||
}
|
||||
17
src/helpers/messages/pin_message.ts
Normal file
17
src/helpers/messages/pin_message.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { RequestManager } from "../../rest/request_manager.ts";
|
||||
import { endpoints } from "../../util/constants.ts";
|
||||
import { requireBotChannelPermissions } from "../../util/permissions.ts";
|
||||
|
||||
/** Pin a message in a channel. Requires MANAGE_MESSAGES. Max pins allowed in a channel = 50. */
|
||||
export async function pin(channelID: string, messageID: string) {
|
||||
await requireBotChannelPermissions(channelID, ["MANAGE_MESSAGES"]);
|
||||
|
||||
const result = await RequestManager.put(
|
||||
endpoints.CHANNEL_PIN(channelID, messageID),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { pin as pinMessage };
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user