diff --git a/DisCatSharp/Clients/DiscordClient.Dispatch.cs b/DisCatSharp/Clients/DiscordClient.Dispatch.cs index 2b38712164..3677716d7e 100644 --- a/DisCatSharp/Clients/DiscordClient.Dispatch.cs +++ b/DisCatSharp/Clients/DiscordClient.Dispatch.cs @@ -2377,6 +2377,17 @@ internal async Task OnMessageCreateEventAsync(DiscordMessage message, TransportU message.ReferencedMessage.PopulateMentions(); } + message.MessageSnapshots?.ForEach(x => + { + x.Message.Discord = this; + if (x.Message.MentionedUsersInternal.Count is not 0) + x.Message.MentionedUsers.ForEach(u => u.Discord = this); + if (x.Message.AttachmentsInternal.Count is not 0) + x.Message.AttachmentsInternal.ForEach(a => a.Discord = this); + if (x.Message.EmbedsInternal.Count is not 0) + x.Message.EmbedsInternal.ForEach(a => a.Discord = this); + }); + foreach (var sticker in message.Stickers) sticker.Discord = this; @@ -2435,6 +2446,28 @@ internal async Task OnMessageUpdateEventAsync(DiscordMessage message, TransportU message.IsTts = eventMessage.IsTts; } + message.MessageSnapshots?.ForEach(x => + { + x.Message.Discord = this; + if (x.Message.MentionedUsersInternal.Count is not 0) + x.Message.MentionedUsers.ForEach(u => u.Discord = this); + if (x.Message.AttachmentsInternal.Count is not 0) + x.Message.AttachmentsInternal.ForEach(a => a.Discord = this); + if (x.Message.EmbedsInternal.Count is not 0) + x.Message.EmbedsInternal.ForEach(a => a.Discord = this); + }); + + oldmsg?.MessageSnapshots?.ForEach(x => + { + x.Message.Discord = this; + if (x.Message.MentionedUsersInternal.Count is not 0) + x.Message.MentionedUsers.ForEach(u => u.Discord = this); + if (x.Message.AttachmentsInternal.Count is not 0) + x.Message.AttachmentsInternal.ForEach(a => a.Discord = this); + if (x.Message.EmbedsInternal.Count is not 0) + x.Message.EmbedsInternal.ForEach(a => a.Discord = this); + }); + message.PopulateMentions(); var ea = new MessageUpdateEventArgs(this.ServiceProvider) diff --git a/DisCatSharp/Entities/Message/DiscordForwardedMessage.cs b/DisCatSharp/Entities/Message/DiscordForwardedMessage.cs new file mode 100644 index 0000000000..d06a142274 --- /dev/null +++ b/DisCatSharp/Entities/Message/DiscordForwardedMessage.cs @@ -0,0 +1,178 @@ +using System.Collections.Generic; +using System; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; + +using DisCatSharp.Attributes; +using DisCatSharp.Enums; +using DisCatSharp.Net.Abstractions; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +[DiscordInExperiment, Experimental("This is subject to change at any time.")] +public class DiscordForwardedMessage : ObservableApiObject +{ + internal DiscordForwardedMessage() + { + this._attachmentsLazy = new(() => new ReadOnlyCollection(this.AttachmentsInternal)); + this._embedsLazy = new(() => new ReadOnlyCollection(this.EmbedsInternal)); + /*this._mentionedChannelsLazy = new(() => this.MentionedChannelsInternal != null + ? new ReadOnlyCollection(this.MentionedChannelsInternal) + : Array.Empty()); + this._mentionedRolesLazy = new(() => this.MentionedRolesInternal != null ? new ReadOnlyCollection(this.MentionedRolesInternal) : Array.Empty()); + this.MentionedUsersLazy = new(() => new ReadOnlyCollection(this.MentionedUsersInternal));*/ + } + + /// + /// Gets the type of the message. + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public MessageType? MessageType { get; internal set; } + + /// + /// Gets the message's content. + /// + [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] + public string Content { get; internal set; } + + /// + /// Gets embeds attached to this message. + /// + [JsonIgnore] + public IReadOnlyList Embeds + => this._embedsLazy.Value; + + [JsonProperty("embeds", NullValueHandling = NullValueHandling.Ignore)] + internal List EmbedsInternal = []; + + [JsonIgnore] + private readonly Lazy> _embedsLazy; + + /// + /// Gets files attached to this message. + /// + [JsonIgnore] + public IReadOnlyList Attachments + => this._attachmentsLazy.Value; + + [JsonProperty("attachments", NullValueHandling = NullValueHandling.Ignore)] + internal List AttachmentsInternal = []; + + [JsonIgnore] + private readonly Lazy> _attachmentsLazy; + + /// + /// Gets the message's creation timestamp. + /// + [JsonIgnore] + public DateTimeOffset? Timestamp + => !string.IsNullOrWhiteSpace(this.TimestampRaw) && DateTimeOffset.TryParse(this.TimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; + + /// + /// Gets the message's creation timestamp as raw string. + /// + [JsonProperty("timestamp", NullValueHandling = NullValueHandling.Ignore)] + internal string TimestampRaw { get; set; } + + /// + /// Gets the message's edit timestamp. Will be null if the message was not edited. + /// + [JsonIgnore] + public DateTimeOffset? EditedTimestamp + => !string.IsNullOrWhiteSpace(this.EditedTimestampRaw) && DateTimeOffset.TryParse(this.EditedTimestampRaw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dto) ? dto : null; + + /// + /// Gets the message's edit timestamp as raw string. Will be null if the message was not edited. + /// + [JsonProperty("edited_timestamp", NullValueHandling = NullValueHandling.Ignore)] + internal string EditedTimestampRaw { get; set; } + + /// + /// Gets whether this message was edited. + /// + [JsonIgnore] + public bool IsEdited + => !string.IsNullOrWhiteSpace(this.EditedTimestampRaw); + + /// + /// Gets the bitwise flags for this message. + /// + [JsonProperty("flags", NullValueHandling = NullValueHandling.Ignore)] + public MessageFlags? Flags { get; internal set; } + + /// + /// Gets whether the message mentions everyone. + /// + [JsonProperty("mention_everyone", NullValueHandling = NullValueHandling.Ignore)] + public bool MentionEveryone { get; internal set; } + + /* + TODO: Implement if stable + /// + /// Gets users or members mentioned by this message. + /// + [JsonIgnore] + public IReadOnlyList MentionedUsers + => this.MentionedUsersLazy.Value; + */ + + [JsonProperty("mentions", NullValueHandling = NullValueHandling.Ignore)] + internal List MentionedUsersInternal { get; set; } = []; + + /// + /// Gets users mentioned by this message. + /// + [JsonIgnore] + public List MentionedUsers + => this.MentionedUsersInternal.Count is not 0 + ? this.MentionedUsersInternal.Select(x => new DiscordUser(x) + { + Discord = this.Discord + }).ToList() + : []; + + /* + TODO: Implement if stable + + [JsonIgnore] + internal readonly Lazy> MentionedUsersLazy; + + /// + /// Gets roles mentioned by this message. + /// + [JsonIgnore] + public IReadOnlyList MentionedRoles + => this._mentionedRolesLazy.Value; + + [JsonIgnore] + internal List MentionedRolesInternal; + */ + + /// + /// Gets role ids mentioned by this message. + /// + [JsonProperty("mention_roles")] + public List MentionedRoleIds = []; + + /* + TODO: Implement if stable + [JsonIgnore] + private readonly Lazy> _mentionedRolesLazy; + + /// + /// Gets channels mentioned by this message. + /// + [JsonIgnore] + public IReadOnlyList MentionedChannels + => this._mentionedChannelsLazy.Value; + + [JsonIgnore] + internal List MentionedChannelsInternal; + + [JsonIgnore] + private readonly Lazy> _mentionedChannelsLazy; + */ +} diff --git a/DisCatSharp/Entities/Message/DiscordMessage.cs b/DisCatSharp/Entities/Message/DiscordMessage.cs index 2bac68e6dd..29656f5b3c 100644 --- a/DisCatSharp/Entities/Message/DiscordMessage.cs +++ b/DisCatSharp/Entities/Message/DiscordMessage.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; +using DisCatSharp.Attributes; using DisCatSharp.Enums; using DisCatSharp.Exceptions; using DisCatSharp.Net.Abstractions; @@ -345,12 +346,32 @@ public IReadOnlyList Reactions internal InternalDiscordMessageReference? InternalReference { get; set; } /// - /// Gets the original message reference from the cross-posted message. + /// Gets the message reference. /// [JsonIgnore] public DiscordMessageReference Reference => this.InternalReference.HasValue ? this?.InternalBuildMessageReference() : null; + /// + /// Gets the message snapshots. + /// + [JsonProperty("message_snapshots", NullValueHandling = NullValueHandling.Ignore)] + public List? MessageSnapshots { get; internal set; } + + /// + /// Gets whether this message has a message reference (reply, announcement, etc.). + /// + [Experimental("We provide that temporary, as we figure out things.")] + public bool HasMessageReference + => this.InternalReference is { Type: ReferenceType.Default }; + + /// + /// Gets whether this message has forwarded messages. + /// + [Experimental("We provide that temporary, as we figure out things.")] + public bool HasMessageSnapshots + => this.InternalReference is { Type: ReferenceType.Forward }; + /// /// Gets the bitwise flags for this message. /// @@ -474,6 +495,7 @@ internal DiscordMessageReference InternalBuildMessageReference() var guildId = this.InternalReference.Value.GuildId; var channelId = this.InternalReference.Value.ChannelId; var messageId = this.InternalReference.Value.MessageId; + var type = this.InternalReference.Value.Type; var reference = new DiscordMessageReference(); @@ -487,6 +509,7 @@ internal DiscordMessageReference InternalBuildMessageReference() }; var channel = client.InternalGetCachedChannel(channelId.Value); + reference.Type = type; if (channel == null) { diff --git a/DisCatSharp/Entities/Message/DiscordMessageReference.cs b/DisCatSharp/Entities/Message/DiscordMessageReference.cs index 4c2427a511..a8c69b63a4 100644 --- a/DisCatSharp/Entities/Message/DiscordMessageReference.cs +++ b/DisCatSharp/Entities/Message/DiscordMessageReference.cs @@ -1,3 +1,5 @@ +using DisCatSharp.Enums; + using Newtonsoft.Json; namespace DisCatSharp.Entities; @@ -7,6 +9,11 @@ namespace DisCatSharp.Entities; /// public class DiscordMessageReference { + /// + /// Gets the type of the reference. + /// + public ReferenceType Type { get; internal set; } + /// /// Gets the original message. /// @@ -37,6 +44,21 @@ internal DiscordMessageReference() internal struct InternalDiscordMessageReference { + public InternalDiscordMessageReference() + { + this.Type = ReferenceType.Default; + this.MessageId = null; + this.ChannelId = null; + this.GuildId = null; + this.FailIfNotExists = false; + } + + /// + /// Gets the type of the reference. + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + internal ReferenceType Type { get; set; } + /// /// Gets the message id. /// diff --git a/DisCatSharp/Entities/Message/DiscordMessageSnapshots.cs b/DisCatSharp/Entities/Message/DiscordMessageSnapshots.cs new file mode 100644 index 0000000000..45dbf9c342 --- /dev/null +++ b/DisCatSharp/Entities/Message/DiscordMessageSnapshots.cs @@ -0,0 +1,12 @@ +using DisCatSharp.Attributes; + +using Newtonsoft.Json; + +namespace DisCatSharp.Entities; + +[DiscordInExperiment, Experimental] +public class DiscordMessageSnapshot : ObservableApiObject +{ + [JsonProperty("message")] + public DiscordForwardedMessage Message { get; internal set; } +} diff --git a/DisCatSharp/Enums/Message/ReferenceType.cs b/DisCatSharp/Enums/Message/ReferenceType.cs new file mode 100644 index 0000000000..5657e4db40 --- /dev/null +++ b/DisCatSharp/Enums/Message/ReferenceType.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DisCatSharp.Enums; + +/// +/// Represents the message reference type. +/// +public enum ReferenceType +{ + /// + /// A standard reference used by replies. + /// + Default = 0, + + /// + /// Reference used to point to a message at a point in time. + /// + Forward = 1 +}