Skip to content

Commit

Permalink
feat: forwarding messages
Browse files Browse the repository at this point in the history
  • Loading branch information
TAEMBO committed Oct 20, 2024
1 parent 6cbe248 commit 07a5c46
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 5 deletions.
31 changes: 29 additions & 2 deletions packages/discord.js/src/managers/MessageManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v10');
const { MessageReferenceType, Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager');
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
const { Message } = require('../structures/Message');
const MessagePayload = require('../structures/MessagePayload');
const { MakeCacheOverrideSymbol } = require('../util/Symbols');
Expand Down Expand Up @@ -209,6 +209,33 @@ class MessageManager extends CachedManager {
return this.cache.get(data.id) ?? this._add(data);
}

/**
* Forwards a message to this manager's channel.
* @param {Message|MessageReference} reference The message to forward
* @returns {Promise<Message>}
*/
async forward(reference) {
if (!reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
const message_id = this.resolveId(reference.messageId);
if (!message_id) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
const channel_id = this.client.channels.resolveId(reference.channelId);
if (!channel_id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'ChannelResolvable');
const guild_id = this.client.guilds.resolveId(reference.guildId);

const data = await this.client.rest.post(Routes.channelMessages(this.channel.id), {
body: {
message_reference: {
message_id,
channel_id,
guild_id,
type: MessageReferenceType.Forward,
},
},
});

return this.cache.get(data.id) ?? this._add(data);
}

/**
* Pins a message to the channel's pinned messages, even if it's not cached.
* @param {MessageResolvable} message The message to pin
Expand Down
23 changes: 20 additions & 3 deletions packages/discord.js/src/structures/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
ChannelType,
MessageType,
MessageFlags,
MessageReferenceType,
PermissionFlagsBits,
} = require('discord-api-types/v10');
const Attachment = require('./Attachment');
Expand All @@ -20,7 +21,7 @@ const MessagePayload = require('./MessagePayload');
const { Poll } = require('./Poll.js');
const ReactionCollector = require('./ReactionCollector');
const { Sticker } = require('./Sticker');
const { DiscordjsError, ErrorCodes } = require('../errors');
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
const ReactionManager = require('../managers/ReactionManager');
const { createComponent } = require('../util/Components');
const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants');
Expand Down Expand Up @@ -794,6 +795,19 @@ class Message extends Base {
return message;
}

/**
* Forwards this message.
* @param {ChannelResolvable} channel The channel to forward this message to
* @returns {Promise<Message>}
*/
forward(channel) {
const resolvedChannel = this.client.channels.resolve(channel);

if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'ChannelResolvable');

return resolvedChannel.messages.forward(this);
}

/**
* Whether the message is crosspostable by the client user
* @type {boolean}
Expand Down Expand Up @@ -947,8 +961,11 @@ class Message extends Base {
data = options;
} else {
data = MessagePayload.create(this, options, {
reply: {
messageReference: this,
messageReference: {
messageId: this.id,
channelId: this.channelId,
guildId: this.guildId,
type: MessageReferenceType.Default,
failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists,
},
});
Expand Down
17 changes: 17 additions & 0 deletions packages/discord.js/src/structures/MessagePayload.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,23 @@ class MessagePayload {
}
}

if (this.options.messageReference) {
const reference = this.options.messageReference;
const message_id = this.target.messages.resolveId(reference.messageId);
const channel_id = this.target.client.channels.resolveId(reference.channelId);
const guild_id = this.target.client.guilds.resolveId(reference.guildId);

if (message_id) {
message_reference = {
message_id,
channel_id,
guild_id,
type: reference.type,
fail_if_not_exists: reference.failIfNotExists ?? this.target.client.options.failIfNotExists,
};
}
}

const attachments = this.options.files?.map((file, index) => ({
id: index.toString(),
description: file.description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ class TextBasedChannel {
* The options for sending a message.
* @typedef {BaseMessageCreateOptions} MessageCreateOptions
* @property {ReplyOptions} [reply] The options for replying to a message
* <warn>This property is deprecated. Use `messageReference` instead.</warn>
* @property {MessageReference|MessageResolvable} [messageReference] The options for a reference to a message
*/

/**
Expand Down
5 changes: 5 additions & 0 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2191,6 +2191,7 @@ export class Message<InGuild extends boolean = boolean> extends Base {
public equals(message: Message, rawData: unknown): boolean;
public fetchReference(): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;
public fetchWebhook(): Promise<Webhook>;
public forward(channel: TextBasedChannelResolvable): Promise<Message>;
public crosspost(): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;
public fetch(force?: boolean): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;
public pin(reason?: string): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;
Expand Down Expand Up @@ -4310,6 +4311,7 @@ export abstract class MessageManager<InGuild extends boolean = boolean> extends
public fetch(options: MessageResolvable | FetchMessageOptions): Promise<Message<InGuild>>;
public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message<InGuild>>>;
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message<InGuild>>>;
public forward(reference: Omit<MessageReference, 'type'>): Promise<Message<InGuild>>;
public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;
public pin(message: MessageResolvable, reason?: string): Promise<void>;
public unpin(message: MessageResolvable, reason?: string): Promise<void>;
Expand Down Expand Up @@ -6270,7 +6272,9 @@ export interface MessageCreateOptions extends BaseMessageOptionsWithPoll {
tts?: boolean;
nonce?: string | number;
enforceNonce?: boolean;
/** @deprecated Use {@link MessageCreateOptions.messageReference} instead */
reply?: ReplyOptions;
messageReference?: MessageReference & { failIfNotExists?: boolean };
stickers?: readonly StickerResolvable[];
flags?: BitFieldResolvable<
Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications'>,
Expand Down Expand Up @@ -6516,6 +6520,7 @@ export interface ReactionCollectorOptions extends CollectorOptions<[MessageReact
maxUsers?: number;
}

/** @deprecated Use {@link MessageReference} instead. */
export interface ReplyOptions {
messageReference: MessageResolvable;
failIfNotExists?: boolean;
Expand Down

0 comments on commit 07a5c46

Please sign in to comment.