mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-03 17:30:07 +00:00
i love you
This commit is contained in:
66
src/bot.ts
66
src/bot.ts
@@ -1,24 +1,3 @@
|
||||
import {
|
||||
calculateChannelOverwrites,
|
||||
calculateBasePermissions,
|
||||
getCached,
|
||||
hasChannelPermissions,
|
||||
hasGuildPermissions,
|
||||
validatePermissions,
|
||||
getMissingChannelPermissions,
|
||||
getMissingGuildPermissions,
|
||||
requireGuildPermissions,
|
||||
requireChannelPermissions,
|
||||
highestRole,
|
||||
higherRolePosition,
|
||||
requireBotChannelPermissions,
|
||||
requireBotGuildPermissions,
|
||||
botHasChannelPermissions,
|
||||
calculateBits,
|
||||
isHigherPosition,
|
||||
requireOverwritePermissions,
|
||||
calculatePermissions,
|
||||
} from "./util/permissions.ts";
|
||||
import {
|
||||
checkRateLimits,
|
||||
processQueue,
|
||||
@@ -320,34 +299,14 @@ export function createUtils(options: Partial<HelperUtils>) {
|
||||
delay,
|
||||
iconHashToBigInt,
|
||||
iconBigintToHash,
|
||||
// Permissions
|
||||
getCached,
|
||||
calculateBasePermissions,
|
||||
calculateChannelOverwrites,
|
||||
getMissingChannelPermissions,
|
||||
getMissingGuildPermissions,
|
||||
hasGuildPermissions,
|
||||
hasChannelPermissions,
|
||||
requireGuildPermissions,
|
||||
requireChannelPermissions,
|
||||
validatePermissions,
|
||||
highestRole,
|
||||
higherRolePosition,
|
||||
validateLength,
|
||||
validateSlashOptions,
|
||||
validateSlashOptionChoices,
|
||||
requireBotChannelPermissions,
|
||||
requireBotGuildPermissions,
|
||||
validateComponents,
|
||||
hasProperty,
|
||||
urlToBase64,
|
||||
botHasChannelPermissions,
|
||||
calculateBits,
|
||||
isHigherPosition,
|
||||
formatImageURL,
|
||||
validateSlashCommands,
|
||||
requireOverwritePermissions,
|
||||
calculatePermissions,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -358,33 +317,14 @@ export interface HelperUtils {
|
||||
delay: typeof delay;
|
||||
iconHashToBigInt: typeof iconHashToBigInt;
|
||||
iconBigintToHash: typeof iconBigintToHash;
|
||||
getCached: typeof getCached;
|
||||
calculateBasePermissions: typeof calculateBasePermissions;
|
||||
calculateChannelOverwrites: typeof calculateChannelOverwrites;
|
||||
hasGuildPermissions: typeof hasGuildPermissions;
|
||||
hasChannelPermissions: typeof hasChannelPermissions;
|
||||
validatePermissions: typeof validatePermissions;
|
||||
getMissingChannelPermissions: typeof getMissingChannelPermissions;
|
||||
getMissingGuildPermissions: typeof getMissingGuildPermissions;
|
||||
requireGuildPermissions: typeof requireGuildPermissions;
|
||||
requireChannelPermissions: typeof requireChannelPermissions;
|
||||
highestRole: typeof highestRole;
|
||||
higherRolePosition: typeof higherRolePosition;
|
||||
validateLength: typeof validateLength;
|
||||
validateSlashOptions: typeof validateSlashOptions;
|
||||
validateSlashOptionChoices: typeof validateSlashOptionChoices;
|
||||
requireBotChannelPermissions: typeof requireBotChannelPermissions;
|
||||
requireBotGuildPermissions: typeof requireBotGuildPermissions;
|
||||
botHasChannelPermissions: typeof botHasChannelPermissions;
|
||||
validateComponents: typeof validateComponents;
|
||||
hasProperty: typeof hasProperty;
|
||||
urlToBase64: typeof urlToBase64;
|
||||
calculateBits: typeof calculateBits;
|
||||
isHigherPosition: typeof isHigherPosition;
|
||||
formatImageURL: typeof formatImageURL;
|
||||
validateSlashCommands: typeof validateSlashCommands;
|
||||
requireOverwritePermissions: typeof requireOverwritePermissions;
|
||||
calculatePermissions: typeof calculatePermissions;
|
||||
}
|
||||
|
||||
export function createGatewayManager(
|
||||
@@ -613,7 +553,6 @@ export interface Helpers {
|
||||
isButton: typeof helpers.isButton;
|
||||
isSelectMenu: typeof helpers.isSelectMenu;
|
||||
isSlashCommand: typeof helpers.isSlashCommand;
|
||||
kick: typeof helpers.kick;
|
||||
kickMember: typeof helpers.kickMember;
|
||||
leaveGuild: typeof helpers.leaveGuild;
|
||||
moveMember: typeof helpers.moveMember;
|
||||
@@ -632,9 +571,7 @@ export interface Helpers {
|
||||
startTyping: typeof helpers.startTyping;
|
||||
swapChannels: typeof helpers.swapChannels;
|
||||
syncGuildTemplate: typeof helpers.syncGuildTemplate;
|
||||
unban: typeof helpers.unban;
|
||||
unbanMember: typeof helpers.unbanMember;
|
||||
unpin: typeof helpers.unpin;
|
||||
unpinMessage: typeof helpers.unpinMessage;
|
||||
updateBotVoiceState: typeof helpers.updateBotVoiceState;
|
||||
updateStageInstance: typeof helpers.updateStageInstance;
|
||||
@@ -785,7 +722,6 @@ export function createBaseHelpers(options: Partial<Helpers>) {
|
||||
isButton: options.isButton || helpers.isButton,
|
||||
isSelectMenu: options.isSelectMenu || helpers.isSelectMenu,
|
||||
isSlashCommand: options.isSlashCommand || helpers.isSlashCommand,
|
||||
kick: options.kick || helpers.kick,
|
||||
kickMember: options.kickMember || helpers.kickMember,
|
||||
leaveGuild: options.leaveGuild || helpers.leaveGuild,
|
||||
moveMember: options.moveMember || helpers.moveMember,
|
||||
@@ -804,9 +740,7 @@ export function createBaseHelpers(options: Partial<Helpers>) {
|
||||
startTyping: options.startTyping || helpers.startTyping,
|
||||
swapChannels: options.swapChannels || helpers.swapChannels,
|
||||
syncGuildTemplate: options.syncGuildTemplate || helpers.syncGuildTemplate,
|
||||
unban: options.unban || helpers.unban,
|
||||
unbanMember: options.unbanMember || helpers.unbanMember,
|
||||
unpin: options.unpin || helpers.unpin,
|
||||
unpinMessage: options.unpinMessage || helpers.unpinMessage,
|
||||
updateBotVoiceState: options.updateBotVoiceState || helpers.updateBotVoiceState,
|
||||
updateStageInstance: options.updateStageInstance || helpers.updateStageInstance,
|
||||
|
||||
@@ -3,12 +3,9 @@ import type { Bot } from "../../bot.ts";
|
||||
/** Delete the channel permission overwrites for a user or role in this channel. Requires `MANAGE_ROLES` permission. */
|
||||
export async function deleteChannelOverwrite(
|
||||
bot: Bot,
|
||||
guildId: bigint,
|
||||
channelId: bigint,
|
||||
overwriteId: bigint
|
||||
): Promise<undefined> {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
|
||||
@@ -4,13 +4,10 @@ import type { Bot } from "../../bot.ts";
|
||||
/** Edit the channel permission overwrites for a user or role in this channel. Requires `MANAGE_ROLES` permission. */
|
||||
export async function editChannelOverwrite(
|
||||
bot: Bot,
|
||||
guildId: bigint,
|
||||
channelId: bigint,
|
||||
overwriteId: bigint,
|
||||
options: Omit<Overwrite, "id">
|
||||
): Promise<undefined> {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"put",
|
||||
|
||||
@@ -3,8 +3,6 @@ import type { Bot } from "../../bot.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(bot: Bot, sourceChannelId: bigint, targetChannelId: bigint) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, targetChannelId, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const data = await bot.rest.runMethod<FollowedChannel>(
|
||||
bot.rest,
|
||||
"post",
|
||||
|
||||
@@ -4,8 +4,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Gets the webhooks for this channel. Requires MANAGE_WEBHOOKS */
|
||||
export async function getChannelWebhooks(bot: Bot, channelId: bigint) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const result = await bot.rest.runMethod<Webhook[]>(
|
||||
bot.rest,
|
||||
"get",
|
||||
|
||||
@@ -15,7 +15,6 @@ export async function getArchivedThreads(
|
||||
) {
|
||||
// const permissions = new Set<PermissionStrings>(["READ_MESSAGE_HISTORY"]);
|
||||
// if (options?.type === "private") permissions.add("MANAGE_THREADS");
|
||||
// await bot.utils.requireBotChannelPermissions(bot, channelId, [...permissions]);
|
||||
// // TODO: pagination
|
||||
// const result = (await bot.rest.runMethod(
|
||||
// bot.rest,
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import type { AddGuildDiscoverySubcategory } from "../../types/discovery/add_guild_discovery_subcategory.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Add a discovery subcategory to the guild. Requires the `MANAGE_GUILD` permission. */
|
||||
export async function addDiscoverySubcategory(bot: Bot, guildId: bigint, categoryId: number) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<AddGuildDiscoverySubcategory>(
|
||||
bot.rest,
|
||||
"post",
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { DiscoveryMetadata } from "../../types/discovery/discovery_metadata.ts";
|
||||
import type { ModifyGuildDiscoveryMetadata } from "../../types/discovery/modify_guild_discovery_metadata.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Modify the discovery metadata for the guild. Requires the MANAGE_GUILD permission. Returns the updated discovery metadata object on success. */
|
||||
export async function editDiscovery(bot: Bot, guildId: bigint, data: ModifyGuildDiscoveryMetadata) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<DiscoveryMetadata>(
|
||||
bot.rest,
|
||||
"patch",
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import type { DiscoveryMetadata } from "../../types/discovery/discovery_metadata.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Returns the discovery metadata object for the guild. Requires the `MANAGE_GUILD` permission. */
|
||||
export async function getDiscovery(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<DiscoveryMetadata>(
|
||||
bot.rest,
|
||||
"get",
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Removes a discovery subcategory from the guild. Requires the MANAGE_GUILD permission. Returns a 204 No Content on success. */
|
||||
export async function removeDiscoverySubcategory(bot: Bot, guildId: bigint, categoryId: number) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
|
||||
@@ -4,8 +4,6 @@ import type { Bot } from "../../bot.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(bot: Bot, guildId: bigint, options: CreateGuildEmoji) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]);
|
||||
|
||||
if (options.image && !options.image.startsWith("data:image/")) {
|
||||
options.image = await bot.utils.urlToBase64(options.image);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Delete the given emoji. Requires the MANAGE_EMOJIS permission. Returns 204 No Content on success. */
|
||||
export async function deleteEmoji(bot: Bot, guildId: bigint, id: bigint, reason?: string) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(bot.rest, "delete", bot.constants.endpoints.GUILD_EMOJI(guildId, id), {
|
||||
reason,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,5 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Modify the given emoji. Requires the MANAGE_EMOJIS permission. */
|
||||
export async function editEmoji(bot: Bot, guildId: bigint, id: bigint, options: ModifyGuildEmoji) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]);
|
||||
|
||||
return await bot.rest.runMethod<Emoji>(bot.rest, "patch", bot.constants.endpoints.GUILD_EMOJI(guildId, id), options);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Modify a guild widget object for the guild. Requires the MANAGE_GUILD permission. */
|
||||
export async function editWidget(bot: Bot, guildId: bigint, enabled: boolean, channelId?: string | null) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<GuildWidget>(bot.rest, "patch", bot.constants.endpoints.GUILD_WIDGET(guildId), {
|
||||
enabled,
|
||||
channel_id: channelId,
|
||||
|
||||
@@ -4,8 +4,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Returns the audit logs for the guild. Requires VIEW AUDIT LOGS permission */
|
||||
export async function getAuditLogs(bot: Bot, guildId: bigint, options?: GetGuildAuditLog) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["VIEW_AUDIT_LOG"]);
|
||||
|
||||
if (options?.userId) options.userId = options.userId.toString();
|
||||
if (options?.before) options.before = options.before.toString();
|
||||
if (options?.limit) options.limit = options.limit >= 1 && options.limit <= 100 ? options.limit : 50;
|
||||
|
||||
@@ -3,8 +3,6 @@ import type { Bot } from "../../bot.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(bot: Bot, guildId: bigint, memberId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
|
||||
|
||||
const result = await bot.rest.runMethod<Ban>(bot.rest, "get", bot.constants.endpoints.GUILD_BAN(guildId, memberId));
|
||||
|
||||
return {
|
||||
|
||||
@@ -4,8 +4,6 @@ import { Collection } from "../../util/collection.ts";
|
||||
|
||||
/** Returns a list of ban objects for the users banned from this guild. Requires the BAN_MEMBERS permission. */
|
||||
export async function getBans(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
|
||||
|
||||
const results = await bot.rest.runMethod<Ban[]>(bot.rest, "get", bot.constants.endpoints.GUILD_BANS(guildId));
|
||||
|
||||
return new Collection<bigint, Ban>(results.map((res) => [bot.transformers.snowflake(res.user.id), res]));
|
||||
|
||||
@@ -8,8 +8,6 @@ export async function getPruneCount(bot: Bot, guildId: bigint, options?: GetGuil
|
||||
throw new Error(bot.constants.Errors.PRUNE_MAX_DAYS);
|
||||
}
|
||||
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]);
|
||||
|
||||
const result = await bot.rest.runMethod(
|
||||
bot.rest,
|
||||
"get",
|
||||
|
||||
@@ -3,7 +3,5 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Returns the guild widget object. Requires the MANAGE_GUILD permission. */
|
||||
export async function getWidgetSettings(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<GuildWidget>(bot.rest, "get", bot.constants.endpoints.GUILD_WIDGET(guildId));
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Delete the attached integration object for the guild with this id. Requires MANAGE_GUILD permission. */
|
||||
export async function deleteIntegration(bot: Bot, guildId: bigint, id: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
|
||||
@@ -3,7 +3,5 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Returns a list of integrations for the guild. Requires the MANAGE_GUILD permission. */
|
||||
export async function getIntegrations(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<Integration>(bot.rest, "get", bot.constants.endpoints.GUILD_INTEGRATIONS(guildId));
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Creates a new invite for this channel. Requires CREATE_INSTANT_INVITE */
|
||||
export async function createInvite(bot: Bot, channelId: bigint, options: CreateChannelInvite = {}) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["CREATE_INSTANT_INVITE"]);
|
||||
|
||||
if (options.maxAge && (options.maxAge < 0 || options.maxAge > 604800)) {
|
||||
throw new Error(Errors.INVITE_MAX_AGE_INVALID);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Gets the invites for this channel. Requires MANAGE_CHANNEL */
|
||||
export async function getChannelInvites(bot: Bot, channelId: bigint) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_CHANNELS"]);
|
||||
|
||||
const result = await bot.rest.runMethod<InviteMetadata[]>(
|
||||
bot.rest,
|
||||
"get",
|
||||
|
||||
@@ -5,8 +5,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Get all the invites for this guild. Requires MANAGE_GUILD permission */
|
||||
export async function getInvites(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
const result = await bot.rest.runMethod<InviteMetadata[]>(
|
||||
bot.rest,
|
||||
"get",
|
||||
|
||||
@@ -3,8 +3,6 @@ import type { Bot } from "../../bot.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(bot: Bot, guildId: bigint, id: bigint, options?: CreateGuildBan) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"put",
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Edit the nickname of the bot in this guild */
|
||||
export async function editBotNickname(bot: Bot, guildId: bigint, nickname: string | null) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["CHANGE_NICKNAME"]);
|
||||
|
||||
const response = await bot.rest.runMethod<{ nick: string }>(
|
||||
bot.rest,
|
||||
"patch",
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { Bot } from "../../bot.ts";
|
||||
|
||||
/** Kick a member from the server */
|
||||
export async function kick(bot: Bot, guildId: bigint, memberId: bigint, reason?: string) {
|
||||
const botsHighestRole = await bot.utils.highestRole(bot, guildId, bot.id);
|
||||
const membersHighestRole = await bot.utils.highestRole(bot, guildId, memberId);
|
||||
if (botsHighestRole && membersHighestRole && botsHighestRole.position <= membersHighestRole.position) {
|
||||
throw new Error(bot.constants.Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]);
|
||||
|
||||
export async function kickMember(bot: Bot, guildId: bigint, memberId: bigint, reason?: string) {
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
@@ -16,6 +9,3 @@ export async function kick(bot: Bot, guildId: bigint, memberId: bigint, reason?:
|
||||
{ reason }
|
||||
);
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { kick as kickMember };
|
||||
|
||||
@@ -10,8 +10,6 @@ export async function pruneMembers(bot: Bot, guildId: bigint, options: BeginGuil
|
||||
if (options.days && options.days < 1) throw new Error(bot.constants.Errors.PRUNE_MIN_DAYS);
|
||||
if (options.days && options.days > 30) throw new Error(bot.constants.Errors.PRUNE_MAX_DAYS);
|
||||
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]);
|
||||
|
||||
const result = await bot.rest.runMethod<{ pruned: number }>(
|
||||
bot.rest,
|
||||
"post",
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Remove the ban for a user. Requires BAN_MEMBERS permission */
|
||||
export async function unban(bot: Bot, guildId: bigint, id: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]);
|
||||
|
||||
export async function unbanMember(bot: Bot, guildId: bigint, id: bigint) {
|
||||
return await bot.rest.runMethod<undefined>(bot.rest, "delete", bot.constants.endpoints.GUILD_BAN(guildId, id));
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { unban as unbanMember };
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.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(bot: Bot, channelId: bigint, messageId: bigint, reaction: string) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["ADD_REACTIONS", "READ_MESSAGE_HISTORY"]);
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Delete messages from the channel. 2-100. Requires the MANAGE_MESSAGES permission */
|
||||
export async function deleteMessages(bot: Bot, channelId: bigint, ids: bigint[], reason?: string) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_MESSAGES"]);
|
||||
|
||||
if (ids.length < 2) {
|
||||
throw new Error(bot.constants.Errors.DELETE_MESSAGES_MIN);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ export async function getMessages(
|
||||
channelId: bigint,
|
||||
options?: GetMessagesAfter | GetMessagesBefore | GetMessagesAround | GetMessagesLimit
|
||||
) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["VIEW_CHANNEL", "READ_MESSAGE_HISTORY"]);
|
||||
|
||||
if (options?.limit && (options.limit < 0 || options.limit > 100)) {
|
||||
throw new Error(bot.constants.Errors.INVALID_GET_MESSAGES_LIMIT);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Removes all reactions for all emojis on this message. */
|
||||
export async function removeAllReactions(bot: Bot, channelId: bigint, messageId: bigint) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_MESSAGES"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
|
||||
@@ -8,10 +8,6 @@ export async function removeReaction(
|
||||
reaction: string,
|
||||
options?: { userId?: bigint }
|
||||
) {
|
||||
if (options?.userId) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_MESSAGES"]);
|
||||
}
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
import type { Bot } from "../../bot.ts";
|
||||
|
||||
export async function removeReactionEmoji(bot: Bot, channelId: bigint, messageId: bigint, reaction: string) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_MESSAGES"]);
|
||||
|
||||
if (reaction.startsWith("<:")) {
|
||||
reaction = reaction.substring(2, reaction.length - 1);
|
||||
} else if (reaction.startsWith("<a:")) {
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
/** Unpin a message in a channel. Requires MANAGE_MESSAGES. */
|
||||
import type { Bot } from "../../bot.ts";
|
||||
|
||||
export async function unpin(bot: Bot, channelId: bigint, messageId: bigint): Promise<undefined> {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_MESSAGES"]);
|
||||
|
||||
export async function unpinMessage(bot: Bot, channelId: bigint, messageId: bigint): Promise<undefined> {
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
bot.constants.endpoints.CHANNEL_PIN(channelId, messageId)
|
||||
);
|
||||
}
|
||||
|
||||
// aliases
|
||||
export { unpin as unpinMessage };
|
||||
|
||||
@@ -74,11 +74,11 @@ import { editMember } from "./members/edit_member.ts";
|
||||
import { fetchMembers } from "./members/fetch_members.ts";
|
||||
import { getMember } from "./members/get_member.ts";
|
||||
import { getMembers } from "./members/get_members.ts";
|
||||
import { kick, kickMember } from "./members/kick_member.ts";
|
||||
import { kickMember } from "./members/kick_member.ts";
|
||||
import { moveMember } from "./members/move_member.ts";
|
||||
import { pruneMembers } from "./members/prune_members.ts";
|
||||
import { getDmChannel } from "./members/send_direct_message.ts";
|
||||
import { unban, unbanMember } from "./members/unban_member.ts";
|
||||
import { unbanMember } from "./members/unban_member.ts";
|
||||
import { addReaction } from "./messages/add_reaction.ts";
|
||||
import { addReactions } from "./messages/add_reactions.ts";
|
||||
import { deleteMessage } from "./messages/delete_message.ts";
|
||||
@@ -94,7 +94,7 @@ import { removeReaction } from "./messages/remove_reaction.ts";
|
||||
import { removeReactionEmoji } from "./messages/remove_reaction_emoji.ts";
|
||||
import { sendMessage } from "./messages/send_message.ts";
|
||||
import { suppressEmbeds } from "./messages/suppress_embeds.ts";
|
||||
import { unpin, unpinMessage } from "./messages/unpin_message.ts";
|
||||
import { unpinMessage } from "./messages/unpin_message.ts";
|
||||
import { editBotProfile } from "./misc/edit_bot_profile.ts";
|
||||
import { editBotStatus } from "./misc/edit_bot_status.ts";
|
||||
import { getGatewayBot } from "./misc/get_gateway_bot.ts";
|
||||
@@ -265,7 +265,6 @@ export {
|
||||
isButton,
|
||||
isSelectMenu,
|
||||
isSlashCommand,
|
||||
kick,
|
||||
kickMember,
|
||||
leaveGuild,
|
||||
moveMember,
|
||||
@@ -284,9 +283,7 @@ export {
|
||||
startTyping,
|
||||
swapChannels,
|
||||
syncGuildTemplate,
|
||||
unban,
|
||||
unbanMember,
|
||||
unpin,
|
||||
unpinMessage,
|
||||
updateBotVoiceState,
|
||||
updateStageInstance,
|
||||
|
||||
@@ -2,13 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Add a role to the member */
|
||||
export async function addRole(bot: Bot, guildId: bigint, memberId: bigint, roleId: bigint, reason?: string) {
|
||||
const isHigherRolePosition = await bot.utils.isHigherPosition(bot, guildId, bot.id, roleId);
|
||||
if (!isHigherRolePosition) {
|
||||
throw new Error(bot.constants.Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"put",
|
||||
|
||||
@@ -4,22 +4,16 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Create a new role for the guild. Requires the MANAGE_ROLES permission. */
|
||||
export async function createRole(bot: Bot, guildId: bigint, options: CreateGuildRole, reason?: string) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
const result = await bot.rest.runMethod<Role>(bot.rest, "post", bot.constants.endpoints.GUILD_ROLES(guildId), {
|
||||
name: options.name,
|
||||
color: options.color,
|
||||
hoist: options.hoist,
|
||||
mentionable: options.mentionable,
|
||||
permissions: bot.utils.calculateBits(options?.permissions || []),
|
||||
reason,
|
||||
});
|
||||
|
||||
const result = await bot.rest.runMethod<Role>(bot.rest,
|
||||
"post",
|
||||
bot.constants.endpoints.GUILD_ROLES(guildId),
|
||||
{
|
||||
name: options.name,
|
||||
color: options.color,
|
||||
hoist: options.hoist,
|
||||
mentionable: options.mentionable,
|
||||
permissions: bot.utils.calculateBits(options?.permissions || []),
|
||||
reason,
|
||||
}
|
||||
);
|
||||
|
||||
const role = await bot.transformers.role(bot, {
|
||||
const role = bot.transformers.role(bot, {
|
||||
role: result,
|
||||
guildId,
|
||||
});
|
||||
|
||||
@@ -2,7 +2,5 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Delete a guild role. Requires the MANAGE_ROLES permission. */
|
||||
export async function deleteRole(bot: Bot, guildId: bigint, id: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(bot.rest, "delete", bot.constants.endpoints.GUILD_ROLE(guildId, id));
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { CreateGuildRole } from "../../types/guilds/create_guild_role.ts";
|
||||
import type { Role } from "../../types/permissions/role.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Edit a guild role. Requires the MANAGE_ROLES permission. */
|
||||
export async function editRole(bot: Bot, guildId: bigint, id: bigint, options: CreateGuildRole) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
const result = await bot.rest.runMethod<Role>(
|
||||
bot.rest,
|
||||
"patch",
|
||||
|
||||
@@ -8,8 +8,6 @@ import { DiscordenoRole } from "../../transformers/role.ts";
|
||||
* ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your roles will be cached in your guild.**
|
||||
*/
|
||||
export async function getRoles(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
const result = await bot.rest.runMethod<Role[]>(bot.rest, "get", bot.constants.endpoints.GUILD_ROLES(guildId));
|
||||
|
||||
const roleStructures = result.map((role) => bot.transformers.role(bot, { role, guildId }));
|
||||
|
||||
@@ -2,13 +2,6 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Remove a role from the member */
|
||||
export async function removeRole(bot: Bot, guildId: bigint, memberId: bigint, roleId: bigint, reason?: string) {
|
||||
const isHigherRolePosition = await bot.utils.isHigherPosition(bot, guildId, bot.id, roleId);
|
||||
if (!isHigherRolePosition) {
|
||||
throw new Error(bot.constants.Errors.BOTS_HIGHEST_ROLE_TOO_LOW);
|
||||
}
|
||||
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { Template } from "../../types/templates/template.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import { User } from "../../types/users/user.ts";
|
||||
import { Guild } from "../../types/guilds/guild.ts";
|
||||
|
||||
/**
|
||||
* Creates a template for the guild.
|
||||
@@ -11,8 +9,6 @@ import { Guild } from "../../types/guilds/guild.ts";
|
||||
* @param data
|
||||
*/
|
||||
export async function createGuildTemplate(bot: Bot, guildId: bigint, data: Template) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
if (data.name.length < 1 || data.name.length > 100) {
|
||||
throw new Error("The name can only be in between 1-100 characters.");
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import type { Bot } from "../../bot.ts";
|
||||
* Requires the `MANAGE_GUILD` permission.
|
||||
*/
|
||||
export async function deleteGuildTemplate(bot: Bot, guildId: bigint, templateCode: string) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<Template>(
|
||||
bot.rest,
|
||||
"delete",
|
||||
|
||||
@@ -7,8 +7,6 @@ import type { Bot } from "../../bot.ts";
|
||||
* Requires the `MANAGE_GUILD` permission.
|
||||
*/
|
||||
export async function editGuildTemplate(bot: Bot, guildId: bigint, templateCode: string, data: ModifyGuildTemplate) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
if (data.name?.length && (data.name.length < 1 || data.name.length > 100)) {
|
||||
throw new Error("The name can only be in between 1-100 characters.");
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import type { Bot } from "../../bot.ts";
|
||||
* Requires the `MANAGE_GUILD` permission.
|
||||
*/
|
||||
export async function getGuildTemplates(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
const templates = await bot.rest.runMethod<Template[]>(bot.rest, "get", bot.constants.endpoints.GUILD_TEMPLATES(guildId));
|
||||
|
||||
return new Collection(templates.map((template) => [template.code, template]));
|
||||
|
||||
@@ -6,8 +6,6 @@ import type { Bot } from "../../bot.ts";
|
||||
* Requires the `MANAGE_GUILD` permission.
|
||||
*/
|
||||
export async function syncGuildTemplate(bot: Bot, guildId: bigint, templateCode: string) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
return await bot.rest.runMethod<Template>(
|
||||
bot.rest,
|
||||
"put",
|
||||
|
||||
@@ -10,8 +10,6 @@ export async function connectToVoiceChannel(
|
||||
channelId: bigint,
|
||||
options?: AtLeastOne<Omit<UpdateVoiceState, "guildId" | "channelId">>
|
||||
) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["CONNECT", "VIEW_CHANNEL"]);
|
||||
|
||||
bot.gateway.sendShardMessage(bot.gateway, bot.utils.calculateShardId(bot.gateway, guildId), {
|
||||
op: DiscordGatewayOpcodes.VoiceStateUpdate,
|
||||
d: {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import type { CreateWebhook } from "../../types/webhooks/create_webhook.ts";
|
||||
import type { Webhook } from "../../types/webhooks/webhook.ts";
|
||||
import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/**
|
||||
* Create a new webhook. Requires the MANAGE_WEBHOOKS permission. Returns a webhook object on success. Webhook names follow our naming restrictions that can be found in our Usernames and Nicknames documentation, with the following additional stipulations:
|
||||
@@ -9,8 +8,6 @@ import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
* Webhook names cannot be: 'clyde'
|
||||
*/
|
||||
export async function createWebhook(bot: Bot, channelId: bigint, options: CreateWebhook) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
if (
|
||||
// Specific usernames that discord does not allow
|
||||
options.name === "clyde" ||
|
||||
|
||||
@@ -2,7 +2,5 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Delete a webhook permanently. Requires the `MANAGE_WEBHOOKS` permission. Returns a undefined on success */
|
||||
export async function deleteWebhook(bot: Bot, channelId: bigint, webhookId: bigint) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
return await bot.rest.runMethod<undefined>(bot.rest, "delete", bot.constants.endpoints.WEBHOOK_ID(webhookId));
|
||||
}
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
import type { ModifyWebhook } from "../../types/webhooks/modify_webhook.ts";
|
||||
import type { Webhook } from "../../types/webhooks/webhook.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Edit a webhook. Requires the `MANAGE_WEBHOOKS` permission. Returns the updated webhook object on success. */
|
||||
export async function editWebhook(bot: Bot, channelId: bigint, webhookId: bigint, options: ModifyWebhook) {
|
||||
await bot.utils.requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
return await bot.rest.runMethod<Webhook>(
|
||||
bot.rest,
|
||||
"patch",
|
||||
bot.constants.endpoints.WEBHOOK_ID(webhookId),
|
||||
{
|
||||
...options,
|
||||
channel_id: options.channelId,
|
||||
}
|
||||
);
|
||||
return await bot.rest.runMethod<Webhook>(bot.rest, "patch", bot.constants.endpoints.WEBHOOK_ID(webhookId), {
|
||||
...options,
|
||||
channel_id: options.channelId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
/** Returns a list of guild webhooks objects. Requires the MANAGE_WEBHOOKs permission. */
|
||||
export async function getWebhooks(bot: Bot, guildId: bigint) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_WEBHOOKS"]);
|
||||
|
||||
const result = await bot.rest.runMethod<Webhook[]>(
|
||||
bot.rest,
|
||||
"get",
|
||||
|
||||
@@ -3,6 +3,5 @@ export * from "./calculate_shard_id.ts";
|
||||
export * from "./collection.ts";
|
||||
export * from "./constants.ts";
|
||||
export * from "./hash.ts";
|
||||
export * from "./permissions.ts";
|
||||
export * from "./utils.ts";
|
||||
export * from "./validate_length.ts";
|
||||
|
||||
@@ -1,377 +0,0 @@
|
||||
import type { Bot } from "../bot.ts";
|
||||
import { DiscordenoChannel, separate } from "../transformers/channel.ts";
|
||||
import type { DiscordenoGuild } from "../transformers/guild.ts";
|
||||
import type { DiscordenoMember } from "../transformers/member.ts";
|
||||
import { DiscordenoRole } from "../transformers/role.ts";
|
||||
import { Overwrite } from "../types/channels/overwrite.ts";
|
||||
import { Errors } from "../types/discordeno/errors.ts";
|
||||
import { DiscordBitwisePermissionFlags } from "../types/permissions/bitwise_permission_flags.ts";
|
||||
import type { PermissionStrings } from "../types/permissions/permission_strings.ts";
|
||||
|
||||
export async function getCached(
|
||||
bot: Bot,
|
||||
table: "guilds",
|
||||
key: bigint | DiscordenoGuild
|
||||
): Promise<DiscordenoGuild | undefined>;
|
||||
export async function getCached(
|
||||
bot: Bot,
|
||||
table: "channels",
|
||||
key: bigint | DiscordenoChannel
|
||||
): Promise<DiscordenoChannel | undefined>;
|
||||
export async function getCached(
|
||||
bot: Bot,
|
||||
table: "members",
|
||||
key: bigint | DiscordenoMember
|
||||
): Promise<DiscordenoMember | undefined>;
|
||||
export async function getCached(
|
||||
bot: Bot,
|
||||
table: "guilds" | "channels" | "members",
|
||||
key: bigint | DiscordenoGuild | DiscordenoChannel | DiscordenoMember
|
||||
) {
|
||||
const cached = typeof key === "bigint" ? await bot.cache[table].get(key) : key;
|
||||
|
||||
return typeof cached === "bigint" ? undefined : cached;
|
||||
}
|
||||
|
||||
/** Calculates the permissions this member has in the given guild */
|
||||
export async function calculateBasePermissions(
|
||||
bot: Bot,
|
||||
guildOrId: bigint | DiscordenoGuild,
|
||||
memberOrId: bigint | DiscordenoMember
|
||||
) {
|
||||
const guild = await bot.utils.getCached(bot, "guilds", guildOrId);
|
||||
const member = await bot.utils.getCached(bot, "members", memberOrId);
|
||||
|
||||
if (!guild || !member) return 8n;
|
||||
|
||||
let permissions = 0n;
|
||||
// Calculate the role permissions bits, @everyone role is not in memberRoleIds so we need to pass guildId manualy
|
||||
permissions |=
|
||||
[...member.roles, guild.id]
|
||||
.map((id) => guild.roles.get(id)?.permissions)
|
||||
// Removes any edge case undefined
|
||||
.filter((perm) => perm)
|
||||
.reduce((bits, perms) => {
|
||||
bits! |= perms!;
|
||||
return bits;
|
||||
}, 0n) || 0n;
|
||||
|
||||
// If the memberId is equal to the guild ownerId he automatically has every permission so we add ADMINISTRATOR permission
|
||||
if (guild.ownerId === member.id) permissions |= 8n;
|
||||
// Return the members permission bits as a string
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/** Calculates the permissions this member has for the given Channel */
|
||||
export async function calculateChannelOverwrites(
|
||||
bot: Bot,
|
||||
channelOrId: bigint | DiscordenoChannel,
|
||||
memberOrId: bigint | DiscordenoMember
|
||||
) {
|
||||
const channel = await bot.utils.getCached(bot, "channels", channelOrId);
|
||||
|
||||
// This is a DM channel so return ADMINISTRATOR permission
|
||||
if (!channel?.guildId) return 8n;
|
||||
|
||||
const member = await bot.utils.getCached(bot, "members", memberOrId);
|
||||
|
||||
if (!channel || !member) return 8n;
|
||||
|
||||
// Get all the role permissions this member already has
|
||||
let permissions = await bot.utils.calculateBasePermissions(bot, channel.guildId, member);
|
||||
|
||||
// First calculate @everyone overwrites since these have the lowest priority
|
||||
const overwriteEveryone = channel.permissionOverwrites?.find((overwrite) => {
|
||||
const [_, id] = separate(overwrite);
|
||||
return id === channel.guildId;
|
||||
});
|
||||
if (overwriteEveryone) {
|
||||
const [type, id, allow, deny] = separate(overwriteEveryone);
|
||||
// First remove denied permissions since denied < allowed
|
||||
permissions &= ~deny;
|
||||
permissions |= allow;
|
||||
}
|
||||
|
||||
const overwrites = channel.permissionOverwrites;
|
||||
|
||||
// In order to calculate the role permissions correctly we need to temporarily save the allowed and denied permissions
|
||||
let allow = 0n;
|
||||
let deny = 0n;
|
||||
const memberRoles = member.roles || [];
|
||||
// Second calculate members role overwrites since these have middle priority
|
||||
for (const overwrite of overwrites || []) {
|
||||
const [type, id, allowBits, denyBits] = separate(overwrite);
|
||||
|
||||
if (!memberRoles.includes(id)) continue;
|
||||
|
||||
deny |= denyBits;
|
||||
allow |= allowBits;
|
||||
}
|
||||
// After role overwrite calculate save allowed permissions first we remove denied permissions since "denied < allowed"
|
||||
permissions &= ~deny;
|
||||
permissions |= allow;
|
||||
|
||||
// Third calculate member specific overwrites since these have the highest priority
|
||||
const overwriteMember = overwrites?.find((overwrite) => {
|
||||
const [_, id] = separate(overwrite);
|
||||
return id === member.id;
|
||||
});
|
||||
if (overwriteMember) {
|
||||
const [type, id, allowBits, denyBits] = separate(overwriteMember);
|
||||
|
||||
permissions &= ~denyBits;
|
||||
permissions |= allowBits;
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/** Checks if the given permission bits are matching the given permissions. `ADMINISTRATOR` always returns `true` */
|
||||
export function validatePermissions(permissionBits: bigint, permissions: PermissionStrings[]) {
|
||||
if (permissionBits & 8n) return true;
|
||||
|
||||
return permissions.every(
|
||||
(permission) =>
|
||||
// Check if permission is in permissionBits
|
||||
permissionBits & BigInt(DiscordBitwisePermissionFlags[permission])
|
||||
);
|
||||
}
|
||||
|
||||
/** Checks if the given member has these permissions in the given guild */
|
||||
export async function hasGuildPermissions(
|
||||
bot: Bot,
|
||||
guild: bigint | DiscordenoGuild,
|
||||
member: bigint | DiscordenoMember,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// First we need the role permission bits this member has
|
||||
const basePermissions = await bot.utils.calculateBasePermissions(bot, guild, member);
|
||||
// Second use the validatePermissions function to check if the member has every permission
|
||||
return bot.utils.validatePermissions(basePermissions, permissions);
|
||||
}
|
||||
|
||||
/** Checks if the bot has these permissions in the given guild */
|
||||
export function botHasGuildPermissions(bot: Bot, guild: bigint | DiscordenoGuild, permissions: PermissionStrings[]) {
|
||||
// Since Bot is a normal member we can use the hasRolePermissions() function
|
||||
return bot.utils.hasGuildPermissions(bot, guild, bot.id, permissions);
|
||||
}
|
||||
|
||||
/** Checks if the given member has these permissions for the given channel */
|
||||
export async function hasChannelPermissions(
|
||||
bot: Bot,
|
||||
channel: bigint | DiscordenoChannel,
|
||||
member: bigint | DiscordenoMember,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// First we need the overwrite bits this member has
|
||||
const channelOverwrites = await bot.utils.calculateChannelOverwrites(bot, channel, member);
|
||||
// Second use the validatePermissions function to check if the member has every permission
|
||||
return bot.utils.validatePermissions(channelOverwrites, permissions);
|
||||
}
|
||||
|
||||
/** Checks if the bot has these permissions f0r the given channel */
|
||||
export function botHasChannelPermissions(
|
||||
bot: Bot,
|
||||
channel: bigint | DiscordenoChannel,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// Since Bot is a normal member we can use the hasRolePermissions() function
|
||||
return bot.utils.hasChannelPermissions(bot, channel, bot.id, permissions);
|
||||
}
|
||||
|
||||
/** Returns the permissions that are not in the given permissionBits */
|
||||
export function missingPermissions(permissionBits: bigint, permissions: PermissionStrings[]) {
|
||||
if (permissionBits & 8n) return [];
|
||||
|
||||
return permissions.filter((permission) => !(permissionBits & BigInt(DiscordBitwisePermissionFlags[permission])));
|
||||
}
|
||||
|
||||
/** Get the missing Guild permissions this member has */
|
||||
export async function getMissingGuildPermissions(
|
||||
bot: Bot,
|
||||
guild: bigint | DiscordenoGuild,
|
||||
member: bigint | DiscordenoMember,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// First we need the role permission bits this member has
|
||||
const permissionBits = await bot.utils.calculateBasePermissions(bot, guild, member);
|
||||
// Second return the members missing permissions
|
||||
return missingPermissions(permissionBits, permissions);
|
||||
}
|
||||
|
||||
/** Get the missing Channel permissions this member has */
|
||||
export async function getMissingChannelPermissions(
|
||||
bot: Bot,
|
||||
channel: bigint | DiscordenoChannel,
|
||||
member: bigint | DiscordenoMember,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// First we need the role permissino bits this member has
|
||||
const permissionBits = await bot.utils.calculateChannelOverwrites(bot, channel, member);
|
||||
// Second returnn the members missing permissions
|
||||
return missingPermissions(permissionBits, permissions);
|
||||
}
|
||||
|
||||
/** Throws an error if this member has not all of the given permissions */
|
||||
export async function requireGuildPermissions(
|
||||
bot: Bot,
|
||||
guild: bigint | DiscordenoGuild,
|
||||
member: bigint | DiscordenoMember,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
const missing = await bot.utils.getMissingGuildPermissions(bot, guild, member, permissions);
|
||||
if (missing.length) {
|
||||
// If the member is missing a permission throw an Error
|
||||
throw new Error(`Missing Permissions: ${missing.join(" & ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Throws an error if the bot does not have all permissions */
|
||||
export function requireBotGuildPermissions(
|
||||
bot: Bot,
|
||||
guild: bigint | DiscordenoGuild,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// Since Bot is a normal member we can use the throwOnMissingGuildPermission() function
|
||||
return bot.utils.requireGuildPermissions(bot, guild, bot.id, permissions);
|
||||
}
|
||||
|
||||
/** Throws an error if this member has not all of the given permissions */
|
||||
export async function requireChannelPermissions(
|
||||
bot: Bot,
|
||||
channel: bigint | DiscordenoChannel,
|
||||
member: bigint | DiscordenoMember,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
const missing = await bot.utils.getMissingChannelPermissions(bot, channel, member, permissions);
|
||||
if (missing.length) {
|
||||
// If the member is missing a permission throw an Error
|
||||
throw new Error(`Missing Permissions: ${missing.join(" & ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Throws an error if the bot has not all of the given channel permissions */
|
||||
export function requireBotChannelPermissions(
|
||||
bot: Bot,
|
||||
channel: bigint | DiscordenoChannel,
|
||||
permissions: PermissionStrings[]
|
||||
) {
|
||||
// Since Bot is a normal member we can use the throwOnMissingChannelPermission() function
|
||||
return bot.utils.requireChannelPermissions(bot, channel, bot.id, permissions);
|
||||
}
|
||||
|
||||
/** This function converts a bitwise string to permission strings */
|
||||
export function calculatePermissions(permissionBits: bigint) {
|
||||
return Object.keys(DiscordBitwisePermissionFlags).filter((permission) => {
|
||||
// Since Object.keys() not only returns the permission names but also the bit values we need to return false if it is a Number
|
||||
if (Number(permission)) return false;
|
||||
// Check if permissionBits has this permission
|
||||
return permissionBits & BigInt(DiscordBitwisePermissionFlags[permission as PermissionStrings]);
|
||||
}) as PermissionStrings[];
|
||||
}
|
||||
|
||||
/** This function converts an array of permissions into the bitwise string. */
|
||||
export function calculateBits(permissions: PermissionStrings[]) {
|
||||
return permissions
|
||||
.reduce((bits, perm) => {
|
||||
bits |= BigInt(DiscordBitwisePermissionFlags[perm]);
|
||||
return bits;
|
||||
}, 0n)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/** Internal function to check if the bot has the permissions to set these overwrites */
|
||||
export async function requireOverwritePermissions(
|
||||
bot: Bot,
|
||||
guildOrId: bigint | DiscordenoGuild,
|
||||
overwrites: Overwrite[]
|
||||
) {
|
||||
let requiredPerms: Set<PermissionStrings> = new Set(["MANAGE_CHANNELS"]);
|
||||
|
||||
overwrites?.forEach((overwrite) => {
|
||||
if (overwrite.allow) overwrite.allow.forEach(requiredPerms.add, requiredPerms);
|
||||
if (overwrite.deny) overwrite.deny.forEach(requiredPerms.add, requiredPerms);
|
||||
});
|
||||
|
||||
// MANAGE_ROLES permission can only be set by administrators
|
||||
if (requiredPerms.has("MANAGE_ROLES")) {
|
||||
requiredPerms = new Set<PermissionStrings>(["ADMINISTRATOR"]);
|
||||
}
|
||||
|
||||
await bot.utils.requireGuildPermissions(bot, guildOrId, bot.id, [...requiredPerms]);
|
||||
}
|
||||
|
||||
/** Gets the highest role from the member in this guild */
|
||||
export async function highestRole(
|
||||
bot: Bot,
|
||||
guildOrId: bigint | DiscordenoGuild,
|
||||
memberOrId: bigint | DiscordenoMember
|
||||
) {
|
||||
const guild = await bot.utils.getCached(bot, "guilds", guildOrId);
|
||||
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
|
||||
// Get the roles from the member
|
||||
const memberRoles = (await bot.utils.getCached(bot, "members", memberOrId))?.roles;
|
||||
// This member has no roles so the highest one is the @everyone role
|
||||
if (!memberRoles) return guild.roles.get(guild.id)!;
|
||||
|
||||
let memberHighestRole: DiscordenoRole | undefined;
|
||||
|
||||
for (const roleId of memberRoles) {
|
||||
const role = guild.roles.get(roleId);
|
||||
// Rare edge case handling if undefined
|
||||
if (!role) continue;
|
||||
|
||||
// If memberHighestRole is still undefined we want to assign the role,
|
||||
// else we want to check if the current role position is higher than the current memberHighestRole
|
||||
if (
|
||||
!memberHighestRole ||
|
||||
memberHighestRole.position < role.position ||
|
||||
memberHighestRole.position === role.position
|
||||
) {
|
||||
memberHighestRole = role;
|
||||
}
|
||||
}
|
||||
|
||||
// The member has at least one role so memberHighestRole must exist
|
||||
return memberHighestRole!;
|
||||
}
|
||||
|
||||
/** Checks if the first role is higher than the second role */
|
||||
export async function higherRolePosition(
|
||||
bot: Bot,
|
||||
guildOrId: bigint | DiscordenoGuild,
|
||||
roleId: bigint,
|
||||
otherRoleId: bigint
|
||||
) {
|
||||
const guild = await bot.utils.getCached(bot, "guilds", guildOrId);
|
||||
|
||||
if (!guild) return true;
|
||||
|
||||
const role = guild.roles.get(roleId);
|
||||
const otherRole = guild.roles.get(otherRoleId);
|
||||
if (!role || !otherRole) throw new Error(Errors.ROLE_NOT_FOUND);
|
||||
|
||||
// Rare edge case handling
|
||||
if (role.position === otherRole.position) {
|
||||
return role.id < otherRole.id;
|
||||
}
|
||||
|
||||
return role.position > otherRole.position;
|
||||
}
|
||||
|
||||
/** Checks if the member has a higher position than the given role */
|
||||
export async function isHigherPosition(
|
||||
bot: Bot,
|
||||
guildOrId: bigint | DiscordenoGuild,
|
||||
memberId: bigint,
|
||||
compareRoleId: bigint
|
||||
) {
|
||||
const guild = await bot.utils.getCached(bot, "guilds", guildOrId);
|
||||
|
||||
if (!guild || guild.ownerId === memberId) return true;
|
||||
|
||||
const memberHighestRole = await bot.utils.highestRole(bot, guild, memberId);
|
||||
return bot.utils.higherRolePosition(bot, guild.id, memberHighestRole.id, compareRoleId);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ export async function deleteChannelOverwriteTests(bot: Bot<Cache>, guildId: bigi
|
||||
true
|
||||
);
|
||||
|
||||
await bot.helpers.deleteChannelOverwrite(channel.guildId, channel.id, bot.id);
|
||||
await bot.helpers.deleteChannelOverwrite(channel.id, bot.id);
|
||||
|
||||
await delayUntil(10000, () => bot.cache.channels.get(channel.id)?.permissionOverwrites?.length === 0);
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import { Bot } from "../../../src/bot.ts";
|
||||
import { assertExists, assertEquals } from "../../deps.ts";
|
||||
|
||||
export async function getVanityURLTests(bot: Bot, guildId: bigint, t: Deno.TestContext) {
|
||||
await bot.utils.requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]);
|
||||
|
||||
// TODO: VANITY IS BROKEN ATM FROM DISCORDS SIDE
|
||||
return;
|
||||
// const fetchedVanityURL = await bot.helpers.getVanityURL(guildId);
|
||||
|
||||
@@ -3,4 +3,3 @@ import "./util/validate_length.ts";
|
||||
import "./util/utils.ts";
|
||||
import "./util/hash.ts";
|
||||
import "./util/format_urls.ts";
|
||||
import "./util/permissions.ts";
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { PermissionStrings } from "../../src/types/permissions/permission_strings.ts";
|
||||
import { calculateBits } from "../../src/util/permissions.ts";
|
||||
import { assertEquals } from "../deps.ts";
|
||||
const permissionStrins: PermissionStrings[] = [
|
||||
"CREATE_INSTANT_INVITE",
|
||||
"KICK_MEMBERS",
|
||||
"BAN_MEMBERS",
|
||||
"ADMINISTRATOR",
|
||||
"MANAGE_CHANNELS",
|
||||
"MANAGE_GUILD",
|
||||
"ADD_REACTIONS",
|
||||
"VIEW_AUDIT_LOG",
|
||||
"PRIORITY_SPEAKER",
|
||||
"STREAM",
|
||||
"VIEW_CHANNEL",
|
||||
"SEND_MESSAGES",
|
||||
"SEND_TTS_MESSAGES",
|
||||
"MANAGE_MESSAGES",
|
||||
"EMBED_LINKS",
|
||||
"ATTACH_FILES",
|
||||
"READ_MESSAGE_HISTORY",
|
||||
"MENTION_EVERYONE",
|
||||
"USE_EXTERNAL_EMOJIS",
|
||||
"VIEW_GUILD_INSIGHTS",
|
||||
"CONNECT",
|
||||
"SPEAK",
|
||||
"MUTE_MEMBERS",
|
||||
"DEAFEN_MEMBERS",
|
||||
"MOVE_MEMBERS",
|
||||
"USE_VAD",
|
||||
"CHANGE_NICKNAME",
|
||||
"MANAGE_NICKNAMES",
|
||||
"MANAGE_ROLES",
|
||||
"MANAGE_WEBHOOKS",
|
||||
"MANAGE_EMOJIS",
|
||||
"USE_SLASH_COMMANDS",
|
||||
"REQUEST_TO_SPEAK",
|
||||
"MANAGE_THREADS",
|
||||
"USE_PUBLIC_THREADS",
|
||||
"USE_PRIVATE_THREADS",
|
||||
"USE_EXTERNAL_STICKERS",
|
||||
];
|
||||
const permissionString = "266287972351";
|
||||
Deno.test({
|
||||
name: "[utils] calculate bits",
|
||||
fn() {
|
||||
assertEquals(calculateBits(permissionStrins), permissionString);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user