Hide message content in HTML when linking to an image

Closes #695
pull/882/head
Oleksii Holub 2 years ago
parent 356b1a6afd
commit edba9f36a7

@ -41,16 +41,14 @@ public class DateRangeSpecs : IClassFixture<TempOutputFixture>
After = Snowflake.FromDate(after)
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
var timestamps = document
// Assert
var timestamps = Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("timestamp").GetDateTimeOffset())
.ToArray();
// Assert
timestamps.All(t => t > after).Should().BeTrue();
timestamps.Should().BeEquivalentTo(new[]
@ -87,16 +85,14 @@ public class DateRangeSpecs : IClassFixture<TempOutputFixture>
Before = Snowflake.FromDate(before)
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
var timestamps = document
// Assert
var timestamps = Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("timestamp").GetDateTimeOffset())
.ToArray();
// Assert
timestamps.All(t => t < before).Should().BeTrue();
timestamps.Should().BeEquivalentTo(new[]
@ -133,16 +129,14 @@ public class DateRangeSpecs : IClassFixture<TempOutputFixture>
After = Snowflake.FromDate(after)
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
var timestamps = document
// Assert
var timestamps = Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("timestamp").GetDateTimeOffset())
.ToArray();
// Assert
timestamps.All(t => t < before && t > after).Should().BeTrue();
timestamps.Should().BeEquivalentTo(new[]

@ -39,11 +39,9 @@ public class FilterSpecs : IClassFixture<TempOutputFixture>
MessageFilter = MessageFilter.Parse("some text")
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
// Assert
document
Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
@ -67,11 +65,9 @@ public class FilterSpecs : IClassFixture<TempOutputFixture>
MessageFilter = MessageFilter.Parse("from:Tyrrrz")
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
// Assert
document
Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("author").GetProperty("name").GetString())
@ -95,11 +91,9 @@ public class FilterSpecs : IClassFixture<TempOutputFixture>
MessageFilter = MessageFilter.Parse("has:image")
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
// Assert
document
Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
@ -123,11 +117,9 @@ public class FilterSpecs : IClassFixture<TempOutputFixture>
MessageFilter = MessageFilter.Parse("has:pin")
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
// Assert
document
Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
@ -151,11 +143,9 @@ public class FilterSpecs : IClassFixture<TempOutputFixture>
MessageFilter = MessageFilter.Parse("mentions:Tyrrrz")
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Json.Parse(data);
// Assert
document
Json
.Parse(await File.ReadAllTextAsync(filePath))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Linq;
using System.Threading.Tasks;
using AngleSharp.Dom;
using DiscordChatExporter.Cli.Tests.Fixtures;
using DiscordChatExporter.Cli.Tests.TestData;
@ -26,8 +27,6 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885587844989612074")
);
var fileUrl = message.QuerySelector(".chatlog__attachment a")?.GetAttribute("href");
// Assert
message.Text().Should().ContainAll(
"Generic file attachment",
@ -35,9 +34,13 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
"11 bytes"
);
fileUrl.Should().StartWithEquivalentOf(
"https://cdn.discordapp.com/attachments/885587741654536192/885587844964417596/Test.txt"
);
message
.QuerySelectorAll("a")
.Select(e => e.GetAttribute("href"))
.Should()
.Contain(
"https://cdn.discordapp.com/attachments/885587741654536192/885587844964417596/Test.txt"
);
}
[Fact]
@ -49,14 +52,16 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885654862656843786")
);
var imageUrl = message.QuerySelector(".chatlog__attachment img")?.GetAttribute("src");
// Assert
message.Text().Should().Contain("Image attachment");
imageUrl.Should().StartWithEquivalentOf(
"https://cdn.discordapp.com/attachments/885587741654536192/885654862430359613/bird-thumbnail.png"
);
message
.QuerySelectorAll("img")
.Select(e => e.GetAttribute("src"))
.Should()
.Contain(
"https://cdn.discordapp.com/attachments/885587741654536192/885654862430359613/bird-thumbnail.png"
);
}
[Fact]
@ -68,12 +73,11 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885655761919836171")
);
var videoUrl = message.QuerySelector("video source")?.GetAttribute("src");
// Assert
message.Text().Should().Contain("Video attachment");
videoUrl.Should().StartWithEquivalentOf(
var videoUrl = message.QuerySelector("video source")?.GetAttribute("src");
videoUrl.Should().StartWith(
"https://cdn.discordapp.com/attachments/885587741654536192/885655761512968233/file_example_MP4_640_3MG.mp4"
);
}
@ -87,12 +91,11 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885656175620808734")
);
var audioUrl = message.QuerySelector("audio source")?.GetAttribute("src");
// Assert
message.Text().Should().Contain("Audio attachment");
audioUrl.Should().StartWithEquivalentOf(
var audioUrl = message.QuerySelector("audio source")?.GetAttribute("src");
audioUrl.Should().StartWith(
"https://cdn.discordapp.com/attachments/885587741654536192/885656175348187146/file_example_MP3_1MG.mp3"
);
}

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using AngleSharp.Dom;
using DiscordChatExporter.Cli.Tests.Fixtures;
using DiscordChatExporter.Cli.Tests.TestData;
using DiscordChatExporter.Core.Discord;
using FluentAssertions;
using Xunit;
@ -35,7 +36,7 @@ public class ContentSpecs : IClassFixture<ExportWrapperFixture>
"885169254029213696"
);
messages.Select(e => e.QuerySelector(".chatlog__content")?.Text().Trim()).Should().Equal(
messages.SelectMany(e => e.Text()).Should().ContainInOrder(
"Hello world",
"Goodbye world",
"Foo bar",
@ -46,4 +47,18 @@ public class ContentSpecs : IClassFixture<ExportWrapperFixture>
"Yeet"
);
}
[Fact]
public async Task Message_content_is_hidden_if_it_only_contains_a_link_to_an_image()
{
// Act
var message = await _exportWrapper.GetMessageAsHtmlAsync(
ChannelIds.EmbedTestCases,
Snowflake.Parse("991768701126852638")
);
// Assert
var content = message.QuerySelector(".chatlog__content")?.Text();
content.Should().BeNullOrEmpty();
}
}

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Linq;
using System.Threading.Tasks;
using AngleSharp.Dom;
using DiscordChatExporter.Cli.Tests.Fixtures;
using DiscordChatExporter.Cli.Tests.TestData;
@ -39,18 +40,20 @@ public class EmbedSpecs : IClassFixture<ExportWrapperFixture>
}
[Fact]
public async Task Message_with_a_link_to_an_image_is_rendered_with_that_image()
public async Task Message_with_a_link_to_an_image_contains_an_embed_of_that_image()
{
// Act
var message = await _exportWrapper.GetMessageAsHtmlAsync(
ChannelIds.EmbedTestCases,
Snowflake.Parse("991758772349440053")
Snowflake.Parse("991768701126852638")
);
var imageSrc = message.QuerySelector("img")?.GetAttribute("src");
// Assert
imageSrc.Should().StartWithEquivalentOf("https://i.redd.it/f8w05ja8s4e61.png");
message
.QuerySelectorAll("img")
.Select(e => e.GetAttribute("src"))
.Should()
.Contain("https://i.redd.it/f8w05ja8s4e61.png");
}
[Fact]
@ -62,10 +65,9 @@ public class EmbedSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("867886632203976775")
);
var iframeSrc = message.QuerySelector("iframe")?.GetAttribute("src");
// Assert
iframeSrc.Should().StartWithEquivalentOf("https://open.spotify.com/embed/track/1LHZMWefF9502NPfArRfvP");
var iframeUrl = message.QuerySelector("iframe")?.GetAttribute("src");
iframeUrl.Should().StartWith("https://open.spotify.com/embed/track/1LHZMWefF9502NPfArRfvP");
}
[Fact]
@ -77,9 +79,8 @@ public class EmbedSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("866472508588294165")
);
var iframeSrc = message.QuerySelector("iframe")?.GetAttribute("src");
// Assert
iframeSrc.Should().StartWithEquivalentOf("https://www.youtube.com/embed/qOWW4OlgbvE");
var iframeUrl = message.QuerySelector("iframe")?.GetAttribute("src");
iframeUrl.Should().StartWith("https://www.youtube.com/embed/qOWW4OlgbvE");
}
}

