summaryrefslogtreecommitdiff
path: root/node_modules/discord.js/src/managers/GuildChannelManager.js
diff options
context:
space:
mode:
authorsowgro <tpoke.ferrari@gmail.com>2023-09-02 19:12:47 -0400
committersowgro <tpoke.ferrari@gmail.com>2023-09-02 19:12:47 -0400
commite4450c8417624b71d779cb4f41692538f9165e10 (patch)
treeb70826542223ecdf8a7a259f61b0a1abb8a217d8 /node_modules/discord.js/src/managers/GuildChannelManager.js
downloadsowbot3-e4450c8417624b71d779cb4f41692538f9165e10.tar.gz
sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.tar.bz2
sowbot3-e4450c8417624b71d779cb4f41692538f9165e10.zip
first commit
Diffstat (limited to 'node_modules/discord.js/src/managers/GuildChannelManager.js')
-rw-r--r--node_modules/discord.js/src/managers/GuildChannelManager.js503
1 files changed, 503 insertions, 0 deletions
diff --git a/node_modules/discord.js/src/managers/GuildChannelManager.js b/node_modules/discord.js/src/managers/GuildChannelManager.js
new file mode 100644
index 0000000..7ca9287
--- /dev/null
+++ b/node_modules/discord.js/src/managers/GuildChannelManager.js
@@ -0,0 +1,503 @@
+'use strict';
+
+const process = require('node:process');
+const { Collection } = require('@discordjs/collection');
+const { ChannelType, Routes } = require('discord-api-types/v10');
+const CachedManager = require('./CachedManager');
+const GuildTextThreadManager = require('./GuildTextThreadManager');
+const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
+const GuildChannel = require('../structures/GuildChannel');
+const PermissionOverwrites = require('../structures/PermissionOverwrites');
+const ThreadChannel = require('../structures/ThreadChannel');
+const Webhook = require('../structures/Webhook');
+const ChannelFlagsBitField = require('../util/ChannelFlagsBitField');
+const { transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels');
+const { ThreadChannelTypes } = require('../util/Constants');
+const DataResolver = require('../util/DataResolver');
+const { setPosition } = require('../util/Util');
+
+let cacheWarningEmitted = false;
+
+/**
+ * Manages API methods for GuildChannels and stores their cache.
+ * @extends {CachedManager}
+ */
+class GuildChannelManager extends CachedManager {
+ constructor(guild, iterable) {
+ super(guild.client, GuildChannel, iterable);
+ const defaultCaching =
+ this._cache.constructor.name === 'Collection' ||
+ this._cache.maxSize === undefined ||
+ this._cache.maxSize === Infinity;
+ if (!cacheWarningEmitted && !defaultCaching) {
+ cacheWarningEmitted = true;
+ process.emitWarning(
+ `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`,
+ 'UnsupportedCacheOverwriteWarning',
+ );
+ }
+
+ /**
+ * The guild this Manager belongs to
+ * @type {Guild}
+ */
+ this.guild = guild;
+ }
+
+ /**
+ * The number of channels in this managers cache excluding thread channels
+ * that do not count towards a guild's maximum channels restriction.
+ * @type {number}
+ * @readonly
+ */
+ get channelCountWithoutThreads() {
+ return this.cache.reduce((acc, channel) => {
+ if (ThreadChannelTypes.includes(channel.type)) return acc;
+ return ++acc;
+ }, 0);
+ }
+
+ /**
+ * The cache of this Manager
+ * @type {Collection<Snowflake, GuildChannel|ThreadChannel>}
+ * @name GuildChannelManager#cache
+ */
+
+ _add(channel) {
+ const existing = this.cache.get(channel.id);
+ if (existing) return existing;
+ this.cache.set(channel.id, channel);
+ return channel;
+ }
+
+ /**
+ * Data that can be resolved to give a Guild Channel object. This can be:
+ * * A GuildChannel object
+ * * A ThreadChannel object
+ * * A Snowflake
+ * @typedef {GuildChannel|ThreadChannel|Snowflake} GuildChannelResolvable
+ */
+
+ /**
+ * Resolves a GuildChannelResolvable to a Channel object.
+ * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve
+ * @returns {?(GuildChannel|ThreadChannel)}
+ */
+ resolve(channel) {
+ if (channel instanceof ThreadChannel) return super.resolve(channel.id);
+ return super.resolve(channel);
+ }
+
+ /**
+ * Resolves a GuildChannelResolvable to a channel id.
+ * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve
+ * @returns {?Snowflake}
+ */
+ resolveId(channel) {
+ if (channel instanceof ThreadChannel) return super.resolveId(channel.id);
+ return super.resolveId(channel);
+ }
+
+ /**
+ * Adds the target channel to a channel's followers.
+ * @param {NewsChannel|Snowflake} channel The channel to follow
+ * @param {TextChannelResolvable} targetChannel The channel where published announcements will be posted at
+ * @param {string} [reason] Reason for creating the webhook
+ * @returns {Promise<Snowflake>} Returns created target webhook id.
+ */
+ async addFollower(channel, targetChannel, reason) {
+ const channelId = this.resolveId(channel);
+ const targetChannelId = this.resolveId(targetChannel);
+ if (!channelId || !targetChannelId) throw new Error(ErrorCodes.GuildChannelResolve);
+ const { webhook_id } = await this.client.rest.post(Routes.channelFollowers(channelId), {
+ body: { webhook_channel_id: targetChannelId },
+ reason,
+ });
+ return webhook_id;
+ }
+
+ /**
+ * Options used to create a new channel in a guild.
+ * @typedef {CategoryCreateChannelOptions} GuildChannelCreateOptions
+ * @property {?CategoryChannelResolvable} [parent] Parent of the new channel
+ */
+
+ /**
+ * Creates a new channel in the guild.
+ * @param {GuildChannelCreateOptions} options Options for creating the new channel
+ * @returns {Promise<GuildChannel>}
+ * @example
+ * // Create a new text channel
+ * guild.channels.create({ name: 'new-general', reason: 'Needed a cool new channel' })
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Create a new channel with permission overwrites
+ * guild.channels.create({
+ * name: 'new-general',
+ * type: ChannelType.GuildVoice,
+ * permissionOverwrites: [
+ * {
+ * id: message.author.id,
+ * deny: [PermissionFlagsBits.ViewChannel],
+ * },
+ * ],
+ * })
+ */
+ async create({
+ name,
+ type,
+ topic,
+ nsfw,
+ bitrate,
+ userLimit,
+ parent,
+ permissionOverwrites,
+ position,
+ rateLimitPerUser,
+ rtcRegion,
+ videoQualityMode,
+ availableTags,
+ defaultReactionEmoji,
+ defaultAutoArchiveDuration,
+ defaultSortOrder,
+ defaultForumLayout,
+ reason,
+ }) {
+ parent &&= this.client.channels.resolveId(parent);
+ permissionOverwrites &&= permissionOverwrites.map(o => PermissionOverwrites.resolve(o, this.guild));
+
+ const data = await this.client.rest.post(Routes.guildChannels(this.guild.id), {
+ body: {
+ name,
+ topic,
+ type,
+ nsfw,
+ bitrate,
+ user_limit: userLimit,
+ parent_id: parent,
+ position,
+ permission_overwrites: permissionOverwrites,
+ rate_limit_per_user: rateLimitPerUser,
+ rtc_region: rtcRegion,
+ video_quality_mode: videoQualityMode,
+ available_tags: availableTags?.map(availableTag => transformGuildForumTag(availableTag)),
+ default_reaction_emoji: defaultReactionEmoji && transformGuildDefaultReaction(defaultReactionEmoji),
+ default_auto_archive_duration: defaultAutoArchiveDuration,
+ default_sort_order: defaultSortOrder,
+ default_forum_layout: defaultForumLayout,
+ },
+ reason,
+ });
+ return this.client.actions.ChannelCreate.handle(data).channel;
+ }
+
+ /**
+ * @typedef {ChannelWebhookCreateOptions} WebhookCreateOptions
+ * @property {TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel|Snowflake} channel
+ * The channel to create the webhook for
+ */
+
+ /**
+ * Creates a webhook for the channel.
+ * @param {WebhookCreateOptions} options Options for creating the webhook
+ * @returns {Promise<Webhook>} Returns the created Webhook
+ * @example
+ * // Create a webhook for the current channel
+ * guild.channels.createWebhook({
+ * channel: '222197033908436994',
+ * name: 'Snek',
+ * avatar: 'https://i.imgur.com/mI8XcpG.jpg',
+ * reason: 'Needed a cool new Webhook'
+ * })
+ * .then(console.log)
+ * .catch(console.error)
+ */
+ async createWebhook({ channel, name, avatar, reason }) {
+ const id = this.resolveId(channel);
+ if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
+ if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
+ avatar = await DataResolver.resolveImage(avatar);
+ }
+ const data = await this.client.rest.post(Routes.channelWebhooks(id), {
+ body: {
+ name,
+ avatar,
+ },
+ reason,
+ });
+ return new Webhook(this.client, data);
+ }
+
+ /**
+ * Options used to edit a guild channel.
+ * @typedef {Object} GuildChannelEditOptions
+ * @property {string} [name] The name of the channel
+ * @property {ChannelType} [type] The type of the channel (only conversion between text and news is supported)
+ * @property {number} [position] The position of the channel
+ * @property {?string} [topic] The topic of the text channel
+ * @property {boolean} [nsfw] Whether the channel is NSFW
+ * @property {number} [bitrate] The bitrate of the voice channel
+ * @property {number} [userLimit] The user limit of the voice channel
+ * @property {?CategoryChannelResolvable} [parent] The parent of the channel
+ * @property {boolean} [lockPermissions]
+ * Lock the permissions of the channel to what the parent's permissions are
+ * @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]
+ * Permission overwrites for the channel
+ * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the channel in seconds
+ * @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]
+ * The default auto archive duration for all new threads in this channel
+ * @property {?string} [rtcRegion] The RTC region of the channel
+ * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel
+ * @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel
+ * @property {?DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji
+ * @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts
+ * @property {ChannelFlagsResolvable} [flags] The flags to set on the channel
+ * @property {?SortOrderType} [defaultSortOrder] The default sort order mode to set on the channel
+ * @property {ForumLayoutType} [defaultForumLayout] The default forum layout to set on the channel
+ * @property {string} [reason] Reason for editing this channel
+ */
+
+ /**
+ * Edits the channel.
+ * @param {GuildChannelResolvable} channel The channel to edit
+ * @param {GuildChannelEditOptions} options Options for editing the channel
+ * @returns {Promise<GuildChannel>}
+ * @example
+ * // Edit a channel
+ * guild.channels.edit('222197033908436994', { name: 'new-channel' })
+ * .then(console.log)
+ * .catch(console.error);
+ */
+ async edit(channel, options) {
+ channel = this.resolve(channel);
+ if (!channel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
+
+ const parent = options.parent && this.client.channels.resolveId(options.parent);
+
+ if (options.position !== undefined) {
+ await this.setPosition(channel, options.position, { position: options.position, reason: options.reason });
+ }
+
+ let permission_overwrites = options.permissionOverwrites?.map(o => PermissionOverwrites.resolve(o, this.guild));
+
+ if (options.lockPermissions) {
+ if (parent) {
+ const newParent = this.guild.channels.resolve(parent);
+ if (newParent?.type === ChannelType.GuildCategory) {
+ permission_overwrites = newParent.permissionOverwrites.cache.map(o =>
+ PermissionOverwrites.resolve(o, this.guild),
+ );
+ }
+ } else if (channel.parent) {
+ permission_overwrites = channel.parent.permissionOverwrites.cache.map(o =>
+ PermissionOverwrites.resolve(o, this.guild),
+ );
+ }
+ }
+
+ const newData = await this.client.rest.patch(Routes.channel(channel.id), {
+ body: {
+ name: (options.name ?? channel.name).trim(),
+ type: options.type,
+ topic: options.topic,
+ nsfw: options.nsfw,
+ bitrate: options.bitrate ?? channel.bitrate,
+ user_limit: options.userLimit ?? channel.userLimit,
+ rtc_region: 'rtcRegion' in options ? options.rtcRegion : channel.rtcRegion,
+ video_quality_mode: options.videoQualityMode,
+ parent_id: parent,
+ lock_permissions: options.lockPermissions,
+ rate_limit_per_user: options.rateLimitPerUser,
+ default_auto_archive_duration: options.defaultAutoArchiveDuration,
+ permission_overwrites,
+ available_tags: options.availableTags?.map(availableTag => transformGuildForumTag(availableTag)),
+ default_reaction_emoji:
+ options.defaultReactionEmoji && transformGuildDefaultReaction(options.defaultReactionEmoji),
+ default_thread_rate_limit_per_user: options.defaultThreadRateLimitPerUser,
+ flags: 'flags' in options ? ChannelFlagsBitField.resolve(options.flags) : undefined,
+ default_sort_order: options.defaultSortOrder,
+ default_forum_layout: options.defaultForumLayout,
+ },
+ reason: options.reason,
+ });
+
+ return this.client.actions.ChannelUpdate.handle(newData).updated;
+ }
+
+ /**
+ * Sets a new position for the guild channel.
+ * @param {GuildChannelResolvable} channel The channel to set the position for
+ * @param {number} position The new position for the guild channel
+ * @param {SetChannelPositionOptions} options Options for setting position
+ * @returns {Promise<GuildChannel>}
+ * @example
+ * // Set a new channel position
+ * guild.channels.setPosition('222078374472843266', 2)
+ * .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
+ * .catch(console.error);
+ */
+ async setPosition(channel, position, { relative, reason } = {}) {
+ channel = this.resolve(channel);
+ if (!channel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
+ const updatedChannels = await setPosition(
+ channel,
+ position,
+ relative,
+ this.guild._sortedChannels(channel),
+ this.client,
+ Routes.guildChannels(this.guild.id),
+ reason,
+ );
+
+ this.client.actions.GuildChannelsPositionUpdate.handle({
+ guild_id: this.guild.id,
+ channels: updatedChannels,
+ });
+ return channel;
+ }
+
+ /**
+ * Obtains one or more guild channels from Discord, or the channel cache if they're already available.
+ * @param {Snowflake} [id] The channel's id
+ * @param {BaseFetchOptions} [options] Additional options for this fetch
+ * @returns {Promise<?GuildChannel|ThreadChannel|Collection<Snowflake, ?GuildChannel>>}
+ * @example
+ * // Fetch all channels from the guild (excluding threads)
+ * message.guild.channels.fetch()
+ * .then(channels => console.log(`There are ${channels.size} channels.`))
+ * .catch(console.error);
+ * @example
+ * // Fetch a single channel
+ * message.guild.channels.fetch('222197033908436994')
+ * .then(channel => console.log(`The channel name is: ${channel.name}`))
+ * .catch(console.error);
+ */
+ async fetch(id, { cache = true, force = false } = {}) {
+ if (id && !force) {
+ const existing = this.cache.get(id);
+ if (existing) return existing;
+ }
+
+ if (id) {
+ const data = await this.client.rest.get(Routes.channel(id));
+ // Since this is the guild manager, throw if on a different guild
+ if (this.guild.id !== data.guild_id) throw new DiscordjsError(ErrorCodes.GuildChannelUnowned);
+ return this.client.channels._add(data, this.guild, { cache });
+ }
+
+ const data = await this.client.rest.get(Routes.guildChannels(this.guild.id));
+ const channels = new Collection();
+ for (const channel of data) channels.set(channel.id, this.client.channels._add(channel, this.guild, { cache }));
+ return channels;
+ }
+
+ /**
+ * Fetches all webhooks for the channel.
+ * @param {GuildChannelResolvable} channel The channel to fetch webhooks for
+ * @returns {Promise<Collection<Snowflake, Webhook>>}
+ * @example
+ * // Fetch webhooks
+ * guild.channels.fetchWebhooks('769862166131245066')
+ * .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
+ * .catch(console.error);
+ */
+ async fetchWebhooks(channel) {
+ const id = this.resolveId(channel);
+ if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
+ const data = await this.client.rest.get(Routes.channelWebhooks(id));
+ return data.reduce((hooks, hook) => hooks.set(hook.id, new Webhook(this.client, hook)), new Collection());
+ }
+
+ /**
+ * Data that can be resolved to give a Category Channel object. This can be:
+ * * A CategoryChannel object
+ * * A Snowflake
+ * @typedef {CategoryChannel|Snowflake} CategoryChannelResolvable
+ */
+
+ /**
+ * The data needed for updating a channel's position.
+ * @typedef {Object} ChannelPosition
+ * @property {GuildChannel|Snowflake} channel Channel to update
+ * @property {number} [position] New position for the channel
+ * @property {CategoryChannelResolvable} [parent] Parent channel for this channel
+ * @property {boolean} [lockPermissions] If the overwrites should be locked to the parents overwrites
+ */
+
+ /**
+ * Batch-updates the guild's channels' positions.
+ * <info>Only one channel's parent can be changed at a time</info>
+ * @param {ChannelPosition[]} channelPositions Channel positions to update
+ * @returns {Promise<Guild>}
+ * @example
+ * guild.channels.setPositions([{ channel: channelId, position: newChannelIndex }])
+ * .then(guild => console.log(`Updated channel positions for ${guild}`))
+ * .catch(console.error);
+ */
+ async setPositions(channelPositions) {
+ channelPositions = channelPositions.map(r => ({
+ id: this.client.channels.resolveId(r.channel),
+ position: r.position,
+ lock_permissions: r.lockPermissions,
+ parent_id: r.parent !== undefined ? this.resolveId(r.parent) : undefined,
+ }));
+
+ await this.client.rest.patch(Routes.guildChannels(this.guild.id), { body: channelPositions });
+ return this.client.actions.GuildChannelsPositionUpdate.handle({
+ guild_id: this.guild.id,
+ channels: channelPositions,
+ }).guild;
+ }
+
+ /**
+ * Data returned from fetching threads.
+ * @typedef {Object} FetchedThreads
+ * @property {Collection<Snowflake, ThreadChannel>} threads The threads that were fetched
+ * @property {Collection<Snowflake, ThreadMember>} members The thread members in the received threads
+ */
+
+ /**
+ * Obtains all active thread channels in the guild.
+ * @param {boolean} [cache=true] Whether to cache the fetched data
+ * @returns {Promise<FetchedThreads>}
+ * @example
+ * // Fetch all threads from the guild
+ * message.guild.channels.fetchActiveThreads()
+ * .then(fetched => console.log(`There are ${fetched.threads.size} threads.`))
+ * .catch(console.error);
+ */
+ async fetchActiveThreads(cache = true) {
+ const data = await this.rawFetchGuildActiveThreads();
+ return GuildTextThreadManager._mapThreads(data, this.client, { guild: this.guild, cache });
+ }
+
+ /**
+ * `GET /guilds/{guild.id}/threads/active`
+ * @private
+ * @returns {Promise<RESTGetAPIGuildThreadsResult>}
+ */
+ rawFetchGuildActiveThreads() {
+ return this.client.rest.get(Routes.guildActiveThreads(this.guild.id));
+ }
+
+ /**
+ * Deletes the channel.
+ * @param {GuildChannelResolvable} channel The channel to delete
+ * @param {string} [reason] Reason for deleting this channel
+ * @returns {Promise<void>}
+ * @example
+ * // Delete the channel
+ * guild.channels.delete('858850993013260338', 'making room for new channels')
+ * .then(console.log)
+ * .catch(console.error);
+ */
+ async delete(channel, reason) {
+ const id = this.resolveId(channel);
+ if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
+ await this.client.rest.delete(Routes.channel(id), { reason });
+ this.client.actions.ChannelDelete.handle({ id });
+ }
+}
+
+module.exports = GuildChannelManager;