diff --git a/src/structures/PartialGroupDMChannel.js b/src/structures/PartialGroupDMChannel.js deleted file mode 100644 index 0545b1a..00000000 --- a/src/structures/PartialGroupDMChannel.js +++ /dev/null @@ -1,449 +0,0 @@ -'use strict'; - -const { Collection } = require('@discordjs/collection'); -const { joinVoiceChannel, entersState, VoiceConnectionStatus } = require('@discordjs/voice'); -const { Channel } = require('./Channel'); -const Invite = require('./Invite'); -const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const { Error } = require('../errors'); -const MessageManager = require('../managers/MessageManager'); -const { Status, Opcodes } = require('../util/Constants'); -const DataResolver = require('../util/DataResolver'); - -/** - * Represents a Partial Group DM Channel on Discord. - * @extends {Channel} - */ -class PartialGroupDMChannel extends Channel { - constructor(client, data) { - super(client, data); - - // No flags are present when fetching partial group DM channels. - this.flags = null; - - /** - * The name of this Group DM Channel - * @type {?string} - */ - this.name = null; - - /** - * The hash of the channel icon - * @type {?string} - */ - this.icon = null; - - /** - * Messages data - * @type {Collection} - */ - this.messages = new MessageManager(this); - - /** - * Last Message ID - * @type {?Snowflake} - */ - this.lastMessageId = null; - - /** - * Last Pin Timestamp - * @type {UnixTimestamp} - */ - this.lastPinTimestamp = null; - - /** - * Owner ID - * @type {?Snowflake} - */ - this.ownerId = null; - - /** - * Invites fetch - * @type {Collection} - */ - this.invites = new Collection(); - - this._recipients = []; - - this._patch(data); - } - - /** - * The recipients of this Group DM Channel. - * @type {Collection} - * @readonly - */ - get recipients() { - const collect = new Collection(); - this._recipients.map(recipient => collect.set(recipient.id, this.client.users._add(recipient))); - collect.set(this.client.user.id, this.client.user); - return collect; - } - - /** - * The owner of this Group DM Channel - * @type {?User} - * @readonly - */ - get owner() { - return this.client.users.cache.get(this.ownerId); - } - - /** - * - * @param {Object} data Channel Data - * @private - */ - _patch(data) { - super._patch(data); - if ('recipients' in data && Array.isArray(data.recipients)) { - this._recipients = data.recipients; - } - if ('last_pin_timestamp' in data) { - const date = new Date(data.last_pin_timestamp); - this.lastPinTimestamp = date.getTime(); - } - if ('last_message_id' in data) { - this.lastMessageId = data.last_message_id; - } - if ('owner_id' in data) { - this.ownerId = data.owner_id; - } - if ('name' in data) { - this.name = data.name; - } - if ('icon' in data) { - this.icon = data.icon; - } - } - - /** - * Edit channel data - * @param {Object} data name, icon owner - * @returns {Promise} - * @private - */ - async edit(data) { - const _data = {}; - if ('name' in data) _data.name = data.name?.trim() ?? null; - if (typeof data.icon !== 'undefined') { - _data.icon = await DataResolver.resolveImage(data.icon); - } - if ('owner' in data) { - _data.owner = data.owner; - } - const newData = await this.client.api.channels(this.id).patch({ - data: _data, - }); - - return this.client.actions.ChannelUpdate.handle(newData).updated; - } - - /** - * The URL to this channel's icon. - * @param {StaticImageURLOptions} [options={}] Options for the Image URL - * @returns {?string} - */ - iconURL({ format, size } = {}) { - return this.icon && this.client.rest.cdn.GDMIcon(this.id, this.icon, format, size); - } - - /** - * Adds a user to this Group DM Channel. - * @param {UserResolvable} user User to add to the group - * @returns {Promise} - */ - async addMember(user) { - const userId = this.client.users.resolveId(user); - user = this.client.users.resolve(userId); - if (!userId) { - return Promise.reject(new TypeError('User is not a User or User ID')); - } - // API - // if (this.recipients.get(userId)) return Promise.reject(new Error('USER_ALREADY_IN_GROUP_DM_CHANNEL')); // Fails sometimes if member leaves recently (ex. user leave msg's channel used for adding) - await this.client.api.channels[this.id].recipients[userId].put(); - this._recipients.push(user); - return this; - } - - /** - * Removes a user from this Group DM Channel. - * @param {UserResolvable} user User to remove from the group - * @returns {Promise} - */ - async removeMember(user) { - if (this.ownerId !== this.client.user.id) { - return Promise.reject(new Error('NOT_OWNER_GROUP_DM_CHANNEL')); - } - user = this.client.users.resolveId(user); - if (!user) { - return Promise.reject(new TypeError('User is not a User or User ID')); - } - // API - // if (!this.recipients.get(user)) return Promise.reject(new Error('USER_NOT_IN_GROUP_DM_CHANNEL')); - await this.client.api.channels[this.id].recipients[user].delete(); - this._recipients = this._recipients.filter(r => r.id !== user); - return this; - } - - /** - * Renames this Group DM Channel. - * @param {?string} name Name of the channel - * @returns {Promise} - */ - setName(name) { - return this.edit({ name }); - } - - /** - * Sets the icon of this Group DM Channel. - * @param {?(Base64Resolvable|BufferResolvable)} icon Icon of the channel - * @returns {Promise} - */ - setIcon(icon) { - return this.edit({ icon }); - } - - /** - * Changes the owner of this Group DM Channel. - * @param {UserResolvable} user User to transfer ownership to - * @returns {Promise} - */ - setOwner(user) { - const id = this.client.users.resolveId(user); - if (!id) { - throw new TypeError('User is not a User or User ID'); - } - if (this.ownerId !== this.client.user.id) { - throw new Error('NOT_OWNER_GROUP_DM_CHANNEL'); - } - if (this.ownerId === id) { - return this; - } - return this.edit({ owner: id }); - } - - /** - * Gets the invite for this Group DM Channel. - * @returns {Promise} - */ - async getInvite() { - const inviteCode = await this.client.api.channels(this.id).invites.post({ - data: { - max_age: 86400, - }, - }); - const invite = new Invite(this.client, inviteCode); - this.invites.set(invite.code, invite); - return invite; - } - - /** - * Get all the invites for this Group DM Channel. - * @param {boolean} force Using API to fetch invites or cache - * @returns {Promise>} - */ - async fetchInvite(force = false) { - if (this.ownerId !== this.client.user.id) { - return Promise.reject(new Error('NOT_OWNER_GROUP_DM_CHANNEL')); - } - if (!force && this.invites.size) return this.invites; - const invites = await this.client.api.channels(this.id).invites.get(); - await Promise.all(invites.map(invite => this.invites.set(invite.code, new Invite(this.client, invite)))); - return this.invites; - } - - /** - * Delete invites from this Group DM Channel. - * @param {Invite} invite Invite to add to the channel - * @returns {Promise} - */ - async removeInvite(invite) { - if (this.ownerId !== this.client.user.id) { - return Promise.reject(new Error('NOT_OWNER_GROUP_DM_CHANNEL')); - } - if (!(invite instanceof Invite)) { - return Promise.reject(new TypeError('Invite is not an instance of Discord.Invite')); - } - await this.client.api.channels(this.id).invites[invite.code].delete(); - this.invites.delete(invite.code); - return this; - } - - /** - * Leave this Group DM Channel. - * @param {?boolean} slient Leave without notifying other members - * @returns {Promise} - * @example - * // Delete the channel - * channel.delete() - * .then(console.log) - * .catch(console.error); - */ - async delete(slient = false) { - if (typeof slient === 'boolean' && slient) { - await this.client.api.channels(this.id).delete({ - query: { - silent: true, - }, - }); - } else { - await this.client.api.channels(this.id).delete(); - } - return this; - } - - // These are here only for documentation purposes - they are implemented by TextBasedChannel - /* eslint-disable no-empty-function */ - get lastMessage() {} - get lastPinAt() {} - send() {} - sendTyping() {} - - /** - * @typedef {Object} CallOptions - * @property {boolean} [selfDeaf] Whether to deafen yourself - * @property {boolean} [selfMute] Whether to mute yourself - * @property {boolean} [ring=true] Emit a ringtone - */ - // Testing feature: Call - // URL: https://discord.com/api/v9/channels/DMchannelId/call/ring - /** - * Call this Group DMChannel. Return discordjs/voice VoiceConnection - * @param {CallOptions} options Options for the call - * @returns {Promise} - */ - call(options = {}) { - options = Object.assign( - { - ring: true, - }, - options || {}, - ); - return new Promise((resolve, reject) => { - if (!this.client.options.patchVoice) { - reject( - new Error( - 'VOICE_NOT_PATCHED', - 'Enable voice patching in client options\nhttps://discordjs-self-v13.netlify.app/#/docs/docs/main/typedef/ClientOptions', - ), - ); - } else { - if (options.ring) { - this.client.api.channels(this.id).call.ring.post({ - data: { - recipients: null, - }, - }); - } - const connection = joinVoiceChannel({ - channelId: this.id, - guildId: null, - adapterCreator: this.voiceAdapterCreator, - selfDeaf: options.selfDeaf ?? false, - selfMute: options.selfMute ?? false, - }); - entersState(connection, VoiceConnectionStatus.Ready, 30000) - .then(connection => { - resolve(connection); - }) - .catch(err => { - connection.destroy(); - reject(err); - }); - } - }); - } - - /** - * Ring the user's phone / PC (call) - * @param {UserResolvable[]} recipients Array of recipients - * @returns {Promise} - */ - ring(recipients) { - if (!recipients || !Array.isArray(recipients) || recipients.length == 0) recipients = null; - recipients = recipients.map(r => this.client.users.resolveId(r)).filter(r => r && this.recipients.get(r)); - return this.client.api.channels(this.id).call.ring.post({ - data: { - recipients, - }, - }); - } - - /** - * Sync VoiceState of this Group DMChannel. - * @returns {undefined} - */ - sync() { - this.client.ws.broadcast({ - op: Opcodes.DM_UPDATE, - d: { - channel_id: this.id, - }, - }); - } - /** - * The user in this voice-based channel - * @type {Collection} - * @readonly - */ - get voiceUsers() { - const coll = new Collection(); - for (const state of this.client.voiceStates.cache.values()) { - if (state.channelId === this.id && state.user) { - coll.set(state.id, state.user); - } - } - return coll; - } - /** - * Get connection to current call - * @type {?VoiceConnection} - * @readonly - */ - get voiceConnection() { - const check = this.client.callVoice?.joinConfig?.channelId == this.id; - if (check) { - return this.client.callVoice; - } - return null; - } - /** - * Get current shard - * @type {WebSocketShard} - * @readonly - */ - get shard() { - return this.client.ws.shards.first(); - } - /** - * The voice state adapter for this client that can be used with @discordjs/voice to play audio in DM / Group DM channels. - * @type {?Function} - * @readonly - */ - get voiceAdapterCreator() { - return methods => { - this.client.voice.adapters.set(this.id, methods); - return { - sendPayload: data => { - if (this.shard.status !== Status.READY) return false; - this.shard.send(data); - return true; - }, - destroy: () => { - this.client.voice.adapters.delete(this.id); - }, - }; - }; - } -} - -TextBasedChannel.applyToClass(PartialGroupDMChannel, true, [ - 'bulkDelete', - 'fetchWebhooks', - 'createWebhook', - 'setRateLimitPerUser', - 'setNSFW', -]); - -module.exports = PartialGroupDMChannel;