@ -27,7 +27,7 @@ public class MentionSpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("User mention: @Tyrrrz");
message.Text().Should().Contain("User mention: @Tyrrrz");
message.InnerHtml.Should().Contain("Tyrrrz#5447");
}
@ -41,7 +41,7 @@ public class MentionSpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("Text channel mention: #mention-tests");
message.Text().Should().Contain("Text channel mention: #mention-tests");
}
[Fact]
@ -54,7 +54,7 @@ public class MentionSpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("Voice channel mention: 🔊chaos-vc");
message.Text().Should().Contain("Voice channel mention: 🔊chaos-vc");
}
[Fact]
@ -67,6 +67,6 @@ public class MentionSpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("Role mention: @Role 1");
message.Text().Should().Contain("Role mention: @Role 1");
}
}

@ -27,8 +27,8 @@ public class ReplySpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("reply to original");
message.QuerySelector(".chatlog__reference-link")?.Text().Trim().Should().Contain("original");
message.Text().Should().Contain("reply to original");
message.QuerySelector(".chatlog__reference-link")?.Text().Should().Contain("original");
}
[Fact]
@ -41,9 +41,10 @@ public class ReplySpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("reply to deleted");
message.QuerySelector(".chatlog__reference-link")?.Text().Trim().Should()
.Contain("Original message was deleted or could not be loaded.");
message.Text().Should().Contain("reply to deleted");
message.QuerySelector(".chatlog__reference-link")?.Text().Should().Contain(
"Original message was deleted or could not be loaded."
);
}
[Fact]
@ -56,8 +57,7 @@ public class ReplySpecs : IClassFixture<ExportWrapperFixture>
);
// Assert
message.Text().Trim().Should().Contain("reply to attachment");
message.QuerySelector(".chatlog__reference-link")?.Text().Trim().Should()
.Contain("Click to see attachment");
message.Text().Should().Contain("reply to attachment");
message.QuerySelector(".chatlog__reference-link")?.Text().Should().Contain("Click to see attachment");
}
}

