fix(ThreadMembersUpdate): Only emit added & removed thread members (#7539)

This commit is contained in:
Jiralite
2022-03-06 19:42:33 +00:00
committed by GitHub
parent e71c76c7f7
commit c12d61a342
7 changed files with 77 additions and 21 deletions

View File

@@ -96,6 +96,7 @@ body:
- Message - Message
- Reaction - Reaction
- GuildScheduledEvent - GuildScheduledEvent
- ThreadMember
multiple: true multiple: true
validations: validations:
required: true required: true

View File

@@ -110,6 +110,10 @@ class GenericAction {
Partials.GuildScheduledEvent, Partials.GuildScheduledEvent,
); );
} }
getThreadMember(id, manager) {
return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false);
}
} }
module.exports = GenericAction; module.exports = GenericAction;

View File

@@ -1,5 +1,6 @@
'use strict'; 'use strict';
const { Collection } = require('@discordjs/collection');
const Action = require('./Action'); const Action = require('./Action');
const Events = require('../../util/Events'); const Events = require('../../util/Events');
@@ -8,24 +9,35 @@ class ThreadMembersUpdateAction extends Action {
const client = this.client; const client = this.client;
const thread = client.channels.cache.get(data.id); const thread = client.channels.cache.get(data.id);
if (thread) { if (thread) {
const old = thread.members.cache.clone();
thread.memberCount = data.member_count; thread.memberCount = data.member_count;
const addedMembers = new Collection();
const removedMembers = new Collection();
data.added_members?.forEach(rawMember => { data.added_members?.reduce(
thread.members._add(rawMember); (_addedMembers, addedMember) => _addedMembers.set(addedMember.user_id, thread.members._add(addedMember)),
}); addedMembers,
);
data.removed_member_ids?.forEach(memberId => { data.removed_member_ids?.reduce((removedMembersIds, removedMembersId) => {
thread.members.cache.delete(memberId); const threadMember = this.getThreadMember(removedMembersId, thread.members);
}); if (threadMember) removedMembersIds.set(threadMember.id, threadMember);
thread.members.cache.delete(removedMembersId);
return removedMembersIds;
}, removedMembers);
if (addedMembers.size === 0 && removedMembers.size === 0) {
// Uncached thread member(s) left.
return {};
}
/** /**
* Emitted whenever members are added or removed from a thread. Requires `GUILD_MEMBERS` privileged intent * Emitted whenever members are added or removed from a thread. Requires `GUILD_MEMBERS` privileged intent
* @event Client#threadMembersUpdate * @event Client#threadMembersUpdate
* @param {Collection<Snowflake, ThreadMember>} oldMembers The members before the update * @param {ThreadChannel} thread The thread where members got updated
* @param {Collection<Snowflake, ThreadMember>} newMembers The members after the update * @param {Collection<Snowflake, ThreadMember>} addedMembers The members that were added
* @param {Collection<Snowflake, ThreadMember>} removedMembers The members that were removed
*/ */
client.emit(Events.ThreadMembersUpdate, old, thread.members.cache); client.emit(Events.ThreadMembersUpdate, thread, addedMembers, removedMembers);
} }
return {}; return {};
} }

View File

