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
- Reaction
- GuildScheduledEvent
- ThreadMember
multiple: true
validations:
required: true

View File

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

View File

@@ -1,5 +1,6 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const Action = require('./Action');
const Events = require('../../util/Events');
@@ -8,24 +9,35 @@ class ThreadMembersUpdateAction extends Action {
const client = this.client;
const thread = client.channels.cache.get(data.id);
if (thread) {
const old = thread.members.cache.clone();
thread.memberCount = data.member_count;
const addedMembers = new Collection();
const removedMembers = new Collection();
data.added_members?.forEach(rawMember => {
thread.members._add(rawMember);
});
data.added_members?.reduce(
(_addedMembers, addedMember) => _addedMembers.set(addedMember.user_id, thread.members._add(addedMember)),
addedMembers,
);
data.removed_member_ids?.forEach(memberId => {
thread.members.cache.delete(memberId);
});
data.removed_member_ids?.reduce((removedMembersIds, removedMembersId) => {
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
* @event Client#threadMembersUpdate
* @param {Collection<Snowflake, ThreadMember>} oldMembers The members before the update
* @param {Collection<Snowflake, ThreadMember>} newMembers The members after the update
* @param {ThreadChannel} thread The thread where members got updated
* @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 {};
}

View File

@@ -23,6 +23,12 @@ class ThreadMember extends Base {
*/
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
* @type {Snowflake}
@@ -34,14 +40,16 @@ class ThreadMember extends Base {
_patch(data) {
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) {
/**
* The flags for this thread member
* @type {ThreadMemberFlagsBitField}
*/
this.flags = new ThreadMemberFlagsBitField(data.flags).freeze();
}
/**
* Whether this thread member is a partial
* @type {boolean}
* @readonly
*/
get partial() {
return this.flags === null;
}
/**

View File

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

View File

@@ -107,6 +107,8 @@ import {
CategoryChannelChildManager,
ActionRowData,
MessageActionRowComponentData,
PartialThreadMember,
ThreadMemberFlagsBitField,
Embed,
} from '.';
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 => {
expectType<Snowflake | null>(interaction.guildId);
expectType<Snowflake | null>(interaction.channelId);