From 86cd3e6bf0c45e29538cd0003f5264bf81cb19fb Mon Sep 17 00:00:00 2001 From: Daniel Jarski <30324210+QuantumToasted@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:13:48 -0600 Subject: [PATCH] Initial message snapshots commit --- .../Core/Message/User/IMessageReference.cs | 5 ++ .../Core/Message/User/IMessageSnapshot.cs | 62 ++++++++++++++++ .../Core/Message/User/IUserMessage.cs | 5 ++ .../LocalMessageReferenceExtensions.cs | 7 ++ .../Local/Message/LocalMessageReference.cs | 10 +++ .../Transient/Message/TransientMessage.cs | 2 +- .../Message/User/TransientMessageReference.cs | 3 + .../Message/User/TransientMessageSnapshot.cs | 72 +++++++++++++++++++ .../Message/User/TransientUserMessage.cs | 13 +++- .../Enums/MessageReferenceType.cs | 17 +++++ .../Models/Message/MessageJsonModel.cs | 5 +- .../Message/MessageReferenceJsonModel.cs | 3 + .../Message/MessageSnapshotJsonModel.cs | 9 +++ .../Entities/Cached/Message/CachedMessage.cs | 4 +- .../Cached/Message/User/CachedUserMessage.cs | 3 + .../Message/TransientGatewayMessage.cs | 6 +- .../User/TransientGatewayUserMessage.cs | 12 ++++ 17 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 src/Disqord.Core/Entities/Core/Message/User/IMessageSnapshot.cs create mode 100644 src/Disqord.Core/Entities/Transient/Message/User/TransientMessageSnapshot.cs create mode 100644 src/Disqord.Core/Enums/MessageReferenceType.cs create mode 100644 src/Disqord.Core/Models/Message/MessageSnapshotJsonModel.cs diff --git a/src/Disqord.Core/Entities/Core/Message/User/IMessageReference.cs b/src/Disqord.Core/Entities/Core/Message/User/IMessageReference.cs index b636025c4..aa9d20c4e 100644 --- a/src/Disqord.Core/Entities/Core/Message/User/IMessageReference.cs +++ b/src/Disqord.Core/Entities/Core/Message/User/IMessageReference.cs @@ -5,6 +5,11 @@ /// public interface IMessageReference : IChannelEntity, IPossiblyGuildEntity { + /// + /// Gets the reference type of the referenced message. + /// + MessageReferenceType Type { get; } + /// /// Gets the ID of the referenced message. /// diff --git a/src/Disqord.Core/Entities/Core/Message/User/IMessageSnapshot.cs b/src/Disqord.Core/Entities/Core/Message/User/IMessageSnapshot.cs new file mode 100644 index 000000000..0e13a67df --- /dev/null +++ b/src/Disqord.Core/Entities/Core/Message/User/IMessageSnapshot.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; + +namespace Disqord; + +public interface IMessageSnapshot : IEntity +{ + /// + /// Gets the of this message snapshot. + /// + UserMessageType Type { get; } + + /// + /// Gets the content of this message snapshot. + /// + string Content { get; } + + /// + /// Gets the mentioned users of this message snapshot. + /// + IReadOnlyList MentionedUsers { get; } + + /// + /// Gets the mentioned role IDs of this message snapshot. + /// + IReadOnlyList MentionedRoleIds { get; } + + /// + /// Gets the attachments of this message snapshot. + /// + IReadOnlyList Attachments { get; } + + /// + /// Gets the embeds of this message snapshot. + /// + IReadOnlyList Embeds { get; } + + /// + /// Gets the timestamp of when the snapshotted message was created. + /// + DateTimeOffset Timestamp { get; } + + /// + /// Gets the edit date of this message snapshot. + /// + DateTimeOffset? EditedAt { get; } + + /// + /// Gets the flags of this message snapshot. + /// + MessageFlags Flags { get; } + + /// + /// Gets the stickers sent with this message snapshot. + /// + IReadOnlyList Stickers { get; } + + /// + /// Gets the components of this message snapshot. + /// + IReadOnlyList Components { get; } +} \ No newline at end of file diff --git a/src/Disqord.Core/Entities/Core/Message/User/IUserMessage.cs b/src/Disqord.Core/Entities/Core/Message/User/IUserMessage.cs index b40546249..5a07f5e9d 100644 --- a/src/Disqord.Core/Entities/Core/Message/User/IUserMessage.cs +++ b/src/Disqord.Core/Entities/Core/Message/User/IUserMessage.cs @@ -118,4 +118,9 @@ public interface IUserMessage : IMessage /// Gets the poll of this message. /// IPoll? Poll { get; } + + /// + /// Gets the message snapshots referenced (forwarded) by this message. + /// + IReadOnlyList MessageSnapshots { get; } } diff --git a/src/Disqord.Core/Entities/Local/Message/Extensions/LocalMessageReferenceExtensions.cs b/src/Disqord.Core/Entities/Local/Message/Extensions/LocalMessageReferenceExtensions.cs index 9b597850d..75ee1b14f 100644 --- a/src/Disqord.Core/Entities/Local/Message/Extensions/LocalMessageReferenceExtensions.cs +++ b/src/Disqord.Core/Entities/Local/Message/Extensions/LocalMessageReferenceExtensions.cs @@ -8,6 +8,13 @@ namespace Disqord; [EditorBrowsable(EditorBrowsableState.Never)] public static class LocalMessageReferenceExtensions { + public static TMessageReference WithType(this TMessageReference messageReference, MessageReferenceType type) + where TMessageReference : LocalMessageReference + { + messageReference.Type = type; + return messageReference; + } + /// /// Sets the ID of the referenced message. /// diff --git a/src/Disqord.Core/Entities/Local/Message/LocalMessageReference.cs b/src/Disqord.Core/Entities/Local/Message/LocalMessageReference.cs index a331e933e..788896e43 100644 --- a/src/Disqord.Core/Entities/Local/Message/LocalMessageReference.cs +++ b/src/Disqord.Core/Entities/Local/Message/LocalMessageReference.cs @@ -9,6 +9,14 @@ namespace Disqord; /// public class LocalMessageReference : ILocalConstruct, IJsonConvertible { + /// + /// Gets or sets the type of way this message will be referenced. + /// + /// + /// This property defaults to . + /// + public Optional Type { get; set; } = MessageReferenceType.Reply; + /// /// Gets or sets the ID of the referenced message. /// @@ -65,6 +73,7 @@ public virtual MessageReferenceJsonModel ToModel() { return new MessageReferenceJsonModel { + Type = Type, MessageId = MessageId, ChannelId = ChannelId, GuildId = GuildId, @@ -87,6 +96,7 @@ public static LocalMessageReference CreateFrom(IMessageReference reference) { return new LocalMessageReference { + Type = reference.Type, MessageId = Optional.FromNullable(reference.MessageId), ChannelId = reference.ChannelId, GuildId = Optional.FromNullable(reference.GuildId) diff --git a/src/Disqord.Core/Entities/Transient/Message/TransientMessage.cs b/src/Disqord.Core/Entities/Transient/Message/TransientMessage.cs index cb77cdf27..20f11f684 100644 --- a/src/Disqord.Core/Entities/Transient/Message/TransientMessage.cs +++ b/src/Disqord.Core/Entities/Transient/Message/TransientMessage.cs @@ -15,7 +15,7 @@ public abstract class TransientMessage : TransientClientEntity public Snowflake ChannelId => Model.ChannelId; /// - public IUser Author => _author ??= new TransientUser(Client, Model.Author); + public IUser Author => _author ??= new TransientUser(Client, Model.Author.Value); private IUser? _author; diff --git a/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageReference.cs b/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageReference.cs index 6dd04baaa..2933b4d5b 100644 --- a/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageReference.cs +++ b/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageReference.cs @@ -5,6 +5,9 @@ namespace Disqord; public class TransientMessageReference : TransientEntity, IMessageReference { + /// + public MessageReferenceType Type => Model.Type.GetValueOrNullable() ?? MessageReferenceType.Reply; + /// public Snowflake? MessageId => Model.MessageId.GetValueOrNullable(); diff --git a/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageSnapshot.cs b/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageSnapshot.cs new file mode 100644 index 000000000..11395c291 --- /dev/null +++ b/src/Disqord.Core/Entities/Transient/Message/User/TransientMessageSnapshot.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using Disqord.Models; +using Qommon.Collections.ReadOnly; + +namespace Disqord; + +public class TransientMessageSnapshot : TransientClientEntity, IMessageSnapshot +{ + /// + public UserMessageType Type => Model.Message.Type; + + /// + public string Content => Model.Message.Content; + + /// + public IReadOnlyList MentionedUsers => _mentionedUsers ??= Model.Message.Mentions.ToReadOnlyList(Client, (model, client) => new TransientUser(client, model)); + + private IReadOnlyList? _mentionedUsers; + + /// + public IReadOnlyList MentionedRoleIds => Model.Message.MentionRoles; + + /// + public IReadOnlyList Attachments => _attachments ??= Model.Message.Attachments.ToReadOnlyList(model => new TransientAttachment(model)); + + private IReadOnlyList? _attachments; + + /// + public IReadOnlyList Embeds => _embeds ??= Model.Message.Embeds.ToReadOnlyList(model => new TransientEmbed(model)); + + private IReadOnlyList? _embeds; + + /// + public DateTimeOffset Timestamp { get; } + + /// + public DateTimeOffset? EditedAt { get; } + + /// + public MessageFlags Flags { get; } + + /// + public IReadOnlyList Stickers + { + get + { + if (!Model.Message.StickerItems.HasValue) + return Array.Empty(); + + return _stickers ??= Model.Message.StickerItems.Value.ToReadOnlyList(model => new TransientMessageSticker(model)); + } + } + + private IReadOnlyList? _stickers; + + public IReadOnlyList Components + { + get + { + if (!Model.Message.Components.HasValue) + return Array.Empty(); + + return _components ??= Model.Message.Components.Value.ToReadOnlyList(Client, (model, client) => new TransientRowComponent(client, model)); + } + } + private IReadOnlyList? _components; + + public TransientMessageSnapshot(IClient client, MessageSnapshotJsonModel model) + : base(client, model) + { } +} \ No newline at end of file diff --git a/src/Disqord.Core/Entities/Transient/Message/User/TransientUserMessage.cs b/src/Disqord.Core/Entities/Transient/Message/User/TransientUserMessage.cs index 24cd307d0..8bb59f161 100644 --- a/src/Disqord.Core/Entities/Transient/Message/User/TransientUserMessage.cs +++ b/src/Disqord.Core/Entities/Transient/Message/User/TransientUserMessage.cs @@ -125,7 +125,6 @@ public IReadOnlyList Stickers return _stickers ??= Model.StickerItems.Value.ToReadOnlyList(model => new TransientMessageSticker(model)); } } - private IReadOnlyList? _stickers; /// @@ -133,6 +132,18 @@ public IReadOnlyList Stickers private IPoll? _poll; + public IReadOnlyList MessageSnapshots + { + get + { + if (!Model.MessageSnapshots.HasValue) + return Array.Empty(); + + return _messageSnapshots ??= Model.MessageSnapshots.Value.ToReadOnlyList(Client, (model, client) => new TransientMessageSnapshot(client, model)); + } + } + private IReadOnlyList? _messageSnapshots; + public TransientUserMessage(IClient client, MessageJsonModel model) : base(client, model) { } diff --git a/src/Disqord.Core/Enums/MessageReferenceType.cs b/src/Disqord.Core/Enums/MessageReferenceType.cs new file mode 100644 index 000000000..c92feb9d4 --- /dev/null +++ b/src/Disqord.Core/Enums/MessageReferenceType.cs @@ -0,0 +1,17 @@ +namespace Disqord; + +/// +/// Represents the type of a message reference. +/// +public enum MessageReferenceType +{ + /// + /// A standard reference used by replies. + /// + Reply = 0, + + /// + /// A reference used to point to a message at a point in time. + /// + Forward = 1 +} \ No newline at end of file diff --git a/src/Disqord.Core/Models/Message/MessageJsonModel.cs b/src/Disqord.Core/Models/Message/MessageJsonModel.cs index 57184e066..1eb20a9fb 100644 --- a/src/Disqord.Core/Models/Message/MessageJsonModel.cs +++ b/src/Disqord.Core/Models/Message/MessageJsonModel.cs @@ -17,7 +17,7 @@ public class MessageJsonModel : JsonModel public Optional GuildId; [JsonProperty("author")] - public UserJsonModel Author = null!; + public Optional Author; [JsonProperty("member")] public Optional Member; @@ -79,6 +79,9 @@ public class MessageJsonModel : JsonModel [JsonProperty("message_reference")] public Optional MessageReference; + [JsonProperty("message_snapshots")] + public Optional MessageSnapshots; + [JsonProperty("flags")] public Optional Flags; diff --git a/src/Disqord.Core/Models/Message/MessageReferenceJsonModel.cs b/src/Disqord.Core/Models/Message/MessageReferenceJsonModel.cs index ac03f54de..33bdc2556 100644 --- a/src/Disqord.Core/Models/Message/MessageReferenceJsonModel.cs +++ b/src/Disqord.Core/Models/Message/MessageReferenceJsonModel.cs @@ -5,6 +5,9 @@ namespace Disqord.Models; public class MessageReferenceJsonModel : JsonModel { + [JsonProperty("type")] + public Optional Type; + [JsonProperty("message_id")] public Optional MessageId; diff --git a/src/Disqord.Core/Models/Message/MessageSnapshotJsonModel.cs b/src/Disqord.Core/Models/Message/MessageSnapshotJsonModel.cs new file mode 100644 index 000000000..d8efb6c66 --- /dev/null +++ b/src/Disqord.Core/Models/Message/MessageSnapshotJsonModel.cs @@ -0,0 +1,9 @@ +using Disqord.Serialization.Json; + +namespace Disqord.Models; + +public class MessageSnapshotJsonModel : JsonModel +{ + [JsonProperty("message")] + public MessageJsonModel Message = null!; +} \ No newline at end of file diff --git a/src/Disqord.Gateway/Entities/Cached/Message/CachedMessage.cs b/src/Disqord.Gateway/Entities/Cached/Message/CachedMessage.cs index 302a4f665..f7ad14563 100644 --- a/src/Disqord.Gateway/Entities/Cached/Message/CachedMessage.cs +++ b/src/Disqord.Gateway/Entities/Cached/Message/CachedMessage.cs @@ -53,7 +53,7 @@ protected CachedMessage(IGatewayClient client, CachedMember? author, MessageJson } else { - _author = new TransientUser(Client, model.Author); + _author = new TransientUser(Client, model.Author.Value); } } @@ -72,7 +72,7 @@ public virtual void Update(MessageJsonModel model) } else { - _author = new TransientUser(Client, model.Author); + _author = new TransientUser(Client, model.Author.Value); } } diff --git a/src/Disqord.Gateway/Entities/Cached/Message/User/CachedUserMessage.cs b/src/Disqord.Gateway/Entities/Cached/Message/User/CachedUserMessage.cs index ddec37414..af273a25e 100644 --- a/src/Disqord.Gateway/Entities/Cached/Message/User/CachedUserMessage.cs +++ b/src/Disqord.Gateway/Entities/Cached/Message/User/CachedUserMessage.cs @@ -67,6 +67,8 @@ public class CachedUserMessage : CachedMessage, IGatewayUserMessage, IJsonUpdata /// public IPoll? Poll { get; private set; } + public IReadOnlyList MessageSnapshots { get; private set; } = null!; + public CachedUserMessage(IGatewayClient client, CachedMember? author, MessageJsonModel model) : base(client, author, model) { @@ -96,6 +98,7 @@ public override void Update(MessageJsonModel model) Components = Optional.ConvertOrDefault(model.Components, (models, client) => models.ToReadOnlyList(client, (model, client) => new TransientRowComponent(client, model) as IRowComponent), Client) ?? Array.Empty(); Stickers = Optional.ConvertOrDefault(model.StickerItems, models => models.ToReadOnlyList(model => new TransientMessageSticker(model) as IMessageSticker), Array.Empty()); Poll = Optional.ConvertOrDefault(model.Poll, model => new TransientPoll(model)); + MessageSnapshots = Optional.ConvertOrDefault(model.MessageSnapshots, models => models.ToReadOnlyList(Client, (model, client) => new TransientMessageSnapshot(client, model) as IMessageSnapshot)) ?? Array.Empty(); } public void Update(MessageUpdateJsonModel model) diff --git a/src/Disqord.Gateway/Entities/Transient/Message/TransientGatewayMessage.cs b/src/Disqord.Gateway/Entities/Transient/Message/TransientGatewayMessage.cs index 560f4251a..549198f42 100644 --- a/src/Disqord.Gateway/Entities/Transient/Message/TransientGatewayMessage.cs +++ b/src/Disqord.Gateway/Entities/Transient/Message/TransientGatewayMessage.cs @@ -25,14 +25,14 @@ public IUser Author var guildId = Model.GuildId; if (!guildId.HasValue || !Model.Member.HasValue) { - var user = Client.GetUser(Model.Author.Id); + var user = Client.GetUser(Model.Author.Value.Id); if (user != null) return user; - return _author ??= new TransientUser(Client, Model.Author); + return _author ??= new TransientUser(Client, Model.Author.Value); } - var member = Client.GetMember(guildId.Value, Model.Author.Id); + var member = Client.GetMember(guildId.Value, Model.Author.Value.Id); if (member != null) return member; diff --git a/src/Disqord.Gateway/Entities/Transient/Message/User/TransientGatewayUserMessage.cs b/src/Disqord.Gateway/Entities/Transient/Message/User/TransientGatewayUserMessage.cs index d0af45326..60e523119 100644 --- a/src/Disqord.Gateway/Entities/Transient/Message/User/TransientGatewayUserMessage.cs +++ b/src/Disqord.Gateway/Entities/Transient/Message/User/TransientGatewayUserMessage.cs @@ -105,6 +105,18 @@ public IReadOnlyList Stickers public IPoll? Poll => _poll ??= Optional.ConvertOrDefault(Model.Poll, poll => new TransientPoll(poll)); private IPoll? _poll; + + public IReadOnlyList MessageSnapshots + { + get + { + if (!Model.MessageSnapshots.HasValue) + return Array.Empty(); + + return _messageSnapshots ??= Model.MessageSnapshots.Value.ToReadOnlyList(Client, (model, client) => new TransientMessageSnapshot(client, model)); + } + } + private IReadOnlyList? _messageSnapshots; public TransientGatewayUserMessage(IClient client, MessageJsonModel model) : base(client, model)