mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 11:28:15 +00:00
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:
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user