Add channel cloning

Changes:
    - Added function cloneChannel
    - Modified createChannel to support cloneChannel
   - Added clone(reason) method on channel structure
    - Added channel cloning tests
This commit is contained in:
Exists
2021-04-14 04:01:35 -04:00
parent f31216d0a4
commit 1a1ef34a96
5 changed files with 116 additions and 24 deletions
+28
View File
@@ -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
);
}
+18 -8
View File
@@ -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<PermissionStrings> = 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<DiscordCreateGuildChannel>(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);
+21 -16
View File
@@ -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<DiscordenoChannel> = {
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<DiscordenoChannel> = {
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<DiscordenoChannel> = {
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<string, VoiceState>;
/**
* 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<string, DiscordenoMember | undefined>;
@@ -147,20 +153,19 @@ export interface DiscordenoChannel
/** Edit a channel Overwrite */
editOverwrite(
overwriteID: string,
options: Omit<Overwrite, "id">,
options: Omit<Overwrite, "id">
): ReturnType<typeof editChannelOverwrite>;
/** Delete a channel Overwrite */
deleteOverwrite(
overwriteID: string,
overwriteID: string
): ReturnType<typeof deleteChannelOverwrite>;
/** 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<typeof channelOverwriteHasPermission>;
/** Edit the channel */
edit(
options: ModifyChannel,
reason?: string,
): ReturnType<typeof editChannel>;
edit(options: ModifyChannel, reason?: string): ReturnType<typeof editChannel>;
/** Create a new channel with the same properties */
clone(reason?: string): ReturnType<typeof createChannel>;
}
+48
View File
@@ -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."
);
}
},
});
+1
View File
@@ -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";