-
-
Notifications
You must be signed in to change notification settings - Fork 4k
feat(Interactions)!: member objects for uncached guilds #10195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
advaith1
wants to merge
11
commits into
discordjs:main
Choose a base branch
from
advaith1:uncached-guild-members
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
85025d6
feat(Interactions): member objects for uncached guilds
advaith1 e205862
fix: fix review issues
advaith1 e9cb300
refactor: default export
advaith1 d253966
Merge remote-tracking branch 'upstream/main' into uncached-guild-members
advaith1 1c561a1
refactor: remove deprecated api object compat fields
advaith1 e2a0a2d
refactor: rename to MinimalGuildMember
advaith1 4bc5300
refactor: make GuildMember extend MinimalGuildMember
advaith1 01ea164
try to fix format
advaith1 ea2fedc
feat: update select menus, fix docs and types
advaith1 d634c81
fix: initialize roleIds to []
advaith1 f83626d
feat: add isInCachedGuild typeguard
advaith1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
328 changes: 328 additions & 0 deletions
328
packages/discord.js/src/structures/UncachedGuildMember.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,328 @@ | ||
'use strict'; | ||
|
||
const Base = require('./Base'); | ||
const TextBasedChannel = require('./interfaces/TextBasedChannel'); | ||
const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField'); | ||
const PermissionsBitField = require('../util/PermissionsBitField'); | ||
|
||
/** | ||
* Represents a member of a guild on Discord. Used in interactions from guilds that aren't cached. | ||
* Backwards compatible with {@link APIGuildMember}. | ||
* @implements {TextBasedChannel} | ||
* @extends {Base} | ||
*/ | ||
class UncachedGuildMember extends Base { | ||
constructor(client, data, guildId) { | ||
super(client); | ||
|
||
/** | ||
* The ID of the guild that this member is part of | ||
* @type {string} | ||
*/ | ||
this.guildId = guildId; | ||
|
||
/** | ||
* The user that this guild member instance represents | ||
* @type {User} | ||
*/ | ||
this.user = this.client.users._add(data.user, true); | ||
|
||
/** | ||
* The nickname of this member, if they have one | ||
* @type {?string} | ||
*/ | ||
this.nickname = data.nick; | ||
|
||
/** | ||
* The guild member's avatar hash | ||
* @type {?string} | ||
*/ | ||
this.avatar = data.avatar; | ||
|
||
/** | ||
* The role ids of the member | ||
* @name UncachedGuildMember#roleIds | ||
* @type {Snowflake[]} | ||
*/ | ||
this.roleIds = data.roles; | ||
|
||
/** | ||
* The timestamp the member joined the guild at | ||
* @type {number} | ||
*/ | ||
this.joinedTimestamp = Date.parse(data.joined_at); | ||
|
||
/** | ||
* The timestamp the member joined the guild at, as an ISO8601 timestamp | ||
* @type {string} | ||
* @deprecated Use {@link UncachedGuildMember#joinedTimestamp} or {@link UncachedGuildMember#joinedAt} instead | ||
*/ | ||
this.joined_at = data.joined_at; | ||
|
||
/** | ||
* The last timestamp this member started boosting the guild | ||
* @type {?number} | ||
*/ | ||
this.premiumSinceTimestamp = data.premium_since ? Date.parse(data.premium_since) : null; | ||
|
||
/** | ||
* The last timestamp this member started boosting the guild, as an ISO8601 timestamp | ||
* @type {?string} | ||
* @deprecated Use {@link UncachedGuildMember#premiumSinceTimestamp} | ||
* or {@link UncachedGuildMember#premiumSince} instead | ||
advaith1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
this.premium_since = data.premium_since; | ||
|
||
/** | ||
* Whether the user is deafened in voice channels | ||
* @type {boolean | undefined} | ||
*/ | ||
this.deaf = data.deaf; | ||
|
||
/** | ||
* Whether the user is muted in voice channels | ||
* @type {boolean | undefined} | ||
*/ | ||
this.mute = data.mute; | ||
|
||
/** | ||
* The flags of this member | ||
* @type {Readonly<GuildMemberFlagsBitField>} | ||
*/ | ||
this.parsedFlags = new GuildMemberFlagsBitField(data.flags).freeze(); | ||
|
||
/** | ||
* The raw flags of this member | ||
* @type {number} | ||
* @deprecated Use {@link UncachedGuildMember#parsedFlags} instead. | ||
* This field will be replaced with parsedFlags in the future. | ||
*/ | ||
this.flags = data.flags; | ||
|
||
/** | ||
* Whether this member has yet to pass the guild's membership gate | ||
* @type {?boolean} | ||
*/ | ||
this.pending = data.pending; | ||
|
||
/** | ||
* The total permissions of the member in this channel, including overwrites | ||
* @type {Readonly<PermissionsBitField>} | ||
*/ | ||
this.parsedPermissions = new PermissionsBitField(data.permissions).freeze(); | ||
|
||
/** | ||
* Raw total permissions of the member in this channel, including overwrites | ||
* @type {?string} | ||
* @deprecated Use {@link UncachedGuildMember#parsedPermissions} instead. | ||
* This field will be replaced with parsedPermissions in the future. | ||
*/ | ||
this.permissions = data.permissions; | ||
|
||
/** | ||
* The timestamp this member's timeout will be removed | ||
* @type {?number} | ||
*/ | ||
this.communicationDisabledUntilTimestamp = | ||
data.communication_disabled_until && Date.parse(data.communication_disabled_until); | ||
|
||
/** | ||
* The timestamp this member's timeout will be removed, as an ISO8601 timestamp | ||
* @type {?string} | ||
* @deprecated Use {@link UncachedGuildMember#communicationDisabledUntilTimestamp} | ||
* or {@link UncachedGuildMember#communicationDisabledUntil} instead | ||
*/ | ||
this.communication_disabled_until = data.communication_disabled_until; | ||
|
||
/** | ||
* Whether this UncachedGuildMember is a partial (always true, as it is a partial GuildMember) | ||
* @type {boolean} | ||
* @readonly | ||
*/ | ||
this.partial = true; | ||
} | ||
|
||
/** | ||
* 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.guildId, 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 member's id | ||
* @type {Snowflake} | ||
* @readonly | ||
*/ | ||
get id() { | ||
return this.user.id; | ||
} | ||
vladfrangu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* 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} | ||
advaith1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @readonly | ||
*/ | ||
get displayName() { | ||
return this.nickname ?? this.user.displayName; | ||
} | ||
|
||
/** | ||
* The nickname of the member | ||
* @name UncachedGuildMember#nick | ||
* @type {?string} | ||
* @deprecated Use {@link UncachedGuildMember#nickname} instead | ||
*/ | ||
get nick() { | ||
return this.nickname; | ||
} | ||
Jiralite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* The role ids of the member | ||
* @name UncachedGuildMember#roles | ||
* @type {Snowflake[]} | ||
* @deprecated Use {@link UncachedGuildMember#roleIds} instead | ||
*/ | ||
get roles() { | ||
return this.roleIds; | ||
} | ||
|
||
/** | ||
* Whether this member is currently timed out | ||
* @returns {boolean} | ||
*/ | ||
isCommunicationDisabled() { | ||
return this.communicationDisabledUntilTimestamp > Date.now(); | ||
} | ||
|
||
/** | ||
* 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<DMChannel>} | ||
*/ | ||
createDM(force = false) { | ||
return this.user.createDM(force); | ||
} | ||
|
||
/** | ||
* Deletes a DM channel (if one exists) between the client and the member. Resolves with the channel if successful. | ||
* @returns {Promise<DMChannel>} | ||
*/ | ||
deleteDM() { | ||
return this.user.deleteDM(); | ||
} | ||
|
||
/** | ||
* 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 {UncachedGuildMember} member The member to compare with | ||
* @returns {boolean} | ||
*/ | ||
equals(member) { | ||
return ( | ||
member instanceof this.constructor && | ||
this.id === member.id && | ||
this.partial === member.partial && | ||
this.guildId === member.guildId && | ||
this.joinedTimestamp === member.joinedTimestamp && | ||
this.nickname === member.nickname && | ||
this.avatar === member.avatar && | ||
this.pending === member.pending && | ||
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp && | ||
this.parsedFlags.bitfield === member.parsedFlags.bitfield && | ||
advaith1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(this.roleIds === member.roleIds || | ||
(this.roleIds.length === member.roleIds.length && this.roleIds.every((role, i) => role === member.roleIds[i]))) | ||
); | ||
} | ||
|
||
/** | ||
* When concatenated with a string, this automatically returns the user's mention | ||
* instead of the UncachedGuildMember object. | ||
* @returns {string} | ||
* @example | ||
* // Logs: Hello from <@123456789012345678>! | ||
* console.log(`Hello from ${member}!`); | ||
*/ | ||
toString() { | ||
return this.user.toString(); | ||
} | ||
|
||
toJSON() { | ||
const json = super.toJSON({ | ||
guildId: true, | ||
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 UncachedGuildMember | ||
* @instance | ||
* @param {string|MessagePayload|MessageCreateOptions} options The options to provide | ||
* @returns {Promise<Message>} | ||
* @example | ||
* // Send a direct message | ||
* UncachedGuildMember.send('Hello!') | ||
* .then(message => console.log(`Sent message: ${message.content} to ${guildMember.displayName}`)) | ||
advaith1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* .catch(console.error); | ||
*/ | ||
|
||
TextBasedChannel.applyToClass(UncachedGuildMember); | ||
advaith1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
module.exports = UncachedGuildMember; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.