@ -25,12 +25,9 @@ public class StickerSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("939670623158943754")
);
var container = message.QuerySelector("[title='rock']");
var sourceUrl = container?.QuerySelector("img")?.GetAttribute("src");
// Assert
container.Should().NotBeNull();
sourceUrl.Should().Be("https://discord.com/stickers/904215665597120572.png");
var stickerUrl = message.QuerySelector("[title='rock'] img")?.GetAttribute("src");
stickerUrl.Should().Be("https://discord.com/stickers/904215665597120572.png");
}
[Fact]
@ -42,11 +39,8 @@ public class StickerSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("939670526517997590")
);
var container = message.QuerySelector("[title='Yikes']");
var sourceUrl = container?.QuerySelector("div[data-source]")?.GetAttribute("data-source");
// Assert
container.Should().NotBeNull();
sourceUrl.Should().Be("https://discord.com/stickers/816087132447178774.json");
var stickerUrl = message.QuerySelector("[title='Yikes'] div[data-source]")?.GetAttribute("data-source");
stickerUrl.Should().Be("https://discord.com/stickers/816087132447178774.json");
}
}

@ -26,13 +26,12 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885587844989612074")
);
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
// Assert
message.GetProperty("content").GetString().Should().Be("Generic file attachment");
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
attachments.Should().HaveCount(1);
attachments.Single().GetProperty("url").GetString().Should().StartWithEquivalentOf(
attachments.Single().GetProperty("url").GetString().Should().StartWith(
"https://cdn.discordapp.com/attachments/885587741654536192/885587844964417596/Test.txt"
);
attachments.Single().GetProperty("fileName").GetString().Should().Be("Test.txt");
@ -48,13 +47,12 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885654862656843786")
);
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
// Assert
message.GetProperty("content").GetString().Should().Be("Image attachment");
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
attachments.Should().HaveCount(1);
attachments.Single().GetProperty("url").GetString().Should().StartWithEquivalentOf(
attachments.Single().GetProperty("url").GetString().Should().StartWith(
"https://cdn.discordapp.com/attachments/885587741654536192/885654862430359613/bird-thumbnail.png"
);
attachments.Single().GetProperty("fileName").GetString().Should().Be("bird-thumbnail.png");
@ -70,13 +68,12 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885655761919836171")
);
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
// Assert
message.GetProperty("content").GetString().Should().Be("Video attachment");
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
attachments.Should().HaveCount(1);
attachments.Single().GetProperty("url").GetString().Should().StartWithEquivalentOf(
attachments.Single().GetProperty("url").GetString().Should().StartWith(
"https://cdn.discordapp.com/attachments/885587741654536192/885655761512968233/file_example_MP4_640_3MG.mp4"
);
attachments.Single().GetProperty("fileName").GetString().Should().Be("file_example_MP4_640_3MG.mp4");
@ -92,13 +89,12 @@ public class AttachmentSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("885656175620808734")
);
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
// Assert
message.GetProperty("content").GetString().Should().Be("Audio attachment");
var attachments = message.GetProperty("attachments").EnumerateArray().ToArray();
attachments.Should().HaveCount(1);
attachments.Single().GetProperty("url").GetString().Should().StartWithEquivalentOf(
attachments.Single().GetProperty("url").GetString().Should().StartWith(
"https://cdn.discordapp.com/attachments/885587741654536192/885656175348187146/file_example_MP3_1MG.mp3"
);
attachments.Single().GetProperty("fileName").GetString().Should().Be("file_example_MP3_1MG.mp3");

@ -26,30 +26,29 @@ public class EmbedSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("866769910729146400")
);
var embed = message
.GetProperty("embeds")
.EnumerateArray()
.Single();
var embedAuthor = embed.GetProperty("author");
var embedThumbnail = embed.GetProperty("thumbnail");
var embedFooter = embed.GetProperty("footer");
var embedFields = embed.GetProperty("fields").EnumerateArray().ToArray();
// Assert
var embed = message.GetProperty("embeds").EnumerateArray().Single();
embed.GetProperty("title").GetString().Should().Be("Embed title");
embed.GetProperty("url").GetString().Should().Be("https://example.com");
embed.GetProperty("timestamp").GetString().Should().Be("2021-07-14T21:00:00+00:00");
embed.GetProperty("description").GetString().Should().Be("**Embed** _description_");
embed.GetProperty("color").GetString().Should().Be("#58B9FF");
var embedAuthor = embed.GetProperty("author");
embedAuthor.GetProperty("name").GetString().Should().Be("Embed author");
embedAuthor.GetProperty("url").GetString().Should().Be("https://example.com/author");
embedAuthor.GetProperty("iconUrl").GetString().Should().NotBeNullOrWhiteSpace();
var embedThumbnail = embed.GetProperty("thumbnail");
embedThumbnail.GetProperty("url").GetString().Should().NotBeNullOrWhiteSpace();
embedThumbnail.GetProperty("width").GetInt32().Should().Be(120);
embedThumbnail.GetProperty("height").GetInt32().Should().Be(120);
var embedFooter = embed.GetProperty("footer");
embedFooter.GetProperty("text").GetString().Should().Be("Embed footer");
embedFooter.GetProperty("iconUrl").GetString().Should().NotBeNullOrWhiteSpace();
var embedFields = embed.GetProperty("fields").EnumerateArray().ToArray();
embedFields.Should().HaveCount(3);
embedFields[0].GetProperty("name").GetString().Should().Be("Field 1");
embedFields[0].GetProperty("value").GetString().Should().Be("Value 1");

