From 407c2bd2ae52491fb676a100fd519ce735b1f5e7 Mon Sep 17 00:00:00 2001
From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com>
Date: Sat, 19 Feb 2022 00:03:17 +0200
Subject: [PATCH] Don't crash on invalid mentions
Fixes #816
---
.../MarkdownVisitors/HtmlMarkdownVisitor.cs | 21 ++++++++++++-------
.../PlainTextMarkdownVisitor.cs | 15 ++++++++-----
.../Markdown/MentionKind.cs | 3 ++-
.../Markdown/MentionNode.cs | 3 ++-
.../Markdown/Parsing/MarkdownParser.cs | 12 +++++------
.../Markdown/UnixTimestampNode.cs | 2 +-
6 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs
index 634f2316..c9e98ace 100644
--- a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs
+++ b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs
@@ -107,27 +107,34 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
protected override MarkdownNode VisitMention(MentionNode mention)
{
- if (mention.Kind == MentionKind.Meta)
+ if (mention.Kind == MentionKind.Everyone)
{
_buffer
.Append("")
- .Append("@").Append(HtmlEncode(mention.Id.ToString()))
+ .Append("@everyone")
+ .Append("");
+ }
+ else if (mention.Kind == MentionKind.Here)
+ {
+ _buffer
+ .Append("")
+ .Append("@here")
.Append("");
}
else if (mention.Kind == MentionKind.User)
{
- var member = _context.TryGetMember(mention.Id);
+ var member = mention.TargetId?.Pipe(_context.TryGetMember);
var fullName = member?.User.FullName ?? "Unknown";
var nick = member?.Nick ?? "Unknown";
_buffer
.Append($"")
- .Append("@").Append(HtmlEncode(nick))
+ .Append('@').Append(HtmlEncode(nick))
.Append("");
}
else if (mention.Kind == MentionKind.Channel)
{
- var channel = _context.TryGetChannel(mention.Id);
+ var channel = mention.TargetId?.Pipe(_context.TryGetChannel);
var symbol = channel?.IsVoiceChannel == true ? "🔊" : "#";
var name = channel?.Name ?? "deleted-channel";
@@ -138,7 +145,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
}
else if (mention.Kind == MentionKind.Role)
{
- var role = _context.TryGetRole(mention.Id);
+ var role = mention.TargetId?.Pipe(_context.TryGetRole);
var name = role?.Name ?? "deleted-role";
var color = role?.Color;
@@ -148,7 +155,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
_buffer
.Append($"")
- .Append("@").Append(HtmlEncode(name))
+ .Append('@').Append(HtmlEncode(name))
.Append("");
}
diff --git a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs
index a44a08ee..842ba1aa 100644
--- a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs
+++ b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs
@@ -1,6 +1,7 @@
using System.Text;
using DiscordChatExporter.Core.Markdown;
using DiscordChatExporter.Core.Markdown.Parsing;
+using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors;
@@ -34,20 +35,24 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
protected override MarkdownNode VisitMention(MentionNode mention)
{
- if (mention.Kind == MentionKind.Meta)
+ if (mention.Kind == MentionKind.Everyone)
{
- _buffer.Append($"@{mention.Id}");
+ _buffer.Append("@everyone");
+ }
+ else if (mention.Kind == MentionKind.Here)
+ {
+ _buffer.Append("@here");
}
else if (mention.Kind == MentionKind.User)
{
- var member = _context.TryGetMember(mention.Id);
+ var member = mention.TargetId?.Pipe(_context.TryGetMember);
var name = member?.User.Name ?? "Unknown";
_buffer.Append($"@{name}");
}
else if (mention.Kind == MentionKind.Channel)
{
- var channel = _context.TryGetChannel(mention.Id);
+ var channel =mention.TargetId?.Pipe(_context.TryGetChannel);
var name = channel?.Name ?? "deleted-channel";
_buffer.Append($"#{name}");
@@ -58,7 +63,7 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
}
else if (mention.Kind == MentionKind.Role)
{
- var role = _context.TryGetRole(mention.Id);
+ var role = mention.TargetId?.Pipe(_context.TryGetRole);
var name = role?.Name ?? "deleted-role";
_buffer.Append($"@{name}");
diff --git a/DiscordChatExporter.Core/Markdown/MentionKind.cs b/DiscordChatExporter.Core/Markdown/MentionKind.cs
index 5fb66dbc..d7512363 100644
--- a/DiscordChatExporter.Core/Markdown/MentionKind.cs
+++ b/DiscordChatExporter.Core/Markdown/MentionKind.cs
@@ -2,7 +2,8 @@
internal enum MentionKind
{
- Meta,
+ Everyone,
+ Here,
User,
Channel,
Role
diff --git a/DiscordChatExporter.Core/Markdown/MentionNode.cs b/DiscordChatExporter.Core/Markdown/MentionNode.cs
index cc6458e1..609bf042 100644
--- a/DiscordChatExporter.Core/Markdown/MentionNode.cs
+++ b/DiscordChatExporter.Core/Markdown/MentionNode.cs
@@ -2,4 +2,5 @@
namespace DiscordChatExporter.Core.Markdown;
-internal record MentionNode(Snowflake Id, MentionKind Kind) : MarkdownNode;
\ No newline at end of file
+// Null ID means it's a meta mention or an invalid mention
+internal record MentionNode(Snowflake? TargetId, MentionKind Kind) : MarkdownNode;
\ No newline at end of file
diff --git a/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs b/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs
index 2229402b..7ee1c887 100644
--- a/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs
+++ b/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs
@@ -124,31 +124,31 @@ internal static partial class MarkdownParser
// Capture @everyone
private static readonly IMatcher EveryoneMentionNodeMatcher = new StringMatcher(
"@everyone",
- _ => new MentionNode(Snowflake.Zero, MentionKind.Meta)
+ _ => new MentionNode(null, MentionKind.Everyone)
);
// Capture @here
private static readonly IMatcher HereMentionNodeMatcher = new StringMatcher(
"@here",
- _ => new MentionNode(Snowflake.Zero, MentionKind.Meta)
+ _ => new MentionNode(null, MentionKind.Here)
);
// Capture <@123456> or <@!123456>
private static readonly IMatcher UserMentionNodeMatcher = new RegexMatcher(
new Regex("<@!?(\\d+)>", DefaultRegexOptions),
- (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.User)
+ (_, m) => new MentionNode(Snowflake.TryParse(m.Groups[1].Value), MentionKind.User)
);
// Capture <#123456>
private static readonly IMatcher ChannelMentionNodeMatcher = new RegexMatcher(
new Regex("<#!?(\\d+)>", DefaultRegexOptions),
- (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.Channel)
+ (_, m) => new MentionNode(Snowflake.TryParse(m.Groups[1].Value), MentionKind.Channel)
);
// Capture <@&123456>
private static readonly IMatcher RoleMentionNodeMatcher = new RegexMatcher(
new Regex("<@&(\\d+)>", DefaultRegexOptions),
- (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.Role)
+ (_, m) => new MentionNode(Snowflake.TryParse(m.Groups[1].Value), MentionKind.Role)
);
/* Emoji */
@@ -179,7 +179,7 @@ internal static partial class MarkdownParser
private static readonly IMatcher CustomEmojiNodeMatcher = new RegexMatcher(
new Regex("<(a)?:(.+?):(\\d+?)>", DefaultRegexOptions),
(_, m) => new EmojiNode(
- Snowflake.Parse(m.Groups[3].Value),
+ Snowflake.TryParse(m.Groups[3].Value),
m.Groups[2].Value,
!string.IsNullOrWhiteSpace(m.Groups[1].Value)
)
diff --git a/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs b/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs
index 82a81c2c..23991c7c 100644
--- a/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs
+++ b/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs
@@ -2,5 +2,5 @@
namespace DiscordChatExporter.Core.Markdown;
-// Null means invalid date
+// Null date means invalid timestamp
internal record UnixTimestampNode(DateTimeOffset? Date) : MarkdownNode;
\ No newline at end of file