Skip to content
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

feat: Allow webhooks to fetch, edit and delete messages in threads #6695

Merged
merged 10 commits into from Oct 2, 2021
47 changes: 40 additions & 7 deletions src/structures/Webhook.js
Expand Up @@ -105,6 +105,8 @@ class Webhook {
* @property {MessageAttachment[]} [attachments] Attachments to send with the message
* @property {MessageActionRow[]|MessageActionRowOptions[]} [components]
* Action rows containing interactive components for the message (buttons, select menus)
* @property {Snowflake} [threadId] The id of the thread this message belongs to
* <info>For interaction webhooks, this property is ignored</info>
*/

/**
Expand Down Expand Up @@ -235,18 +237,38 @@ class Webhook {
return this;
}

/**
* Options that can be passed into fetchMessage.
* @typedef {options} WebhookFetchMessageOptions
* @property {boolean} [cache=true] Whether to cache the message.
* @property {Snowflake} [threadId] The id of the thread this message belongs to.
* <info>For interaction webhooks, this property is ignored</info>
*/

/**
* Gets a message that was sent by this webhook.
* @param {Snowflake|'@original'} message The id of the message to fetch
* @param {boolean} [cache=true] Whether to cache the message
* @param {WebhookFetchMessageOptions|boolean} [cacheOrOptions={}] The options to provide to fetch the message.
* A **deprecated** boolean may be passed instead to specify whether to cache the message.
* @returns {Promise<Message|APIMessage>} Returns the raw message data if the webhook was instantiated as a
* {@link WebhookClient} or if the channel is uncached, otherwise a {@link Message} will be returned
*/
async fetchMessage(message, cache = true) {
async fetchMessage(message, cacheOrOptions = { cache: true }) {
if (typeof cacheOrOptions === 'boolean') {
cacheOrOptions = { cache: cacheOrOptions };
}

if (!this.token) throw new Error('WEBHOOK_TOKEN_UNAVAILABLE');

const data = await this.client.api.webhooks(this.id, this.token).messages(message).get();
return this.client.channels?.cache.get(data.channel_id)?.messages._add(data, cache) ?? data;
const data = await this.client.api
.webhooks(this.id, this.token)
.messages(message)
.get({
query: {
thread_id: cacheOrOptions.threadId,
},
});
return this.client.channels?.cache.get(data.channel_id)?.messages._add(data, cacheOrOptions.cache) ?? data;
}

/**
Expand All @@ -269,7 +291,13 @@ class Webhook {
const d = await this.client.api
.webhooks(this.id, this.token)
.messages(typeof message === 'string' ? message : message.id)
.patch({ data, files });
.patch({
data,
files,
query: {
thread_id: messagePayload.options.threadId,
},
});

const messageManager = this.client.channels?.cache.get(d.channel_id)?.messages;
if (!messageManager) return d;
Expand All @@ -294,15 +322,20 @@ class Webhook {
/**
* Delete a message that was sent by this webhook.
* @param {MessageResolvable|'@original'} message The message to delete
* @param {Snowflake} [threadId] The id of the thread this message belongs to
* @returns {Promise<void>}
*/
async deleteMessage(message) {
async deleteMessage(message, threadId) {
if (!this.token) throw new Error('WEBHOOK_TOKEN_UNAVAILABLE');

await this.client.api
.webhooks(this.id, this.token)
.messages(typeof message === 'string' ? message : message.id)
.delete();
.delete({
query: {
thread_id: threadId,
},
});
}

/**
Expand Down
17 changes: 15 additions & 2 deletions typings/index.d.ts
Expand Up @@ -2119,7 +2119,11 @@ export class WebhookClient extends WebhookMixin(BaseClient) {
message: MessageResolvable,
options: string | MessagePayload | WebhookEditMessageOptions,
): Promise<APIMessage>;
public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<APIMessage>;
/* tslint:disable:unified-signatures */
/** @deprecated */
public fetchMessage(message: Snowflake, cache?: boolean): Promise<APIMessage>;
/* tslint:enable:unified-signatures */
public send(options: string | MessagePayload | WebhookMessageOptions): Promise<APIMessage>;
}

Expand Down Expand Up @@ -2825,12 +2829,16 @@ export function WebhookMixin<T>(Base?: Constructable<T>): Constructable<T & Webh
export interface PartialWebhookFields {
id: Snowflake;
readonly url: string;
deleteMessage(message: MessageResolvable | APIMessage | '@original'): Promise<void>;
deleteMessage(message: MessageResolvable | APIMessage | '@original', threadId?: Snowflake): Promise<void>;
editMessage(
message: MessageResolvable | '@original',
options: string | MessagePayload | WebhookEditMessageOptions,
): Promise<Message | APIMessage>;
fetchMessage(message: Snowflake | '@original', options?: WebhookFetchMessageOptions): Promise<Message | APIMessage>;
/* tslint:disable:unified-signatures */
/** @deprecated */
fetchMessage(message: Snowflake | '@original', cache?: boolean): Promise<Message | APIMessage>;
/* tslint:enable:unified-signatures */
send(options: string | MessagePayload | WebhookMessageOptions): Promise<Message | APIMessage>;
}

Expand Down Expand Up @@ -4790,9 +4798,14 @@ export interface WebhookEditData {

export type WebhookEditMessageOptions = Pick<
WebhookMessageOptions,
'content' | 'embeds' | 'files' | 'allowedMentions' | 'components' | 'attachments'
'content' | 'embeds' | 'files' | 'allowedMentions' | 'components' | 'attachments' | 'threadId'
>;

export interface WebhookFetchMessageOptions {
cache?: boolean;
threadId?: Snowflake;
}

export interface WebhookMessageOptions extends Omit<MessageOptions, 'reply'> {
username?: string;
avatarURL?: string;
Expand Down