@ -26,12 +26,12 @@ public class StickerSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("939670623158943754")
);
// Assert
var sticker = message
.GetProperty("stickers")
.EnumerateArray()
.Single();
// Assert
sticker.GetProperty("id").GetString().Should().Be("904215665597120572");
sticker.GetProperty("name").GetString().Should().Be("rock");
sticker.GetProperty("format").GetString().Should().Be("PngAnimated");
@ -47,12 +47,12 @@ public class StickerSpecs : IClassFixture<ExportWrapperFixture>
Snowflake.Parse("939670526517997590")
);
// Assert
var sticker = message
.GetProperty("stickers")
.EnumerateArray()
.Single();
// Assert
sticker.GetProperty("id").GetString().Should().Be("816087132447178774");
sticker.GetProperty("name").GetString().Should().Be("Yikes");
sticker.GetProperty("format").GetString().Should().Be("Lottie");

@ -39,11 +39,9 @@ public class SelfContainedSpecs : IClassFixture<TempOutputFixture>
ShouldDownloadMedia = true
}.ExecuteAsync(new FakeConsole());
var data = await File.ReadAllTextAsync(filePath);
var document = Html.Parse(data);
// Assert
document
Html
.Parse(await File.ReadAllTextAsync(filePath))
.QuerySelectorAll("body [src]")
.Select(e => e.GetAttribute("src")!)
.Select(f => Path.GetFullPath(f, dirPath))

