From e4450c8417624b71d779cb4f41692538f9165e10 Mon Sep 17 00:00:00 2001 From: sowgro Date: Sat, 2 Sep 2023 19:12:47 -0400 Subject: first commit --- .../discord.js/src/structures/GuildMember.js | 520 +++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 node_modules/discord.js/src/structures/GuildMember.js (limited to 'node_modules/discord.js/src/structures/GuildMember.js') diff --git a/node_modules/discord.js/src/structures/GuildMember.js b/node_modules/discord.js/src/structures/GuildMember.js new file mode 100644 index 0000000..8806b50 --- /dev/null +++ b/node_modules/discord.js/src/structures/GuildMember.js @@ -0,0 +1,520 @@ +'use strict'; + +const { PermissionFlagsBits } = require('discord-api-types/v10'); +const Base = require('./Base'); +const VoiceState = require('./VoiceState'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const { DiscordjsError, ErrorCodes } = require('../errors'); +const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager'); +const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField'); +const PermissionsBitField = require('../util/PermissionsBitField'); + +/** + * Represents a member of a guild on Discord. + * @implements {TextBasedChannel} + * @extends {Base} + */ +class GuildMember extends Base { + constructor(client, data, guild) { + super(client); + + /** + * The guild that this member is part of + * @type {Guild} + */ + this.guild = guild; + + /** + * The timestamp the member joined the guild at + * @type {?number} + */ + this.joinedTimestamp = null; + + /** + * The last timestamp this member started boosting the guild + * @type {?number} + */ + this.premiumSinceTimestamp = null; + + /** + * The nickname of this member, if they have one + * @type {?string} + */ + this.nickname = null; + + /** + * Whether this member has yet to pass the guild's membership gate + * @type {?boolean} + */ + this.pending = null; + + /** + * The timestamp this member's timeout will be removed + * @type {?number} + */ + this.communicationDisabledUntilTimestamp = null; + + /** + * The role ids of the member + * @name GuildMember#_roles + * @type {Snowflake[]} + * @private + */ + Object.defineProperty(this, '_roles', { value: [], writable: true }); + + if (data) this._patch(data); + } + + _patch(data) { + if ('user' in data) { + /** + * The user that this guild member instance represents + * @type {?User} + */ + this.user = this.client.users._add(data.user, true); + } + + if ('nick' in data) this.nickname = data.nick; + if ('avatar' in data) { + /** + * The guild member's avatar hash + * @type {?string} + */ + this.avatar = data.avatar; + } else if (typeof this.avatar !== 'string') { + this.avatar = null; + } + if ('joined_at' in data) this.joinedTimestamp = Date.parse(data.joined_at); + if ('premium_since' in data) { + this.premiumSinceTimestamp = data.premium_since ? Date.parse(data.premium_since) : null; + } + if ('roles' in data) this._roles = data.roles; + + if ('pending' in data) { + this.pending = data.pending; + } else if (!this.partial) { + // See https://github.com/discordjs/discord.js/issues/6546 for more info. + this.pending ??= false; + } + + if ('communication_disabled_until' in data) { + this.communicationDisabledUntilTimestamp = + data.communication_disabled_until && Date.parse(data.communication_disabled_until); + } + + if ('flags' in data) { + /** + * The flags of this member + * @type {Readonly} + */ + this.flags = new GuildMemberFlagsBitField(data.flags).freeze(); + } else { + this.flags ??= new GuildMemberFlagsBitField().freeze(); + } + } + + _clone() { + const clone = super._clone(); + clone._roles = this._roles.slice(); + return clone; + } + + /** + * Whether this GuildMember is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return this.joinedTimestamp === null; + } + + /** + * A manager for the roles belonging to this member + * @type {GuildMemberRoleManager} + * @readonly + */ + get roles() { + return new GuildMemberRoleManager(this); + } + + /** + * The voice state of this member + * @type {VoiceState} + * @readonly + */ + get voice() { + return this.guild.voiceStates.cache.get(this.id) ?? new VoiceState(this.guild, { user_id: this.id }); + } + + /** + * A link to the member's guild avatar. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + avatarURL(options = {}) { + return this.avatar && this.client.rest.cdn.guildMemberAvatar(this.guild.id, this.id, this.avatar, options); + } + + /** + * A link to the member's guild avatar if they have one. + * Otherwise, a link to their {@link User#displayAvatarURL} will be returned. + * @param {ImageURLOptions} [options={}] Options for the Image URL + * @returns {string} + */ + displayAvatarURL(options) { + return this.avatarURL(options) ?? this.user.displayAvatarURL(options); + } + + /** + * The time this member joined the guild + * @type {?Date} + * @readonly + */ + get joinedAt() { + return this.joinedTimestamp && new Date(this.joinedTimestamp); + } + + /** + * The time this member's timeout will be removed + * @type {?Date} + * @readonly + */ + get communicationDisabledUntil() { + return this.communicationDisabledUntilTimestamp && new Date(this.communicationDisabledUntilTimestamp); + } + + /** + * The last time this member started boosting the guild + * @type {?Date} + * @readonly + */ + get premiumSince() { + return this.premiumSinceTimestamp && new Date(this.premiumSinceTimestamp); + } + + /** + * The presence of this guild member + * @type {?Presence} + * @readonly + */ + get presence() { + return this.guild.presences.resolve(this.id); + } + + /** + * The displayed color of this member in base 10 + * @type {number} + * @readonly + */ + get displayColor() { + return this.roles.color?.color ?? 0; + } + + /** + * The displayed color of this member in hexadecimal + * @type {string} + * @readonly + */ + get displayHexColor() { + return this.roles.color?.hexColor ?? '#000000'; + } + + /** + * The member's id + * @type {Snowflake} + * @readonly + */ + get id() { + return this.user.id; + } + + /** + * The DM between the client's user and this member + * @type {?DMChannel} + * @readonly + */ + get dmChannel() { + return this.client.users.dmChannel(this.id); + } + + /** + * The nickname of this member, or their user display name if they don't have one + * @type {?string} + * @readonly + */ + get displayName() { + return this.nickname ?? this.user.displayName; + } + + /** + * The overall set of permissions for this member, taking only roles and owner status into account + * @type {Readonly} + * @readonly + */ + get permissions() { + if (this.user.id === this.guild.ownerId) return new PermissionsBitField(PermissionsBitField.All).freeze(); + return new PermissionsBitField(this.roles.cache.map(role => role.permissions)).freeze(); + } + + /** + * Whether the client user is above this user in the hierarchy, according to role position and guild ownership. + * This is a prerequisite for many moderative actions. + * @type {boolean} + * @readonly + */ + get manageable() { + if (this.user.id === this.guild.ownerId) return false; + if (this.user.id === this.client.user.id) return false; + if (this.client.user.id === this.guild.ownerId) return true; + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return this.guild.members.me.roles.highest.comparePositionTo(this.roles.highest) > 0; + } + + /** + * Whether this member is kickable by the client user + * @type {boolean} + * @readonly + */ + get kickable() { + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.KickMembers); + } + + /** + * Whether this member is bannable by the client user + * @type {boolean} + * @readonly + */ + get bannable() { + if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe); + return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.BanMembers); + } + + /** + * Whether this member is moderatable by the client user + * @type {boolean} + * @readonly + */ + get moderatable() { + return ( + !this.permissions.has(PermissionFlagsBits.Administrator) && + this.manageable && + (this.guild.members.me?.permissions.has(PermissionFlagsBits.ModerateMembers) ?? false) + ); + } + + /** + * Whether this member is currently timed out + * @returns {boolean} + */ + isCommunicationDisabled() { + return this.communicationDisabledUntilTimestamp > Date.now(); + } + + /** + * Returns `channel.permissionsFor(guildMember)`. Returns permissions for a member in a guild channel, + * taking into account roles and permission overwrites. + * @param {GuildChannelResolvable} channel The guild channel to use as context + * @returns {Readonly} + */ + permissionsIn(channel) { + channel = this.guild.channels.resolve(channel); + if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve); + return channel.permissionsFor(this); + } + + /** + * Edits this member. + * @param {GuildMemberEditOptions} options The options to provide + * @returns {Promise} + */ + edit(options) { + return this.guild.members.edit(this, options); + } + + /** + * Sets the flags for this member. + * @param {GuildMemberFlagsResolvable} flags The flags to set + * @param {string} [reason] Reason for setting the flags + * @returns {Promise} + */ + setFlags(flags, reason) { + return this.edit({ flags, reason }); + } + + /** + * Sets the nickname for this member. + * @param {?string} nick The nickname for the guild member, or `null` if you want to reset their nickname + * @param {string} [reason] Reason for setting the nickname + * @returns {Promise} + * @example + * // Set a nickname for a guild member + * guildMember.setNickname('cool nickname', 'Needed a new nickname') + * .then(member => console.log(`Set nickname of ${member.user.username}`)) + * .catch(console.error); + * @example + * // Remove a nickname for a guild member + * guildMember.setNickname(null, 'No nicknames allowed!') + * .then(member => console.log(`Removed nickname for ${member.user.username}`)) + * .catch(console.error); + */ + setNickname(nick, reason) { + return this.edit({ nick, reason }); + } + + /** + * Creates a DM channel between the client and this member. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise} + */ + createDM(force = false) { + return this.user.createDM(force); + } + + /** + * Deletes any DMs with this member. + * @returns {Promise} + */ + deleteDM() { + return this.user.deleteDM(); + } + + /** + * Kicks this member from the guild. + * @param {string} [reason] Reason for kicking user + * @returns {Promise} + */ + kick(reason) { + return this.guild.members.kick(this, reason); + } + + /** + * Bans this guild member. + * @param {BanOptions} [options] Options for the ban + * @returns {Promise} + * @example + * // Ban a guild member, deleting a week's worth of messages + * guildMember.ban({ deleteMessageSeconds: 60 * 60 * 24 * 7, reason: 'They deserved it' }) + * .then(console.log) + * .catch(console.error); + */ + ban(options) { + return this.guild.bans.create(this, options); + } + + /** + * Times this guild member out. + * @param {DateResolvable|null} communicationDisabledUntil The date or timestamp + * for the member's communication to be disabled until. Provide `null` to remove the timeout. + * @param {string} [reason] The reason for this timeout. + * @returns {Promise} + * @example + * // Time a guild member out for 5 minutes + * guildMember.disableCommunicationUntil(Date.now() + (5 * 60 * 1000), 'They deserved it') + * .then(console.log) + * .catch(console.error); + * @example + * // Remove the timeout of a guild member + * guildMember.disableCommunicationUntil(null) + * .then(member => console.log(`Removed timeout for ${member.displayName}`)) + * .catch(console.error); + */ + disableCommunicationUntil(communicationDisabledUntil, reason) { + return this.edit({ communicationDisabledUntil, reason }); + } + + /** + * Times this guild member out. + * @param {number|null} timeout The time in milliseconds + * for the member's communication to be disabled until. Provide `null` to remove the timeout. + * @param {string} [reason] The reason for this timeout. + * @returns {Promise} + * @example + * // Time a guild member out for 5 minutes + * guildMember.timeout(5 * 60 * 1000, 'They deserved it') + * .then(console.log) + * .catch(console.error); + */ + timeout(timeout, reason) { + return this.disableCommunicationUntil(timeout && Date.now() + timeout, reason); + } + + /** + * Fetches this GuildMember. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise} + */ + fetch(force = true) { + return this.guild.members.fetch({ user: this.id, cache: true, force }); + } + + /** + * Whether this guild member equals another guild member. It compares all properties, so for most + * comparison it is advisable to just compare `member.id === member2.id` as it is significantly faster + * and is often what most users need. + * @param {GuildMember} member The member to compare with + * @returns {boolean} + */ + equals(member) { + return ( + member instanceof this.constructor && + this.id === member.id && + this.partial === member.partial && + this.guild.id === member.guild.id && + this.joinedTimestamp === member.joinedTimestamp && + this.nickname === member.nickname && + this.avatar === member.avatar && + this.pending === member.pending && + this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp && + this.flags.bitfield === member.flags.bitfield && + (this._roles === member._roles || + (this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i]))) + ); + } + + /** + * When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object. + * @returns {string} + * @example + * // Logs: Hello from <@123456789012345678>! + * console.log(`Hello from ${member}!`); + */ + toString() { + return this.user.toString(); + } + + toJSON() { + const json = super.toJSON({ + guild: 'guildId', + user: 'userId', + displayName: true, + roles: true, + }); + json.avatarURL = this.avatarURL(); + json.displayAvatarURL = this.displayAvatarURL(); + return json; + } +} + +/** + * Sends a message to this user. + * @method send + * @memberof GuildMember + * @instance + * @param {string|MessagePayload|MessageCreateOptions} options The options to provide + * @returns {Promise} + * @example + * // Send a direct message + * guildMember.send('Hello!') + * .then(message => console.log(`Sent message: ${message.content} to ${guildMember.displayName}`)) + * .catch(console.error); + */ + +TextBasedChannel.applyToClass(GuildMember); + +exports.GuildMember = GuildMember; + +/** + * @external APIGuildMember + * @see {@link https://discord.com/developers/docs/resources/guild#guild-member-object} + */ -- cgit v1.2.3