diff --git a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs index 757c3e4a03..ca37d56618 100644 --- a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace Discord @@ -29,6 +30,11 @@ public interface IUserMessage : IMessage /// IMessageInteractionMetadata InteractionMetadata { get; } + /// + /// Gets a collection of partial messages that were forwarded with this message. + /// + IReadOnlyCollection ForwardedMessages { get; } + /// /// Modifies this message. /// diff --git a/src/Discord.Net.Core/Entities/Messages/MessageReference.cs b/src/Discord.Net.Core/Entities/Messages/MessageReference.cs index 7fdc448ad6..032879a0a2 100644 --- a/src/Discord.Net.Core/Entities/Messages/MessageReference.cs +++ b/src/Discord.Net.Core/Entities/Messages/MessageReference.cs @@ -33,6 +33,11 @@ public class MessageReference /// public Optional FailIfNotExists { get; internal set; } + /// + /// Gets the type of message reference. + /// + public Optional ReferenceType { get; internal set; } + /// /// Initializes a new instance of the class. /// @@ -48,12 +53,14 @@ public class MessageReference /// /// Whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message. Defaults to true. /// - public MessageReference(ulong? messageId = null, ulong? channelId = null, ulong? guildId = null, bool? failIfNotExists = null) + public MessageReference(ulong? messageId = null, ulong? channelId = null, ulong? guildId = null, bool? failIfNotExists = null, + MessageReferenceType referenceType = MessageReferenceType.Default) { MessageId = messageId ?? Optional.Create(); InternalChannelId = channelId ?? Optional.Create(); GuildId = guildId ?? Optional.Create(); FailIfNotExists = failIfNotExists ?? Optional.Create(); + ReferenceType = referenceType; } private string DebuggerDisplay diff --git a/src/Discord.Net.Core/Entities/Messages/MessageReferenceType.cs b/src/Discord.Net.Core/Entities/Messages/MessageReferenceType.cs new file mode 100644 index 0000000000..4fed6f4151 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/MessageReferenceType.cs @@ -0,0 +1,17 @@ +namespace Discord; + +/// +/// Determines how associated data is populated. +/// +public enum MessageReferenceType +{ + /// + /// A standard reference used by replies. + /// + Default = 0, + + /// + /// Reference used to point to a message at a point in time. + /// + Forward = 1, +} diff --git a/src/Discord.Net.Core/Entities/Messages/MessageSnapshot.cs b/src/Discord.Net.Core/Entities/Messages/MessageSnapshot.cs new file mode 100644 index 0000000000..dc1322615a --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/MessageSnapshot.cs @@ -0,0 +1,23 @@ +namespace Discord; + +/// +/// Represents a snapshot of a message. +/// +public readonly struct MessageSnapshot +{ + /// + /// Gets the partial message that was forwarded. + /// + public readonly IMessage Message; + + /// + /// Gets the id of the originating message's guild + /// + public readonly ulong? GuildId; + + internal MessageSnapshot(IMessage message, ulong? guildId) + { + Message = message; + GuildId = guildId; + } +} diff --git a/src/Discord.Net.Rest/API/Common/Message.cs b/src/Discord.Net.Rest/API/Common/Message.cs index c9cc61a203..a5da3f85aa 100644 --- a/src/Discord.Net.Rest/API/Common/Message.cs +++ b/src/Discord.Net.Rest/API/Common/Message.cs @@ -101,4 +101,7 @@ internal class Message [JsonProperty("interaction_metadata")] public Optional InteractionMetadata { get; set; } + + [JsonProperty("message_snapshot")] + public Optional MessageSnapshots { get; set; } } diff --git a/src/Discord.Net.Rest/API/Common/MessageReference.cs b/src/Discord.Net.Rest/API/Common/MessageReference.cs index 70ef4e678e..3e582b2f28 100644 --- a/src/Discord.Net.Rest/API/Common/MessageReference.cs +++ b/src/Discord.Net.Rest/API/Common/MessageReference.cs @@ -4,6 +4,9 @@ namespace Discord.API { internal class MessageReference { + [JsonProperty("type")] + public Optional Type { get; set; } + [JsonProperty("message_id")] public Optional MessageId { get; set; } diff --git a/src/Discord.Net.Rest/API/Common/MessageSnapshot.cs b/src/Discord.Net.Rest/API/Common/MessageSnapshot.cs new file mode 100644 index 0000000000..cb880845f0 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/MessageSnapshot.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API; + +internal class MessageSnapshot +{ + [JsonProperty("message")] + public Message Message { get; set; } + + [JsonProperty("guild_id")] + public Optional GuildId { get; set; } +} diff --git a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs index fd9aa07c96..d6ecc0771c 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs @@ -158,7 +158,8 @@ internal virtual void Update(Model model) GuildId = model.Reference.Value.GuildId, InternalChannelId = model.Reference.Value.ChannelId, MessageId = model.Reference.Value.MessageId, - FailIfNotExists = model.Reference.Value.FailIfNotExists + FailIfNotExists = model.Reference.Value.FailIfNotExists, + ReferenceType = model.Reference.Value.Type }; } diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs index 2312f92c44..56e8fae623 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs @@ -54,6 +54,9 @@ public class RestUserMessage : RestMessage, IUserMessage /// public MessageResolvedData ResolvedData { get; internal set; } + /// + public IReadOnlyCollection ForwardedMessages { get; internal set; } + internal RestUserMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) : base(discord, id, channel, author, source) { @@ -167,6 +170,15 @@ internal override void Update(Model model) } if (model.InteractionMetadata.IsSpecified) InteractionMetadata = model.InteractionMetadata.Value.ToInteractionMetadata(); + + if (model.MessageSnapshots.IsSpecified) + { + ForwardedMessages = model.MessageSnapshots.Value.Select(x => + new MessageSnapshot(RestMessage.Create(Discord, null, null, x.Message), + x.GuildId.IsSpecified ? x.GuildId.Value : null)).ToImmutableArray(); + } + else + ForwardedMessages = ImmutableArray.Empty; } /// diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs index 930c6ca177..8ca06b3b0f 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs @@ -192,7 +192,8 @@ internal virtual void Update(ClientState state, Model model) GuildId = model.Reference.Value.GuildId, InternalChannelId = model.Reference.Value.ChannelId, MessageId = model.Reference.Value.MessageId, - FailIfNotExists = model.Reference.Value.FailIfNotExists + FailIfNotExists = model.Reference.Value.FailIfNotExists, + ReferenceType = model.Reference.Value.Type }; } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index 74d82fdb58..a0eb755708 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -55,6 +55,9 @@ public class SocketUserMessage : SocketMessage, IUserMessage /// public MessageResolvedData ResolvedData { get; internal set; } + /// + public IReadOnlyCollection ForwardedMessages { get; internal set; } + internal SocketUserMessage(DiscordSocketClient discord, ulong id, ISocketMessageChannel channel, SocketUser author, MessageSource source) : base(discord, id, channel, author, source) { @@ -209,6 +212,16 @@ internal override void Update(ClientState state, Model model) if (model.InteractionMetadata.IsSpecified) InteractionMetadata = model.InteractionMetadata.Value.ToInteractionMetadata(); + + + if (model.MessageSnapshots.IsSpecified) + { + ForwardedMessages = model.MessageSnapshots.Value.Select(x => + new MessageSnapshot(RestMessage.Create(Discord, null, null, x.Message), + x.GuildId.IsSpecified ? x.GuildId.Value : null)).ToImmutableArray(); + } + else + ForwardedMessages = ImmutableArray.Empty; } ///