@ -2,6 +2,7 @@
@using System.Linq
@using System.Threading.Tasks
@using DiscordChatExporter.Core.Discord.Data
@using DiscordChatExporter.Core.Discord.Data.Embeds
@using DiscordChatExporter.Core.Exporting.Writers.Html;
@using DiscordChatExporter.Core.Utils.Extensions
@ -48,6 +49,16 @@
var isFirst = i == 0;
var message = Model.Messages[i];
// Hide message content if it only contains a link to an image which is embedded, and nothing else
var isContentHidden =
message.Embeds.Count == 1 &&
message.Content.Trim() == PlainImageEmbedProjection.TryResolve(message.Embeds.Single())?.Url;
var isReferencedContentHidden =
message.ReferencedMessage is not null &&
message.ReferencedMessage.Embeds.Count == 1 &&
message.ReferencedMessage.Content.Trim() == PlainImageEmbedProjection.TryResolve(message.ReferencedMessage.Embeds.Single())?.Url;
<div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
<div class="chatlog__message">
@{/* Left side */}
@ -83,7 +94,7 @@
<div class="chatlog__reference-author" style="@(referencedUserColor is not null ? $"color: rgb({referencedUserColor.Value.R}, {referencedUserColor.Value.G}, {referencedUserColor.Value.B})" : null)" title="@message.ReferencedMessage.Author.FullName">@referencedUserNick</div>
<div class="chatlog__reference-content">
<span class="chatlog__reference-link" onclick="scrollToMessage(event, '@message.ReferencedMessage.Id')">
@if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content))
@if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !isReferencedContentHidden)
{
<!--wmm:ignore-->@Raw(FormatEmbedMarkdown(message.ReferencedMessage.Content))<!--/wmm:ignore-->
}
@ -134,7 +145,10 @@
{
<div class="chatlog__content chatlog__markdown">
@{/* Text */}
<span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Raw(FormatMarkdown(message.Content))<!--/wmm:ignore--></span>
@if (!isContentHidden)
{
<span class="chatlog__markdown-preserve"><!--wmm:ignore-->@Raw(FormatMarkdown(message.Content))<!--/wmm:ignore--></span>
}
@{/* Edited timestamp */}
@if (message.EditedTimestamp is not null)

Loading…
Cancel
Save