[Feature] Message Forwards (#2918)

* code

* no guild

* iTS ALIVE (THANKS aDVAITH)
This commit is contained in:
Mihail Gribkov
2024-08-31 14:29:20 +03:00
committed by GitHub
parent 623a45765d
commit c4d90cd6f1
14 changed files with 96 additions and 7 deletions

View File

@@ -30,6 +30,11 @@ namespace Discord
/// </remarks>
IMessageInteractionMetadata InteractionMetadata { get; }
/// <summary>
/// Gets a collection of partial messages that were forwarded with this message.
/// </summary>
IReadOnlyCollection<MessageSnapshot> ForwardedMessages { get; }
/// <summary>
/// Gets the poll sent with this message.
/// </summary>

View File

@@ -33,6 +33,11 @@ namespace Discord
/// </summary>
public Optional<bool> FailIfNotExists { get; internal set; }
/// <summary>
/// Gets the type of message reference.
/// </summary>
public Optional<MessageReferenceType> ReferenceType { get; internal set; }
/// <summary>
/// Initializes a new instance of the <see cref="MessageReference"/> class.
/// </summary>
@@ -48,12 +53,14 @@ namespace Discord
/// <param name="failIfNotExists">
/// Whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message. Defaults to true.
/// </param>
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<ulong>();
InternalChannelId = channelId ?? Optional.Create<ulong>();
GuildId = guildId ?? Optional.Create<ulong>();
FailIfNotExists = failIfNotExists ?? Optional.Create<bool>();
ReferenceType = referenceType;
}
private string DebuggerDisplay

View File

@@ -0,0 +1,17 @@
namespace Discord;
/// <summary>
/// Determines how associated data is populated.
/// </summary>
public enum MessageReferenceType
{
/// <summary>
/// A standard reference used by replies.
/// </summary>
Default = 0,
/// <summary>
/// Reference used to point to a message at a point in time.
/// </summary>
Forward = 1,
}

View File

@@ -0,0 +1,17 @@
namespace Discord;
/// <summary>
/// Represents a snapshot of a message.
/// </summary>
public readonly struct MessageSnapshot
{
/// <summary>
/// Gets the partial message that was forwarded.
/// </summary>
public readonly IMessage Message;
internal MessageSnapshot(IMessage message)
{
Message = message;
}
}

View File

@@ -98,7 +98,7 @@ namespace Discord
}
public static void MessageAtLeastOneOf(string text = null, MessageComponent components = null, ICollection<IEmbed> embeds = null,
ICollection<ISticker> stickers = null, IEnumerable<FileAttachment> attachments = null, PollProperties poll = null)
ICollection<ISticker> stickers = null, IEnumerable<FileAttachment> attachments = null, PollProperties poll = null, MessageReference messageReference = null)
{
if (!string.IsNullOrEmpty(text))
return;
@@ -118,6 +118,9 @@ namespace Discord
if (poll is not null)
return;
if (messageReference?.ReferenceType.GetValueOrDefault(MessageReferenceType.Default) is MessageReferenceType.Forward)
return;
throw new ArgumentException($"At least one of 'Content', 'Embeds', 'Components', 'Stickers', 'Attachments' or 'Poll' must be specified.");
}

View File

@@ -102,6 +102,9 @@ internal class Message
[JsonProperty("interaction_metadata")]
public Optional<MessageInteractionMetadata> InteractionMetadata { get; set; }
[JsonProperty("message_snapshots")]
public Optional<MessageSnapshot[]> MessageSnapshots { get; set; }
[JsonProperty("poll")]
public Optional<Poll> Poll { get; set; }

View File

