UNPKG

@hedystia/discord

Version:

JavaScript library for interacting with the Discord API

429 lines (389 loc) 16 kB
const {ChannelType} = require("../Util/Constants"); const Base = require("../Base/base"); const PermissionOverwriteManager = require("../Managers/PermissionOverwriteManager"); const {RaidenCol} = require("../Util/@Collections/RaidenCol"); const Invite = require("./Invite"); const Permissions = require("../Util/Permissions"); const Webhook = require("./Webhook"); const Util = require("../Util/Util"); const ChannelFlags = require("../Util/ChannelFlags"); const Snowflake = require("../Util/Snowflake"); /** * Represents a channel in a guild or a direct message. * @class * @extends Base * @param {Object} [data] - The data for the channel. * @param {string} guildId - The ID of the guild that the channel belongs to. * @param {Client} client - The client instance. */ class Channel extends Base { /** * Constructs a new Channel object. * @constructor * @param {Object} [data] - The data object containing the channel information. * @param {string} guildId - The ID of the guild that the channel belongs to. * @param {Client} client - The client instance. */ constructor(data = {}, guildId, client) { super(client); this.partial = data.partial ?? false; this.banner = data.banner ?? null; this.id = data.id ?? null; this.name = data.name ?? null; this.type = (typeof data.type === "number" ? ChannelType[data.type] : data.type) ?? null; this.guildId = guildId; this.position = data.position ?? null; this.topic = data.topic ?? null; this.parentId = data.parent_id ?? null; this.createdAt = data.id ? Snowflake.deconstruct(data.id).createdAt : null; this.createdTimestamp = this.createdAt?.getTime() ?? null; this.defaultAutoArchiveDuration = data.default_auto_archive_duration ?? null; this.permissionOverwrites = new PermissionOverwriteManager(this.id, data.permission_overwrites, this.client); this.flags = new ChannelFlags(data.flags ? BigInt(data.flags) : 0n); } /** * Fetches the channels using the provided options. * @param {Object} [options] - The options to be used for fetching the channels. * @returns {Promise} - A promise that resolves to the fetched channels. */ async fetch(options = {}) { return await this.client.channels.fetch(this, options); } /** * Deletes the channel with the specified reason. * @param {string} reason - The reason for deleting the channel. * @returns {Promise<void>} - A promise that resolves when the channel is deleted. */ async delete(reason) { return await this.client.channels.delete(this, reason); } /** * Edits the properties of a channel using the provided options. * @param {Object} options - The options object containing the properties to edit. * @returns {Promise} A promise that resolves when the channel has been successfully edited. */ async edit(options) { return await this.client.channels.edit(this, options); } /** * Fetches the invites for the channel. * @async * @returns {Promise<RaidenCol>} A promise that resolves to a collection of invites. */ async fetchInvites() { const invite = await this.client.api.get(`${this.client.root}/channels/${this.id}/invites`); return new RaidenCol(invite?.map((o) => [o.code, new Invite(o, this.guildId, this.client)])); } /** * Creates an invite for the current channel using the specified options. * @param {Object} options - The options for creating the invite. * @returns {Promise<Invite>} A promise that resolves to the created invite. */ async createInvite(options) { return await this.client.channels.createInvite(this, options); } /** * Clones the channel. * @returns {Promise<Channel>} A promise that resolves to the cloned channel. */ async clone() { return await this.guild?.channels.clone(this.id); } /** * Checks if the type of the object is "Guild_Text". * @returns {boolean} - true if the type is "Guild_Text", false otherwise. */ isGuildText() { if (["Guild_Text"].includes(this.type)) return true; return false; } /** * Checks if the type of the object is "Dm". * @returns {boolean} - true if the type is "Dm", false otherwise. */ isDM() { if (["Dm"].includes(this.type)) return true; return false; } /** * Checks if the current stage is a Guild Stage Voice. * @returns {boolean} - True if the current stage is a Guild Stage Voice, false otherwise. */ isStage() { if (["Guild_Stage_Voice"].includes(this.type)) return true; return false; } /** * Checks if the current page is a forum page. * @returns {boolean} - true if the page is a forum page, false otherwise. */ isForum() { if (["Guild_Forum"].includes(this.type)) return true; return false; } /** * Checks if the current object is of media type. * @returns {boolean} - true if the object is of media type, false otherwise. */ isMedia() { if (["Guild_Media"].includes(this.type)) return true; return false; } /** * Checks if the type of the object is "Guild_Voice". * @returns {boolean} - true if the type is "Guild_Voice", false otherwise. */ isGuildVoice() { if (["Guild_Voice"].includes(this.type)) return true; return false; } /** * Checks if the current type is "Guild_News". * @returns {boolean} - Returns true if the type is "Guild_News", otherwise returns false. */ isNews() { if (["Guild_News"].includes(this.type)) return true; return false; } /** * Checks if the current object is of the category type. * @returns {boolean} - true if the object is of the category type, false otherwise. */ isCategory() { if (["Guild_Category"].includes(this.type)) return true; return false; } /** * Checks if the current text is of a specific type. * @returns {boolean} - True if the text is of a specific type, false otherwise. */ isText() { if (["Guild_Text", "Dm", "Guild_News", "Guild_News_Thread", "Guild_Public_Thread", "Guild_Private_Thread", "Guild_Voice"].includes(this.type)) return true; return false; } /** * Checks if the current thread is a private, news, or public guild thread. * @returns {boolean} - True if the thread is a private, news, or public guild thread, false otherwise. */ isThread() { if (["Guild_Private_Thread", "Guild_News_Thread", "Guild_Public_Thread"].includes(this.type)) return true; return false; } /** * Checks if the current object is of type "Guild_Voice" or "Guild_Stage_Voice". * @returns {boolean} - true if the object is of type "Guild_Voice" or "Guild_Stage_Voice", false otherwise. */ isVoice() { if (["Guild_Voice", "Guild_Stage_Voice"].includes(this.type)) return true; return false; } /** * Checks if the current object is a directory. * @returns {boolean} - Returns true if the object is a directory, false otherwise. */ isDirectory() { if (["Guild_Directory"].includes(this.type)) return true; return false; } /** * Checks if the current context is within a guild. * @returns {boolean} - True if the context is within a guild, false otherwise. */ inGuild() { if (this.guildId) return true; return false; } /** * Checks if the guild is cached in the client's guild cache. * @returns {boolean} - true if the guild is cached, false otherwise. */ inCachedGuild() { if (this.client.guilds.cache.has(this.guildId)) return true; return false; } /** * Checks if the current channel is the rules channel for the guild. * @returns {boolean} - true if the current channel is the rules channel, false otherwise. */ isRuleChannel() { if (this.guild?.rulesChannelId === this.id) return true; return false; } /** * Checks if the current channel is the system channel of the guild. * @returns {boolean | null} - Returns true if the channel is the system channel, * false if it is not, and null if the guild does not have a system channel. */ isSystemChannel() { if (!this.guild?.systemChannelId) return null; if (this.guild?.systemChannelId === this.id) return true; return false; } /** * Get the parent channel of this channel. * @returns {Channel | null} The parent channel if it exists, otherwise null. */ get parent() { return this.client.channels._add(this.parentId) ?? null; } /** * Returns the URL of the channel banner image. * @param {Object} options - Optional parameters for generating the URL. * @param {boolean} [options.dynamic] - Whether to generate a dynamic URL. * @param {string} [options.size] - The desired size of the banner image. * @param {string} [options.format] - The desired format of the banner image. * @returns {string | null} The URL of the channel banner image, or null if no banner is set. */ bannerURL(options = {}) { if (!this.banner) return null; return this.client.cdn.ChannelBanner(this.banner, options.dynamic, options.size, options.format, this.id); } /** * Sets the name and reason for an object. * @param {string} name - The new name to set. * @param {string} reason - The reason for setting the new name. * @returns {Promise} - A promise that resolves when the name and reason are successfully set. */ async setName(name, reason) { return await this.edit({name, reason}); } /** * Sets the type and reason of an object asynchronously. * @param {any} type - The type to set. * @param {any} reason - The reason to set. * @returns {Promise<any>} - A promise that resolves to the edited object. */ async setType(type, reason) { return await this.edit({type, reason}); } /** * Sets the topic of the current object and provides a reason for the change. * @param {string} topic - The new topic to set. * @param {string} reason - The reason for changing the topic. * @returns {Promise} - A promise that resolves when the topic is successfully set. */ async setTopic(topic, reason) { return await this.edit({topic, reason}); } /** * Sets the position of an object and provides a reason for the change. * @param {any} position - The new position of the object. * @param {string} reason - The reason for the position change. * @returns {Promise<void>} - A promise that resolves when the position is successfully set. */ async setPosition(position, reason) { return await this.edit({position, reason}); } /** * Sets the parent of an object and provides a reason for the change. * @param {any} parent - The new parent object. * @param {string} reason - The reason for setting the new parent. * @returns {Promise} A promise that resolves when the parent is successfully set. */ async setParent(parent, reason) { return await this.edit({parent, reason}); } /** * Sets the default auto-archive duration for a specific item. * @param {number} defaultAutoArchiveDuration - The new default auto-archive duration to set. * @param {string} reason - The reason for setting the new default auto-archive duration. * @returns {Promise} - A promise that resolves when the default auto-archive duration is successfully set. */ async setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) { return await this.edit({defaultAutoArchiveDuration, reason}); } /** * Sets the flags and reason for an object. * @param {any} flags - The flags to set. * @param {string} reason - The reason for setting the flags. * @returns {Promise<void>} - A promise that resolves when the flags are set. */ async setFlags(flags, reason) { return await this.edit({flags, reason}); } /** * Locks the permissions for the current object. * @async * @returns {Promise<void>} A promise that resolves when the permissions are locked. */ async lockPermissions() { const permissionOverwrites = this.parent.permissionOverwrites.cache.mapVal((o) => o); return await this.edit({permissionOverwrites}); } /** * Retrieves the guild associated with this guildId. * @returns The guild object if found, otherwise null. */ get guild() { return this.client.guilds._add(this.guildId) ?? null; } /** * Retrieves the permissions for a given user or role in the guild. * @param {string | GuildMember | Role} userOrRole - The user or role to retrieve permissions for. * @returns {Permissions} - The permissions for the user or role. * @throws {RangeError} - If the user or role is not found in the cache or is invalid. */ permissionsFor(userOrRole) { userOrRole = typeof userOrRole === "string" ? userOrRole : userOrRole?.user?.id ?? userOrRole?.id; const overwrites = this.permissionOverwrites.cache; const roles = this.guild.roles.cache.get(userOrRole); const member = this.guild.members.cache.get(userOrRole); if (roles) { if (roles.permissions.has(Permissions.Flags.Administrator)) return new Permissions(Permissions.All).freeze(); const roleOverwrites = overwrites.filter((o) => o.type === "Role" && roles.id === o.id); const rolePerm = new Permissions( roleOverwrites?.mapVal((o) => o.allow), Permissions.defaultBit ); return rolePerm; } if (member) { if (this.guild.ownerId === member.id) return new Permissions(Permissions.All).freeze(); if (member.permissions.has(Permissions.Flags.Administrator)) return new Permissions(Permissions.Flags.Administrator).freeze(); const memberOverwrites = overwrites.filter((o) => o.type === "Member" && o.id === member.id); const roleOverwrites = overwrites.filter((o) => o.type === "Role" && member.roles.cache.keyArray()?.includes(o.id)); const memberPerm = new Permissions( memberOverwrites?.mapVal((overwrites) => overwrites.allow), Permissions.defaultBit ); const rolePerms = new Permissions( roleOverwrites?.mapVal((overwrites) => overwrites.allow), Permissions.defaultBit ); memberPerm.add(member.permissions); memberPerm.add(rolePerms); return memberPerm; } throw new RangeError(`Role or GuildMember not found in cache or invalid.`); } /** * Fetches the webhooks associated with the channel. * @returns {Promise<RaidenCol>} A promise that resolves to a collection of webhooks. */ async fetchWebhooks() { const webhooks = await this.client.api.get(`${this.client.root}/channels/${this.id}/webhooks`); return new RaidenCol(webhooks?.map((o) => [o.id, new Webhook(o, this.guildId, this.client)])); } /** * Creates a webhook for the current channel. * @param {Object} [options] - Optional parameters for creating the webhook. * @param {string} [options.reason] - The reason for creating the webhook. * @param {string} [options.name] - The name of the webhook. * @param {string} [options.avatar] - The avatar URL or file path of the webhook. * @returns {Promise<Webhook>} A promise that resolves with the created webhook. */ async createWebhook(options = {}) { const {reason} = options; const body = { name: options.name ?? undefined, avatar: options.avatar ? await Util.generateDataURI(options.avatar) : undefined, }; const webhook = await this.client.api.post(`${this.client.root}/channels/${this.id}/webhooks`, { reason, body, }); return new Webhook(webhook, this.guildId, this.client); } } module.exports = Channel;