From 1a1ef34a96827c4f18865259677704e29b4096b4 Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 04:01:35 -0400 Subject: [PATCH 01/14] Add channel cloning Changes: - Added function cloneChannel - Modified createChannel to support cloneChannel - Added clone(reason) method on channel structure - Added channel cloning tests --- src/helpers/channels/clone_channel.ts | 28 +++++++++++++++ src/helpers/channels/create_channel.ts | 26 +++++++++----- src/structures/channel.ts | 37 +++++++++++--------- tests/channels/clone_channel.ts | 48 ++++++++++++++++++++++++++ tests/mod.ts | 1 + 5 files changed, 116 insertions(+), 24 deletions(-) create mode 100644 src/helpers/channels/clone_channel.ts create mode 100644 tests/channels/clone_channel.ts diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts new file mode 100644 index 000000000..56509a036 --- /dev/null +++ b/src/helpers/channels/clone_channel.ts @@ -0,0 +1,28 @@ +import { cacheHandlers } from "../../cache.ts"; +import { createChannel } from "./create_channel.ts"; +import { CreateGuildChannel } from "../../types/guilds/create_guild_channel.ts"; +import { DiscordenoChannel } from "../../structures/channel.ts"; + +/** Create a copy of a channel */ +export async function cloneChannel(channelId: string, reason?: string) { + const channelToClone: DiscordenoChannel | undefined = await cacheHandlers.get( + "channels", + channelId + ); + //Return undefined if channel is not cached (unsure about error handling) + if (!channelToClone) return; + + //If "name" is null or undefined as specified by types + channelToClone.name ??= "new-channel"; + + //Merge channel data with reason for createChannel options + const creationData = { + reason, + ...channelToClone, + }; + //Create the channel (also handles permissions) + return createChannel( + channelToClone.guildId!, + creationData as CreateGuildChannel + ); +} diff --git a/src/helpers/channels/create_channel.ts b/src/helpers/channels/create_channel.ts index ac586c930..180028d68 100644 --- a/src/helpers/channels/create_channel.ts +++ b/src/helpers/channels/create_channel.ts @@ -17,14 +17,22 @@ import { calculateBits } from "../../util/permissions.ts"; /** Create a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */ export async function createChannel( guildId: string, - options?: CreateGuildChannel, + options?: CreateGuildChannel ) { const requiredPerms: Set = new Set(["MANAGE_CHANNELS"]); + //Integration with permissions for channel cloning + let useDefaultOverwrites = false; + options?.permissionOverwrites?.forEach((overwrite) => { + if (overwrite.id && parseInt(overwrite.allow)) { + useDefaultOverwrites = true; + + return; + } eventHandlers.debug?.( "loop", - `Running forEach loop in create_channel file.`, + `Running forEach loop in create_channel file.` ); overwrite.allow.forEach(requiredPerms.add, requiredPerms); overwrite.deny.forEach(requiredPerms.add, requiredPerms); @@ -40,14 +48,16 @@ export async function createChannel( endpoints.GUILD_CHANNELS(guildId), { ...camelKeysToSnakeCase(options ?? {}), - permission_overwrites: options?.permissionOverwrites?.map((perm) => ({ - ...perm, + permission_overwrites: useDefaultOverwrites + ? options?.permissionOverwrites + : options?.permissionOverwrites?.map((perm) => ({ + ...perm, - allow: calculateBits(perm.allow), - deny: calculateBits(perm.deny), - })), + allow: calculateBits(perm.allow), + deny: calculateBits(perm.deny), + })), type: options?.type || DiscordChannelTypes.GUILD_TEXT, - }, + } )) as DiscordChannel; const discordenoChannel = await structures.createDiscordenoChannel(result); diff --git a/src/structures/channel.ts b/src/structures/channel.ts index 71086cc4f..88b0b9dfe 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -5,6 +5,8 @@ import { deleteChannel } from "../helpers/channels/delete_channel.ts"; import { deleteChannelOverwrite } from "../helpers/channels/delete_channel_overwrite.ts"; import { editChannel } from "../helpers/channels/edit_channel.ts"; import { editChannelOverwrite } from "../helpers/channels/edit_channel_overwrite.ts"; +import { createChannel } from "../helpers/channels/create_channel.ts"; +import { cloneChannel } from "../helpers/channels/clone_channel.ts"; import { sendMessage } from "../helpers/messages/send_message.ts"; import { disconnectMember } from "../helpers/mod.ts"; import { Channel, DiscordChannel } from "../types/channels/channel.ts"; @@ -30,8 +32,8 @@ const baseChannel: Partial = { return `<#${this.id!}>`; }, get voiceStates() { - return this.guild?.voiceStates.filter((voiceState) => - voiceState.channelId === this.id + return this.guild?.voiceStates.filter( + (voiceState) => voiceState.channelId === this.id ); }, get connectedMembers() { @@ -39,7 +41,7 @@ const baseChannel: Partial = { if (!voiceStates) return undefined; return new Collection( - voiceStates.map((vs, key) => [key, cache.members.get(key)]), + voiceStates.map((vs, key) => [key, cache.members.get(key)]) ); }, send(content) { @@ -62,19 +64,23 @@ const baseChannel: Partial = { this.guildId!, this.id!, overwrites, - permissions, + permissions ); }, edit(options, reason) { return editChannel(this.id!, options, reason); }, + + clone(reason) { + return cloneChannel(this.id!, reason); + }, }; /** Create a structure object */ // deno-lint-ignore require-await export async function createDiscordenoChannel( data: DiscordChannel, - guildId?: string, + guildId?: string ) { const { guildId: rawGuildId = "", @@ -86,7 +92,7 @@ export async function createDiscordenoChannel( Object.keys(rest).forEach((key) => { eventHandlers.debug?.( "loop", - `Running forEach loop in createDiscordenoChannel function.`, + `Running forEach loop in createDiscordenoChannel function.` ); // @ts-ignore index signature props[key] = createNewProp(rest[key]); @@ -96,7 +102,7 @@ export async function createDiscordenoChannel( ...props, guildId: createNewProp(guildId || rawGuildId), lastPinTimestamp: createNewProp( - lastPinTimestamp ? Date.parse(lastPinTimestamp) : undefined, + lastPinTimestamp ? Date.parse(lastPinTimestamp) : undefined ), }); @@ -125,13 +131,13 @@ export interface DiscordenoChannel mention: string; /** * Gets the voice states for this channel - * + * * ⚠️ ADVANCED: If you use the custom cache, these will not work for you. Getters can not be async and custom cache requires async. */ voiceStates?: Collection; /** * Gets the connected members for this channel undefined if member is not cached - * + * * ⚠️ ADVANCED: If you use the custom cache, these will not work for you. Getters can not be async and custom cache requires async. */ connectedMembers?: Collection; @@ -147,20 +153,19 @@ export interface DiscordenoChannel /** Edit a channel Overwrite */ editOverwrite( overwriteID: string, - options: Omit, + options: Omit ): ReturnType; /** Delete a channel Overwrite */ deleteOverwrite( - overwriteID: string, + overwriteID: string ): ReturnType; /** Checks if a channel overwrite for a user id or a role id has permission in this channel */ hasPermission( overwrites: DiscordOverwrite[], - permissions: PermissionStrings[], + permissions: PermissionStrings[] ): ReturnType; /** Edit the channel */ - edit( - options: ModifyChannel, - reason?: string, - ): ReturnType; + edit(options: ModifyChannel, reason?: string): ReturnType; + /** Create a new channel with the same properties */ + clone(reason?: string): ReturnType; } diff --git a/tests/channels/clone_channel.ts b/tests/channels/clone_channel.ts new file mode 100644 index 000000000..a2ca9d2ad --- /dev/null +++ b/tests/channels/clone_channel.ts @@ -0,0 +1,48 @@ +import { defaultTestOptions, tempData } from "../ws/start_bot.ts"; +import { assertEquals, assertExists } from "../deps.ts"; +import { cache } from "../../src/cache.ts"; +import { cloneChannel } from "../../src/helpers/channels/clone_channel.ts"; +import { delayUntil } from "../util/delay_until.ts"; + +Deno.test({ + name: "[channel] clone a channel", + async fn() { + const cloned = await cloneChannel(tempData.channelId, "testing"); + + //Get channel that was cloned + const originalChannel = cache.channels.get(tempData.channelId); + + //Assertation + assertExists(cloned); + assertEquals(cloned.type, originalChannel.type); + + // Delay the execution to allow CHANNEL_CREATE event to be processed + await delayUntil(10000, () => cache.channels.has(cloned.id)); + + if (!cache.channels.has(cloned.id)) { + throw new Error(`The channel seemed to be cloned but was not cached.`); + } + + if (originalChannel.topic && cloned.topic !== originalChannel.topic) { + throw new Error( + "The clone was supposed to have a topic but it does not appear to be the same topic." + ); + } + + if (originalChannel.bitrate && cloned.bitrate !== originalChannel.bitrate) { + throw new Error( + "The clone was supposed to have a bitrate but it does not appear to be the same bitrate." + ); + } + + if ( + originalChannel.permissionOverwrites && + cloned.permissionOverwrites?.length !== + originalChannel.permissionOverwrites.length + ) { + throw new Error( + "The clone was supposed to have a permissionOverwrites but it does not appear to be the same permissionOverwrites." + ); + } + }, +}); diff --git a/tests/mod.ts b/tests/mod.ts index daa91c90f..f66c18bb1 100644 --- a/tests/mod.ts +++ b/tests/mod.ts @@ -16,6 +16,7 @@ import "./guilds/create_guild.ts"; import "./channels/category_children.ts"; import "./channels/channel_overwrite_has_permission.ts"; import "./channels/create_channel.ts"; +import "./channels/clone_channel.ts"; import "./channels/delete_channel.ts"; import "./channels/delete_channel_overwrite.ts"; import "./channels/edit_channel.ts"; From bfb3502252a0e86597a57b9f13afa74d7f86f036 Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 04:09:00 -0400 Subject: [PATCH 02/14] Fix Linting Issue --- tests/channels/clone_channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/channels/clone_channel.ts b/tests/channels/clone_channel.ts index a2ca9d2ad..bb2209acb 100644 --- a/tests/channels/clone_channel.ts +++ b/tests/channels/clone_channel.ts @@ -1,4 +1,4 @@ -import { defaultTestOptions, tempData } from "../ws/start_bot.ts"; +import { tempData } from "../ws/start_bot.ts"; import { assertEquals, assertExists } from "../deps.ts"; import { cache } from "../../src/cache.ts"; import { cloneChannel } from "../../src/helpers/channels/clone_channel.ts"; From 084d1495984cf0499dfad82b01ca28e7d34655f4 Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Wed, 14 Apr 2021 08:46:02 -0400 Subject: [PATCH 03/14] Update src/helpers/channels/clone_channel.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> --- src/helpers/channels/clone_channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index 56509a036..fc6812e28 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -5,7 +5,7 @@ import { DiscordenoChannel } from "../../structures/channel.ts"; /** Create a copy of a channel */ export async function cloneChannel(channelId: string, reason?: string) { - const channelToClone: DiscordenoChannel | undefined = await cacheHandlers.get( + const channelToClone = await cacheHandlers.get( "channels", channelId ); From 6063bc0afff53acff0489e1f644a7da892adad11 Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Wed, 14 Apr 2021 08:46:18 -0400 Subject: [PATCH 04/14] Update src/helpers/channels/clone_channel.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> --- src/helpers/channels/clone_channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index fc6812e28..a6b018215 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -12,7 +12,7 @@ export async function cloneChannel(channelId: string, reason?: string) { //Return undefined if channel is not cached (unsure about error handling) if (!channelToClone) return; - //If "name" is null or undefined as specified by types + //If "name" is undefined as specified by types channelToClone.name ??= "new-channel"; //Merge channel data with reason for createChannel options From 4183ffd21dfebe262a73b5516ff9e978b6b39f39 Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Wed, 14 Apr 2021 08:47:21 -0400 Subject: [PATCH 05/14] Update src/helpers/channels/clone_channel.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> --- src/helpers/channels/clone_channel.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index a6b018215..429129b07 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -15,14 +15,10 @@ export async function cloneChannel(channelId: string, reason?: string) { //If "name" is undefined as specified by types channelToClone.name ??= "new-channel"; - //Merge channel data with reason for createChannel options - const creationData = { - reason, - ...channelToClone, - }; //Create the channel (also handles permissions) return createChannel( channelToClone.guildId!, - creationData as CreateGuildChannel + channelToClone, + reason, ); } From ef88a57a38c74df4ff23badc66a0f3414e69cd3a Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Wed, 14 Apr 2021 08:47:46 -0400 Subject: [PATCH 06/14] Update src/helpers/channels/clone_channel.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> --- src/helpers/channels/clone_channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index 429129b07..21524b143 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -10,7 +10,7 @@ export async function cloneChannel(channelId: string, reason?: string) { channelId ); //Return undefined if channel is not cached (unsure about error handling) - if (!channelToClone) return; + if (!channelToClone) throw new Error(Errors.CHANNEL_NOT_FOUND); //If "name" is undefined as specified by types channelToClone.name ??= "new-channel"; From d3ed1e03e7a6942731b854333766df50ec23468f Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 11:41:57 -0500 Subject: [PATCH 07/14] Formatting Changes Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> --- src/structures/channel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/structures/channel.ts b/src/structures/channel.ts index 88b0b9dfe..793a71e13 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -70,7 +70,6 @@ const baseChannel: Partial = { edit(options, reason) { return editChannel(this.id!, options, reason); }, - clone(reason) { return cloneChannel(this.id!, reason); }, From 3d5bdc460516ba8d9dd1f13cec3644aa733270ec Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 13:06:21 -0400 Subject: [PATCH 08/14] Suggested changes to cloneChannel - Removed name check - Added DM channel check --- src/helpers/channels/clone_channel.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index 21524b143..d87d48682 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -1,24 +1,22 @@ import { cacheHandlers } from "../../cache.ts"; import { createChannel } from "./create_channel.ts"; -import { CreateGuildChannel } from "../../types/guilds/create_guild_channel.ts"; -import { DiscordenoChannel } from "../../structures/channel.ts"; +import { Errors } from "../../types/misc/errors.ts"; +import { DiscordChannelTypes } from "../../types/channels/channel_types.ts"; /** Create a copy of a channel */ export async function cloneChannel(channelId: string, reason?: string) { - const channelToClone = await cacheHandlers.get( - "channels", - channelId - ); - //Return undefined if channel is not cached (unsure about error handling) + const channelToClone = await cacheHandlers.get("channels", channelId); + //Return undefined if channel is not cached if (!channelToClone) throw new Error(Errors.CHANNEL_NOT_FOUND); - //If "name" is undefined as specified by types - channelToClone.name ??= "new-channel"; + //Check for DM channel + if ( + channelToClone.type === DiscordChannelTypes.DM || + channelToClone.type === DiscordChannelTypes.GROUP_DM + ) { + throw new Error(Errors.CHANNEL_NOT_IN_GUILD); + } //Create the channel (also handles permissions) - return createChannel( - channelToClone.guildId!, - channelToClone, - reason, - ); + return createChannel(channelToClone.guildId!, channelToClone, reason); } From 215141171ae78971b9f30619000bf59b544ff68a Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 13:09:47 -0400 Subject: [PATCH 09/14] Fix formatting (deno fmt) --- src/helpers/channels/create_channel.ts | 14 +++++++------- src/structures/channel.ts | 18 +++++++++--------- tests/channels/clone_channel.ts | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/helpers/channels/create_channel.ts b/src/helpers/channels/create_channel.ts index 180028d68..903103343 100644 --- a/src/helpers/channels/create_channel.ts +++ b/src/helpers/channels/create_channel.ts @@ -17,7 +17,7 @@ import { calculateBits } from "../../util/permissions.ts"; /** Create a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */ export async function createChannel( guildId: string, - options?: CreateGuildChannel + options?: CreateGuildChannel, ) { const requiredPerms: Set = new Set(["MANAGE_CHANNELS"]); @@ -32,7 +32,7 @@ export async function createChannel( } eventHandlers.debug?.( "loop", - `Running forEach loop in create_channel file.` + `Running forEach loop in create_channel file.`, ); overwrite.allow.forEach(requiredPerms.add, requiredPerms); overwrite.deny.forEach(requiredPerms.add, requiredPerms); @@ -51,13 +51,13 @@ export async function createChannel( permission_overwrites: useDefaultOverwrites ? options?.permissionOverwrites : options?.permissionOverwrites?.map((perm) => ({ - ...perm, + ...perm, - allow: calculateBits(perm.allow), - deny: calculateBits(perm.deny), - })), + allow: calculateBits(perm.allow), + deny: calculateBits(perm.deny), + })), type: options?.type || DiscordChannelTypes.GUILD_TEXT, - } + }, )) as DiscordChannel; const discordenoChannel = await structures.createDiscordenoChannel(result); diff --git a/src/structures/channel.ts b/src/structures/channel.ts index 793a71e13..3e3d27329 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -33,7 +33,7 @@ const baseChannel: Partial = { }, get voiceStates() { return this.guild?.voiceStates.filter( - (voiceState) => voiceState.channelId === this.id + (voiceState) => voiceState.channelId === this.id, ); }, get connectedMembers() { @@ -41,7 +41,7 @@ const baseChannel: Partial = { if (!voiceStates) return undefined; return new Collection( - voiceStates.map((vs, key) => [key, cache.members.get(key)]) + voiceStates.map((vs, key) => [key, cache.members.get(key)]), ); }, send(content) { @@ -64,7 +64,7 @@ const baseChannel: Partial = { this.guildId!, this.id!, overwrites, - permissions + permissions, ); }, edit(options, reason) { @@ -79,7 +79,7 @@ const baseChannel: Partial = { // deno-lint-ignore require-await export async function createDiscordenoChannel( data: DiscordChannel, - guildId?: string + guildId?: string, ) { const { guildId: rawGuildId = "", @@ -91,7 +91,7 @@ export async function createDiscordenoChannel( Object.keys(rest).forEach((key) => { eventHandlers.debug?.( "loop", - `Running forEach loop in createDiscordenoChannel function.` + `Running forEach loop in createDiscordenoChannel function.`, ); // @ts-ignore index signature props[key] = createNewProp(rest[key]); @@ -101,7 +101,7 @@ export async function createDiscordenoChannel( ...props, guildId: createNewProp(guildId || rawGuildId), lastPinTimestamp: createNewProp( - lastPinTimestamp ? Date.parse(lastPinTimestamp) : undefined + lastPinTimestamp ? Date.parse(lastPinTimestamp) : undefined, ), }); @@ -152,16 +152,16 @@ export interface DiscordenoChannel /** Edit a channel Overwrite */ editOverwrite( overwriteID: string, - options: Omit + options: Omit, ): ReturnType; /** Delete a channel Overwrite */ deleteOverwrite( - overwriteID: string + overwriteID: string, ): ReturnType; /** Checks if a channel overwrite for a user id or a role id has permission in this channel */ hasPermission( overwrites: DiscordOverwrite[], - permissions: PermissionStrings[] + permissions: PermissionStrings[], ): ReturnType; /** Edit the channel */ edit(options: ModifyChannel, reason?: string): ReturnType; diff --git a/tests/channels/clone_channel.ts b/tests/channels/clone_channel.ts index bb2209acb..caddad7d4 100644 --- a/tests/channels/clone_channel.ts +++ b/tests/channels/clone_channel.ts @@ -25,13 +25,13 @@ Deno.test({ if (originalChannel.topic && cloned.topic !== originalChannel.topic) { throw new Error( - "The clone was supposed to have a topic but it does not appear to be the same topic." + "The clone was supposed to have a topic but it does not appear to be the same topic.", ); } if (originalChannel.bitrate && cloned.bitrate !== originalChannel.bitrate) { throw new Error( - "The clone was supposed to have a bitrate but it does not appear to be the same bitrate." + "The clone was supposed to have a bitrate but it does not appear to be the same bitrate.", ); } @@ -41,7 +41,7 @@ Deno.test({ originalChannel.permissionOverwrites.length ) { throw new Error( - "The clone was supposed to have a permissionOverwrites but it does not appear to be the same permissionOverwrites." + "The clone was supposed to have a permissionOverwrites but it does not appear to be the same permissionOverwrites.", ); } }, From 3088cc0693867dd646080793e6e6ddcdaa158f5d Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 13:28:59 -0400 Subject: [PATCH 10/14] Convert overwrites - Removed integration in createChannel - Converting from DiscordOverwrite to Overwrite in cloneChannel function --- src/helpers/channels/clone_channel.ts | 16 ++++++++++++++++ src/helpers/channels/create_channel.ts | 20 +++++--------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index d87d48682..8c48d47ad 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -2,6 +2,8 @@ import { cacheHandlers } from "../../cache.ts"; import { createChannel } from "./create_channel.ts"; import { Errors } from "../../types/misc/errors.ts"; import { DiscordChannelTypes } from "../../types/channels/channel_types.ts"; +import { calculatePermissions } from "../../util/permissions.ts"; +import { Overwrite } from "../../types/channels/overwrite.ts"; /** Create a copy of a channel */ export async function cloneChannel(channelId: string, reason?: string) { @@ -17,6 +19,20 @@ export async function cloneChannel(channelId: string, reason?: string) { throw new Error(Errors.CHANNEL_NOT_IN_GUILD); } + //Convert channel permission + const newOverwrites: Overwrite[] = []; + + channelToClone.permissionOverwrites.forEach((overwrite) => { + newOverwrites.push({ + id: overwrite.id, + type: overwrite.type, + allow: calculatePermissions(BigInt(overwrite.allow)), + deny: calculatePermissions(BigInt(overwrite.deny)), + }); + }); + + channelToClone.permissionOverwrites = newOverwrites; + //Create the channel (also handles permissions) return createChannel(channelToClone.guildId!, channelToClone, reason); } diff --git a/src/helpers/channels/create_channel.ts b/src/helpers/channels/create_channel.ts index 903103343..ac586c930 100644 --- a/src/helpers/channels/create_channel.ts +++ b/src/helpers/channels/create_channel.ts @@ -21,15 +21,7 @@ export async function createChannel( ) { const requiredPerms: Set = new Set(["MANAGE_CHANNELS"]); - //Integration with permissions for channel cloning - let useDefaultOverwrites = false; - options?.permissionOverwrites?.forEach((overwrite) => { - if (overwrite.id && parseInt(overwrite.allow)) { - useDefaultOverwrites = true; - - return; - } eventHandlers.debug?.( "loop", `Running forEach loop in create_channel file.`, @@ -48,14 +40,12 @@ export async function createChannel( endpoints.GUILD_CHANNELS(guildId), { ...camelKeysToSnakeCase(options ?? {}), - permission_overwrites: useDefaultOverwrites - ? options?.permissionOverwrites - : options?.permissionOverwrites?.map((perm) => ({ - ...perm, + permission_overwrites: options?.permissionOverwrites?.map((perm) => ({ + ...perm, - allow: calculateBits(perm.allow), - deny: calculateBits(perm.deny), - })), + allow: calculateBits(perm.allow), + deny: calculateBits(perm.deny), + })), type: options?.type || DiscordChannelTypes.GUILD_TEXT, }, )) as DiscordChannel; From fea973b346759310a711fa109525b3a9ee2a1d38 Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 13:33:08 -0400 Subject: [PATCH 11/14] Editing return type on channel clone method Changed return type of `clone` to reflect `cloneChannel`. Removed unused import for `createChannel`. --- src/structures/channel.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/structures/channel.ts b/src/structures/channel.ts index 3e3d27329..e3955e8c8 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -5,7 +5,6 @@ import { deleteChannel } from "../helpers/channels/delete_channel.ts"; import { deleteChannelOverwrite } from "../helpers/channels/delete_channel_overwrite.ts"; import { editChannel } from "../helpers/channels/edit_channel.ts"; import { editChannelOverwrite } from "../helpers/channels/edit_channel_overwrite.ts"; -import { createChannel } from "../helpers/channels/create_channel.ts"; import { cloneChannel } from "../helpers/channels/clone_channel.ts"; import { sendMessage } from "../helpers/messages/send_message.ts"; import { disconnectMember } from "../helpers/mod.ts"; @@ -166,5 +165,5 @@ export interface DiscordenoChannel /** Edit the channel */ edit(options: ModifyChannel, reason?: string): ReturnType; /** Create a new channel with the same properties */ - clone(reason?: string): ReturnType; + clone(reason?: string): ReturnType; } From 3b41656c090b997143ebe4ce8473239aec6683cd Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 14:14:37 -0400 Subject: [PATCH 12/14] Rework channel clone tests - Removed previous channel clone test - Copied over create channel tests and modified `ifItFailsBlameWolf` to check against a clone instead of created --- tests/channels/clone_channel.ts | 190 +++++++++++++++++++++++++------- 1 file changed, 151 insertions(+), 39 deletions(-) diff --git a/tests/channels/clone_channel.ts b/tests/channels/clone_channel.ts index caddad7d4..d37631b96 100644 --- a/tests/channels/clone_channel.ts +++ b/tests/channels/clone_channel.ts @@ -1,48 +1,160 @@ -import { tempData } from "../ws/start_bot.ts"; +import { defaultTestOptions, tempData } from "../ws/start_bot.ts"; import { assertEquals, assertExists } from "../deps.ts"; import { cache } from "../../src/cache.ts"; import { cloneChannel } from "../../src/helpers/channels/clone_channel.ts"; +import { createChannel } from "../../src/helpers/channels/create_channel.ts"; +import { CreateGuildChannel } from "../../src/types/guilds/create_guild_channel.ts"; + import { delayUntil } from "../util/delay_until.ts"; +import { botId } from "../../src/bot.ts"; +import { DiscordOverwriteTypes } from "../../src/types/channels/overwrite_types.ts"; +import { DiscordChannelTypes } from "../../src/types/channels/channel_types.ts"; + +async function ifItFailsBlameWolf(options: CreateGuildChannel, save = false) { + const channel = await createChannel(tempData.guildId, options); + + const cloned = await cloneChannel(channel.id); + + //Assertations + assertExists(cloned); + assertEquals(cloned.type, channel.type); + + // Delay the execution to allow CHANNEL_CREATE event to be processed + await delayUntil(10000, () => cache.channels.has(cloned.id)); + + if (!cache.channels.has(cloned.id)) { + throw new Error(`The channel seemed to be cloned but was not cached.`); + } + + if (channel.topic && cloned.topic !== channel.topic) { + throw new Error( + "The clone was supposed to have a topic but it does not appear to be the same topic.", + ); + } + + if (channel.bitrate && cloned.bitrate !== channel.bitrate) { + throw new Error( + "The clone was supposed to have a bitrate but it does not appear to be the same bitrate.", + ); + } + + if ( + channel.permissionOverwrites && + cloned.permissionOverwrites?.length !== channel.permissionOverwrites.length + ) { + throw new Error( + "The clone was supposed to have a permissionOverwrites but it does not appear to be the same permissionOverwrites.", + ); + } +} +Deno.test({ + name: "[channel] clone a new text channel", + async fn() { + await ifItFailsBlameWolf({ name: "Discordeno-clone-test" }, false); + }, + ...defaultTestOptions, +}); Deno.test({ - name: "[channel] clone a channel", + name: "[channel] clone a new category channel", async fn() { - const cloned = await cloneChannel(tempData.channelId, "testing"); - - //Get channel that was cloned - const originalChannel = cache.channels.get(tempData.channelId); - - //Assertation - assertExists(cloned); - assertEquals(cloned.type, originalChannel.type); - - // Delay the execution to allow CHANNEL_CREATE event to be processed - await delayUntil(10000, () => cache.channels.has(cloned.id)); - - if (!cache.channels.has(cloned.id)) { - throw new Error(`The channel seemed to be cloned but was not cached.`); - } - - if (originalChannel.topic && cloned.topic !== originalChannel.topic) { - throw new Error( - "The clone was supposed to have a topic but it does not appear to be the same topic.", - ); - } - - if (originalChannel.bitrate && cloned.bitrate !== originalChannel.bitrate) { - throw new Error( - "The clone was supposed to have a bitrate but it does not appear to be the same bitrate.", - ); - } - - if ( - originalChannel.permissionOverwrites && - cloned.permissionOverwrites?.length !== - originalChannel.permissionOverwrites.length - ) { - throw new Error( - "The clone was supposed to have a permissionOverwrites but it does not appear to be the same permissionOverwrites.", - ); - } + await ifItFailsBlameWolf( + { + name: "Discordeno-clone-test", + type: DiscordChannelTypes.GUILD_CATEGORY, + }, + false, + ); }, + ...defaultTestOptions, +}); + +Deno.test({ + name: "[channel] clone a new voice channel", + async fn() { + await ifItFailsBlameWolf( + { + name: "Discordeno-clone-test", + type: DiscordChannelTypes.GUILD_VOICE, + }, + false, + ); + }, + ...defaultTestOptions, +}); + +Deno.test({ + name: "[channel] clone a new voice channel with a bitrate", + async fn() { + await ifItFailsBlameWolf( + { + name: "discordeno-clone-test", + type: DiscordChannelTypes.GUILD_VOICE, + bitrate: 32000, + }, + false, + ); + }, + ...defaultTestOptions, +}); + +Deno.test({ + name: "[channel] clone a new voice channel with a user limit", + async fn() { + await ifItFailsBlameWolf( + { + name: "Discordeno-clone-test", + type: DiscordChannelTypes.GUILD_VOICE, + userLimit: 32, + }, + false, + ); + }, + ...defaultTestOptions, +}); + +Deno.test({ + name: "[channel] clone a new text channel with a rate limit per user", + async fn() { + await ifItFailsBlameWolf( + { + name: "Discordeno-clone-test", + rateLimitPerUser: 2423, + }, + false, + ); + }, + ...defaultTestOptions, +}); + +Deno.test({ + name: "[channel] clone a new text channel with NSFW", + async fn() { + await ifItFailsBlameWolf( + { name: "Discordeno-clone-test", nsfw: true }, + false, + ); + }, + ...defaultTestOptions, +}); + +Deno.test({ + name: "[channel] create a new text channel with permission overwrites", + async fn() { + await ifItFailsBlameWolf( + { + name: "Discordeno-clone-test", + permissionOverwrites: [ + { + id: botId, + type: DiscordOverwriteTypes.MEMBER, + allow: ["VIEW_CHANNEL"], + deny: [], + }, + ], + }, + false, + ); + }, + ...defaultTestOptions, }); From c7a21b7a84a90f1fe56a5048c09fe7d3b02274f0 Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 14:28:44 -0400 Subject: [PATCH 13/14] Formatting --- tests/channels/clone_channel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/channels/clone_channel.ts b/tests/channels/clone_channel.ts index d37631b96..bcd839f49 100644 --- a/tests/channels/clone_channel.ts +++ b/tests/channels/clone_channel.ts @@ -4,7 +4,6 @@ import { cache } from "../../src/cache.ts"; import { cloneChannel } from "../../src/helpers/channels/clone_channel.ts"; import { createChannel } from "../../src/helpers/channels/create_channel.ts"; import { CreateGuildChannel } from "../../src/types/guilds/create_guild_channel.ts"; - import { delayUntil } from "../util/delay_until.ts"; import { botId } from "../../src/bot.ts"; import { DiscordOverwriteTypes } from "../../src/types/channels/overwrite_types.ts"; From 3133e1015dd1f661e5d2950cd4bbb433622e354d Mon Sep 17 00:00:00 2001 From: Exists <55012346+existentiality@users.noreply.github.com> Date: Wed, 14 Apr 2021 14:03:01 -0500 Subject: [PATCH 14/14] Fix test name Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> --- tests/channels/clone_channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/channels/clone_channel.ts b/tests/channels/clone_channel.ts index bcd839f49..41759cca6 100644 --- a/tests/channels/clone_channel.ts +++ b/tests/channels/clone_channel.ts @@ -138,7 +138,7 @@ Deno.test({ }); Deno.test({ - name: "[channel] create a new text channel with permission overwrites", + name: "[channel] clone a new text channel with permission overwrites", async fn() { await ifItFailsBlameWolf( {