Don't crash on invalid mentions

Fixes #816
pull/825/head
Oleksii Holub 3 years ago
parent 5b563d4f00
commit 407c2bd2ae

@ -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("<span class=\"mention\">")
.Append("@").Append(HtmlEncode(mention.Id.ToString()))
.Append("@everyone")
.Append("</span>");
}
else if (mention.Kind == MentionKind.Here)
{
_buffer
.Append("<span class=\"mention\">")
.Append("@here")
.Append("</span>");
}
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($"<span class=\"mention\" title=\"{HtmlEncode(fullName)}\">")
.Append("@").Append(HtmlEncode(nick))
.Append('@').Append(HtmlEncode(nick))
.Append("</span>");
}
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($"<span class=\"mention\" style=\"{style}\">")
.Append("@").Append(HtmlEncode(name))
.Append('@').Append(HtmlEncode(name))
.Append("</span>");
}

@ -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}");

@ -2,7 +2,8 @@
internal enum MentionKind
{
Meta,
Everyone,
Here,
User,
Channel,
Role

@ -2,4 +2,5 @@
namespace DiscordChatExporter.Core.Markdown;
internal record MentionNode(Snowflake Id, MentionKind Kind) : MarkdownNode;
// Null ID means it's a meta mention or an invalid mention
internal record MentionNode(Snowflake? TargetId, MentionKind Kind) : MarkdownNode;

@ -124,31 +124,31 @@ internal static partial class MarkdownParser
// Capture @everyone
private static readonly IMatcher<MarkdownNode> EveryoneMentionNodeMatcher = new StringMatcher<MarkdownNode>(
"@everyone",
_ => new MentionNode(Snowflake.Zero, MentionKind.Meta)
_ => new MentionNode(null, MentionKind.Everyone)
);
// Capture @here
private static readonly IMatcher<MarkdownNode> HereMentionNodeMatcher = new StringMatcher<MarkdownNode>(
"@here",
_ => new MentionNode(Snowflake.Zero, MentionKind.Meta)
_ => new MentionNode(null, MentionKind.Here)
);
// Capture <@123456> or <@!123456>
private static readonly IMatcher<MarkdownNode> UserMentionNodeMatcher = new RegexMatcher<MarkdownNode>(
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<MarkdownNode> ChannelMentionNodeMatcher = new RegexMatcher<MarkdownNode>(
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<MarkdownNode> RoleMentionNodeMatcher = new RegexMatcher<MarkdownNode>(
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<MarkdownNode> CustomEmojiNodeMatcher = new RegexMatcher<MarkdownNode>(
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)
)

@ -2,5 +2,5 @@
namespace DiscordChatExporter.Core.Markdown;
// Null means invalid date
// Null date means invalid timestamp
internal record UnixTimestampNode(DateTimeOffset? Date) : MarkdownNode;
Loading…
Cancel
Save