@@ -4,6 +4,9 @@ namespace Discord.API
{
internal class MessageReference
{
[JsonProperty("type")]
public Optional<MessageReferenceType> Type { get; set; }
[JsonProperty("message_id")]
public Optional<ulong> MessageId { get; set; }

View File

@@ -0,0 +1,9 @@
using Newtonsoft.Json;
namespace Discord.API;
internal class MessageSnapshot
{
[JsonProperty("message")]
public Message Message { get; set; }
}

View File

@@ -284,7 +284,7 @@ namespace Discord.Rest
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed.");
Preconditions.AtMost(embeds.Length, DiscordConfig.MaxEmbedsPerMessage, nameof(embeds), $"A max of {DiscordConfig.MaxEmbedsPerMessage} Embeds are allowed.");
Preconditions.MessageAtLeastOneOf(text, components, embeds, stickers, poll: poll);
Preconditions.MessageAtLeastOneOf(text, components, embeds, stickers, poll: poll, messageReference: messageReference);
Preconditions.ValidatePoll(poll);
// check that user flag and user Id list are exclusive, same with role flag and role Id list
@@ -400,7 +400,7 @@ namespace Discord.Rest
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed.");
Preconditions.AtMost(embeds.Length, DiscordConfig.MaxEmbedsPerMessage, nameof(embeds), $"A max of {DiscordConfig.MaxEmbedsPerMessage} Embeds are allowed.");
Preconditions.MessageAtLeastOneOf(text, components, embeds, stickers, attachments, poll);
Preconditions.MessageAtLeastOneOf(text, components, embeds, stickers, attachments, poll, messageReference);
Preconditions.ValidatePoll(poll);
foreach (var attachment in attachments)

View File

@@ -165,7 +165,8 @@ namespace Discord.Rest
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
};
}

View File

@@ -57,6 +57,9 @@ namespace Discord.Rest
/// <inheritdoc />
public MessageResolvedData ResolvedData { get; internal set; }
/// <inheritdoc />
public IReadOnlyCollection<MessageSnapshot> ForwardedMessages { get; internal set; }
internal RestUserMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source)
: base(discord, id, channel, author, source)
{
@@ -171,6 +174,14 @@ namespace Discord.Rest
if (model.InteractionMetadata.IsSpecified)
InteractionMetadata = model.InteractionMetadata.Value.ToInteractionMetadata(Discord);
if (model.MessageSnapshots.IsSpecified)
{
ForwardedMessages = model.MessageSnapshots.Value.Select(x =>
new MessageSnapshot(RestMessage.Create(Discord, null, null, x.Message))).ToImmutableArray();
}
else
ForwardedMessages = ImmutableArray<MessageSnapshot>.Empty;
if (model.Poll.IsSpecified)
Poll = model.Poll.Value.ToEntity();
}

View File

@@ -102,7 +102,8 @@ namespace Discord.Rest
ChannelId = entity.InternalChannelId,
GuildId = entity.GuildId,
MessageId = entity.MessageId,
FailIfNotExists = entity.FailIfNotExists
FailIfNotExists = entity.FailIfNotExists,
Type = entity.ReferenceType,
};
}
public static IEnumerable<string> EnumerateMentionTypes(this AllowedMentionTypes mentionTypes)

View File

@@ -198,7 +198,8 @@ namespace Discord.WebSocket
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
};
}

View File

@@ -58,6 +58,9 @@ namespace Discord.WebSocket
/// <inheritdoc />
public MessageResolvedData ResolvedData { get; internal set; }
/// <inheritdoc />
public IReadOnlyCollection<MessageSnapshot> ForwardedMessages { get; internal set; }
internal SocketUserMessage(DiscordSocketClient discord, ulong id, ISocketMessageChannel channel, SocketUser author, MessageSource source)
: base(discord, id, channel, author, source)
{
@@ -213,6 +216,14 @@ namespace Discord.WebSocket
if (model.InteractionMetadata.IsSpecified)
InteractionMetadata = model.InteractionMetadata.Value.ToInteractionMetadata(Discord);
if (model.MessageSnapshots.IsSpecified)
{
ForwardedMessages = model.MessageSnapshots.Value.Select(x =>
new MessageSnapshot(RestMessage.Create(Discord, null, null, x.Message))).ToImmutableArray();
}
else
ForwardedMessages = ImmutableArray<MessageSnapshot>.Empty;
if (model.Poll.IsSpecified)
Poll = model.Poll.Value.ToEntity();
}