diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index e84e039e0..d523572cf 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -13,8 +13,8 @@ export async function cloneChannel(channelId: string, reason?: string) { //Check for DM channel if ( - channelToClone.type === DiscordChannelTypes.DM || - channelToClone.type === DiscordChannelTypes.GROUP_DM + channelToClone.type === DiscordChannelTypes.Dm || + channelToClone.type === DiscordChannelTypes.GroupDm ) { throw new Error(Errors.CHANNEL_NOT_IN_GUILD); } diff --git a/src/helpers/channels/create_channel.ts b/src/helpers/channels/create_channel.ts index 9d675ed60..699881c5a 100644 --- a/src/helpers/channels/create_channel.ts +++ b/src/helpers/channels/create_channel.ts @@ -1,4 +1,3 @@ -import { eventHandlers } from "../../bot.ts"; import { cacheHandlers } from "../../cache.ts"; import { rest } from "../../rest/rest.ts"; import { structures } from "../../structures/mod.ts"; @@ -8,11 +7,10 @@ import { CreateGuildChannel, DiscordCreateGuildChannel, } from "../../types/guilds/create_guild_channel.ts"; -import { PermissionStrings } from "../../types/permissions/permission_strings.ts"; import { endpoints } from "../../util/constants.ts"; import { calculateBits, - requireBotGuildPermissions, + requireOverwritePermissions, } from "../../util/permissions.ts"; import { camelKeysToSnakeCase } from "../../util/utils.ts"; @@ -22,18 +20,12 @@ export async function createChannel( options?: CreateGuildChannel, reason?: string, ) { - const requiredPerms: Set = new Set(["MANAGE_CHANNELS"]); - - options?.permissionOverwrites?.forEach((overwrite) => { - eventHandlers.debug?.( - "loop", - `Running forEach loop in create_channel file.`, + if (options?.permissionOverwrites) { + await requireOverwritePermissions( + guildId, + options.permissionOverwrites, ); - overwrite.allow.forEach(requiredPerms.add, requiredPerms); - overwrite.deny.forEach(requiredPerms.add, requiredPerms); - }); - - await requireBotGuildPermissions(guildId, [...requiredPerms]); + } // BITRATES ARE IN THOUSANDS SO IF USER PROVIDES 32 WE CONVERT TO 32000 if (options?.bitrate && options.bitrate < 1000) options.bitrate *= 1000; @@ -48,7 +40,7 @@ export async function createChannel( allow: calculateBits(perm.allow), deny: calculateBits(perm.deny), })), - type: options?.type || DiscordChannelTypes.GUILD_TEXT, + type: options?.type || DiscordChannelTypes.GuildText, reason, }, ); diff --git a/src/helpers/channels/edit_channel.ts b/src/helpers/channels/edit_channel.ts index dfb064c7d..89b95f2ae 100644 --- a/src/helpers/channels/edit_channel.ts +++ b/src/helpers/channels/edit_channel.ts @@ -1,20 +1,27 @@ import { eventHandlers } from "../../bot.ts"; +import { cacheHandlers } from "../../cache.ts"; import { rest } from "../../rest/rest.ts"; import { ModifyChannel } from "../../types/channels/modify_channel.ts"; import { Channel } from "../../types/mod.ts"; import { endpoints } from "../../util/constants.ts"; import { calculateBits, - requireBotChannelPermissions, + requireOverwritePermissions, } from "../../util/permissions.ts"; - +//TODO: implement DM group channel edit /** Update a channel's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */ export async function editChannel( channelId: string, options: ModifyChannel, reason?: string, ) { - await requireBotChannelPermissions(channelId, ["MANAGE_CHANNELS"]); + const channel = await cacheHandlers.get("channels", channelId); + if (channel?.guildId) { + await requireOverwritePermissions( + channel.guildId, + options.permissionOverwrites || [], + ); + } if (options.name || options.topic) { const request = editChannelNameTopicQueue.get(channelId); diff --git a/src/util/permissions.ts b/src/util/permissions.ts index 90e187562..2a2bf61b5 100644 --- a/src/util/permissions.ts +++ b/src/util/permissions.ts @@ -4,6 +4,7 @@ import { DiscordenoChannel } from "../structures/channel.ts"; import { DiscordenoGuild } from "../structures/guild.ts"; import { DiscordenoMember } from "../structures/member.ts"; import { DiscordenoRole } from "../structures/role.ts"; +import { Overwrite } from "../types/channels/overwrite.ts"; import { Errors } from "../types/misc/errors.ts"; import { DiscordBitwisePermissionFlags } from "../types/permissions/bitwise_permission_flags.ts"; import { PermissionStrings } from "../types/permissions/permission_strings.ts"; @@ -28,11 +29,6 @@ async function getCached( ? // @ts-ignore TS is wrong here await cacheHandlers.get(table, key) : key; - if (!cached || typeof cached === "string") { - throw new Error( - Errors[`${table.slice(0, -1).toUpperCase()}_NOT_FOUND` as Errors], - ); - } return typeof cached === "string" ? undefined : cached; } @@ -50,7 +46,7 @@ export async function calculateBasePermissions( let permissions = 0n; // Calculate the role permissions bits, @everyone role is not in memberRoleIds so we need to pass guildId manualy permissions |= [...(member.guilds.get(guild.id)?.roles || []), guild.id] - .map((id) => (guild as DiscordenoGuild).roles.get(id)?.permissions) + .map((id) => guild.roles.get(id)?.permissions) // Removes any edge case undefined .filter((perm) => perm) .reduce((bits, perms) => { @@ -76,7 +72,7 @@ export async function calculateChannelOverwrites( const member = await getCached("members", memberOrId); - if (!member) return "8"; + if (!channel || !member) return "8"; // Get all the role permissions this member already has let permissions = BigInt( @@ -84,7 +80,7 @@ export async function calculateChannelOverwrites( ); // First calculate @everyone overwrites since these have the lowest priority - const overwriteEveryone = channel?.permissionOverwrites?.find( + const overwriteEveryone = channel.permissionOverwrites.find( (overwrite) => overwrite.id === (channel as DiscordenoChannel).guildId, ); if (overwriteEveryone) { @@ -93,7 +89,7 @@ export async function calculateChannelOverwrites( permissions |= BigInt(overwriteEveryone.allow); } - const overwrites = channel?.permissionOverwrites; + 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; @@ -111,8 +107,8 @@ export async function calculateChannelOverwrites( permissions |= allow; // Third calculate member specific overwrites since these have the highest priority - const overwriteMember = overwrites?.find( - (overwrite) => overwrite.id === (member as DiscordenoMember).id, + const overwriteMember = overwrites.find( + (overwrite) => overwrite.id === member.id, ); if (overwriteMember) { permissions &= ~BigInt(overwriteMember.deny); @@ -290,6 +286,26 @@ export function calculateBits(permissions: PermissionStrings[]) { .toString(); } +/** Internal function to check if the bot has the permissions to set these overwrites */ +export async function requireOverwritePermissions( + guildOrId: string | DiscordenoGuild, + overwrites: Overwrite[], +) { + let requiredPerms: Set = new Set(["MANAGE_CHANNELS"]); + + overwrites?.forEach((overwrite) => { + overwrite.allow.forEach(requiredPerms.add, requiredPerms); + overwrite.deny.forEach(requiredPerms.add, requiredPerms); + }); + + // MANAGE_ROLES permission can only be set by administrators + if (requiredPerms.has("MANAGE_ROLES")) { + requiredPerms = new Set(["ADMINISTRATOR"]); + } + + await requireGuildPermissions(guildOrId, botId, [...requiredPerms]); +} + /** Gets the highest role from the member in this guild */ export async function highestRole( guildOrId: string | DiscordenoGuild,