@@ -23,6 +23,12 @@ class ThreadMember extends Base {
*/ */
this.joinedTimestamp = null; this.joinedTimestamp = null;
/**
* The flags for this thread member. This will be `null` if partial.
* @type {?ThreadMemberFlagsBitField}
*/
this.flags = null;
/** /**
* The id of the thread member * The id of the thread member
* @type {Snowflake} * @type {Snowflake}
@@ -34,14 +40,16 @@ class ThreadMember extends Base {
_patch(data) { _patch(data) {
if ('join_timestamp' in data) this.joinedTimestamp = Date.parse(data.join_timestamp); if ('join_timestamp' in data) this.joinedTimestamp = Date.parse(data.join_timestamp);
if ('flags' in data) this.flags = new ThreadMemberFlagsBitField(data.flags).freeze();
}
if ('flags' in data) { /**
/** * Whether this thread member is a partial
* The flags for this thread member * @type {boolean}
* @type {ThreadMemberFlagsBitField} * @readonly
*/ */
this.flags = new ThreadMemberFlagsBitField(data.flags).freeze(); get partial() {
} return this.flags === null;
} }
/** /**

View File

@@ -2,4 +2,12 @@
const { createEnum } = require('./Enums'); const { createEnum } = require('./Enums');
module.exports = createEnum(['User', 'Channel', 'GuildMember', 'Message', 'Reaction', 'GuildScheduledEvent']); module.exports = createEnum([
'User',
'Channel',
'GuildMember',
'Message',
'Reaction',
'GuildScheduledEvent',
'ThreadMember',
]);

View File

@@ -2338,6 +2338,7 @@ export class ThreadMember extends Base {
public get manageable(): boolean; public get manageable(): boolean;
public thread: ThreadChannel; public thread: ThreadChannel;
public get user(): User | null; public get user(): User | null;
public get partial(): false;
public remove(reason?: string): Promise<ThreadMember>; public remove(reason?: string): Promise<ThreadMember>;
} }
@@ -3289,7 +3290,7 @@ export interface AddGuildMemberOptions {
fetchWhenExisting?: boolean; fetchWhenExisting?: boolean;
} }
export type AllowedPartial = User | Channel | GuildMember | Message | MessageReaction; export type AllowedPartial = User | Channel | GuildMember | Message | MessageReaction | ThreadMember;
export type AllowedThreadTypeForNewsChannel = ChannelType.GuildNewsThread; export type AllowedThreadTypeForNewsChannel = ChannelType.GuildNewsThread;
@@ -3671,8 +3672,9 @@ export interface ClientEvents {
threadListSync: [threads: Collection<Snowflake, ThreadChannel>]; threadListSync: [threads: Collection<Snowflake, ThreadChannel>];
threadMemberUpdate: [oldMember: ThreadMember, newMember: ThreadMember]; threadMemberUpdate: [oldMember: ThreadMember, newMember: ThreadMember];
threadMembersUpdate: [ threadMembersUpdate: [
oldMembers: Collection<Snowflake, ThreadMember>, thread: ThreadChannel,
newMembers: Collection<Snowflake, ThreadMember>, addedMembers: Collection<Snowflake, ThreadMember>,
removedMembers: Collection<Snowflake, ThreadMember | PartialThreadMember>,
]; ];
threadUpdate: [oldThread: ThreadChannel, newThread: ThreadChannel]; threadUpdate: [oldThread: ThreadChannel, newThread: ThreadChannel];
typingStart: [typing: Typing]; typingStart: [typing: Typing];
@@ -4877,6 +4879,8 @@ export interface PartialMessage
export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {} export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {}
export interface PartialThreadMember extends Partialize<ThreadMember, 'flags' | 'joinedAt' | 'joinedTimestamp'> {}
export interface PartialOverwriteData { export interface PartialOverwriteData {
id: Snowflake | number; id: Snowflake | number;
type?: OverwriteType; type?: OverwriteType;
@@ -4895,6 +4899,7 @@ export enum Partials {
Message, Message,
Reaction, Reaction,
GuildScheduledEvent, GuildScheduledEvent,
ThreadMember,
} }
export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {} export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {}

View File

@@ -107,6 +107,8 @@ import {
CategoryChannelChildManager, CategoryChannelChildManager,
ActionRowData, ActionRowData,
MessageActionRowComponentData, MessageActionRowComponentData,
PartialThreadMember,
ThreadMemberFlagsBitField,
Embed, Embed,
} from '.'; } from '.';
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd'; import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
@@ -719,6 +721,22 @@ client.on('messageCreate', async message => {
}); });
}); });
client.on('threadMembersUpdate', (thread, addedMembers, removedMembers) => {
expectType<ThreadChannel>(thread);
expectType<Collection<Snowflake, ThreadMember>>(addedMembers);
expectType<Collection<Snowflake, ThreadMember | PartialThreadMember>>(removedMembers);
const left = removedMembers.first();
if (!left) return;
if (left.partial) {
expectType<PartialThreadMember>(left);
expectType<null>(left.flags);
} else {
expectType<ThreadMember>(left);
expectType<ThreadMemberFlagsBitField>(left.flags);
}
});
client.on('interactionCreate', async interaction => { client.on('interactionCreate', async interaction => {
expectType<Snowflake | null>(interaction.guildId); expectType<Snowflake | null>(interaction.guildId);
expectType<Snowflake | null>(interaction.channelId); expectType<Snowflake | null>(interaction.channelId);