Render server cross-posts properly

Closes #633
This commit is contained in:
Tyrrrz 2023-02-09 18:44:24 +02:00
parent 93799eb231
commit 049338009e
22 changed files with 96 additions and 43 deletions

View file

@ -0,0 +1,8 @@
using Xunit;
namespace DiscordChatExporter.Cli.Tests.Fixtures;
[CollectionDefinition(nameof(ExportWrapperCollection))]
public class ExportWrapperCollection : ICollectionFixture<ExportWrapperFixture>
{
}

View file

@ -6,7 +6,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class CsvContentSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class CsvContentSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -15,6 +15,7 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
[Collection(nameof(ExportWrapperCollection))]
public class DateRangeSpecs : IClassFixture<TempOutputFixture> public class DateRangeSpecs : IClassFixture<TempOutputFixture>
{ {
private readonly TempOutputFixture _tempOutput; private readonly TempOutputFixture _tempOutput;

View file

@ -14,6 +14,7 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
[Collection(nameof(ExportWrapperCollection))]
public class FilterSpecs : IClassFixture<TempOutputFixture> public class FilterSpecs : IClassFixture<TempOutputFixture>
{ {
private readonly TempOutputFixture _tempOutput; private readonly TempOutputFixture _tempOutput;

View file

@ -9,7 +9,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class HtmlAttachmentSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class HtmlAttachmentSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -3,12 +3,14 @@ using System.Threading.Tasks;
using AngleSharp.Dom; using AngleSharp.Dom;
using DiscordChatExporter.Cli.Tests.Fixtures; using DiscordChatExporter.Cli.Tests.Fixtures;
using DiscordChatExporter.Cli.Tests.TestData; using DiscordChatExporter.Cli.Tests.TestData;
using DiscordChatExporter.Core.Discord;
using FluentAssertions; using FluentAssertions;
using Xunit; using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class HtmlContentSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class HtmlContentSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;
@ -46,4 +48,21 @@ public class HtmlContentSpecs : IClassFixture<ExportWrapperFixture>
"Yeet" "Yeet"
); );
} }
[Fact]
public async Task Messages_cross_posted_from_other_guilds_are_rendered_with_the_server_tag()
{
// https://github.com/Tyrrrz/DiscordChatExporter/issues/633
// Act
var message = await _exportWrapper.GetMessageAsHtmlAsync(
ChannelIds.ReplyTestCases,
Snowflake.Parse("1072165330853576876")
);
// Assert
message.Text().Should().Contain("This is a test message from an announcement channel on another server");
message.Text().Should().Contain("SERVER");
message.QuerySelector(".chatlog__reply-link").Should().BeNull();
}
} }

View file

@ -9,7 +9,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class HtmlEmbedSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class HtmlEmbedSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -13,6 +13,7 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
[Collection(nameof(ExportWrapperCollection))]
public class HtmlGroupingSpecs : IClassFixture<TempOutputFixture> public class HtmlGroupingSpecs : IClassFixture<TempOutputFixture>
{ {
private readonly TempOutputFixture _tempOutput; private readonly TempOutputFixture _tempOutput;

View file

@ -8,7 +8,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class HtmlMentionSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class HtmlMentionSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -8,7 +8,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class HtmlReplySpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class HtmlReplySpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;
@ -28,7 +29,7 @@ public class HtmlReplySpecs : IClassFixture<ExportWrapperFixture>
// Assert // Assert
message.Text().Should().Contain("reply to original"); message.Text().Should().Contain("reply to original");
message.QuerySelector(".chatlog__reference-link")?.Text().Should().Contain("original"); message.QuerySelector(".chatlog__reply-link")?.Text().Should().Contain("original");
} }
[Fact] [Fact]
@ -44,7 +45,7 @@ public class HtmlReplySpecs : IClassFixture<ExportWrapperFixture>
// Assert // Assert
message.Text().Should().Contain("reply to deleted"); message.Text().Should().Contain("reply to deleted");
message.QuerySelector(".chatlog__reference-link")?.Text().Should().Contain( message.QuerySelector(".chatlog__reply-link")?.Text().Should().Contain(
"Original message was deleted or could not be loaded." "Original message was deleted or could not be loaded."
); );
} }
@ -62,6 +63,6 @@ public class HtmlReplySpecs : IClassFixture<ExportWrapperFixture>
// Assert // Assert
message.Text().Should().Contain("reply to attachment"); message.Text().Should().Contain("reply to attachment");
message.QuerySelector(".chatlog__reference-link")?.Text().Should().Contain("Click to see attachment"); message.QuerySelector(".chatlog__reply-link")?.Text().Should().Contain("Click to see attachment");
} }
} }

View file

@ -7,7 +7,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class HtmlStickerSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class HtmlStickerSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -8,7 +8,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class JsonAttachmentSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class JsonAttachmentSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -7,7 +7,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class JsonContentSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class JsonContentSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -8,7 +8,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class JsonEmbedSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class JsonEmbedSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -8,7 +8,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class JsonMentionSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class JsonMentionSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -8,7 +8,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class JsonStickerSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class JsonStickerSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -12,6 +12,7 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
[Collection(nameof(ExportWrapperCollection))]
public class PartitioningSpecs : IClassFixture<TempOutputFixture> public class PartitioningSpecs : IClassFixture<TempOutputFixture>
{ {
private readonly TempOutputFixture _tempOutput; private readonly TempOutputFixture _tempOutput;

View file

@ -6,7 +6,8 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
public class PlainTextContentSpecs : IClassFixture<ExportWrapperFixture> [Collection(nameof(ExportWrapperCollection))]
public class PlainTextContentSpecs
{ {
private readonly ExportWrapperFixture _exportWrapper; private readonly ExportWrapperFixture _exportWrapper;

View file

@ -13,6 +13,7 @@ using Xunit;
namespace DiscordChatExporter.Cli.Tests.Specs; namespace DiscordChatExporter.Cli.Tests.Specs;
[Collection(nameof(ExportWrapperCollection))]
public class SelfContainedSpecs : IClassFixture<TempOutputFixture> public class SelfContainedSpecs : IClassFixture<TempOutputFixture>
{ {
private readonly TempOutputFixture _tempOutput; private readonly TempOutputFixture _tempOutput;

View file

@ -1,5 +1,6 @@
{ {
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"methodDisplayOptions": "all", "methodDisplayOptions": "all",
"methodDisplay": "method" "methodDisplay": "method",
"parallelizeTestCollections": true
} }

View file

@ -104,10 +104,10 @@
<div class="chatlog__message-aside"> <div class="chatlog__message-aside">
@if (isFirst) @if (isFirst)
{ {
// Reference symbol // Reply symbol
if (message.Reference is not null) if (message.Kind == MessageKind.Reply)
{ {
<div class="chatlog__reference-symbol"></div> <div class="chatlog__reply-symbol"></div>
} }
// Avatar // Avatar
@ -122,16 +122,16 @@
<div class="chatlog__message-primary"> <div class="chatlog__message-primary">
@if (isFirst) @if (isFirst)
{ {
// Reference // Reply
if (message.Reference is not null) if (message.Kind == MessageKind.Reply && message.Reference is not null)
{ {
<div class="chatlog__reference"> <div class="chatlog__reply">
@if (message.ReferencedMessage is not null) @if (message.ReferencedMessage is not null)
{ {
<img class="chatlog__reference-avatar" src="@await ResolveAssetUrlAsync(message.ReferencedMessage.Author.AvatarUrl)" alt="Avatar" loading="lazy"> <img class="chatlog__reply-avatar" src="@await ResolveAssetUrlAsync(message.ReferencedMessage.Author.AvatarUrl)" alt="Avatar" loading="lazy">
<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__reply-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"> <div class="chatlog__reply-content">
<span class="chatlog__reference-link" onclick="scrollToMessage(event, '@message.ReferencedMessage.Id')"> <span class="chatlog__reply-link" onclick="scrollToMessage(event, '@message.ReferencedMessage.Id')">
@if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !message.ReferencedMessage.IsContentHidden()) @if (!string.IsNullOrWhiteSpace(message.ReferencedMessage.Content) && !message.ReferencedMessage.IsContentHidden())
{ {
<!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(message.ReferencedMessage.Content))<!--/wmm:ignore--> <!--wmm:ignore-->@Html.Raw(await FormatEmbedMarkdownAsync(message.ReferencedMessage.Content))<!--/wmm:ignore-->
@ -149,13 +149,13 @@
@if (message.ReferencedMessage.EditedTimestamp is not null) @if (message.ReferencedMessage.EditedTimestamp is not null)
{ {
<span class="chatlog__reference-edited-timestamp" title="@FormatDate(message.ReferencedMessage.EditedTimestamp.Value)">(edited)</span> <span class="chatlog__reply-edited-timestamp" title="@FormatDate(message.ReferencedMessage.EditedTimestamp.Value)">(edited)</span>
} }
</div> </div>
} }
else else
{ {
<div class="chatlog__reference-unknown"> <div class="chatlog__reply-unknown">
Original message was deleted or could not be loaded. Original message was deleted or could not be loaded.
</div> </div>
} }
@ -170,7 +170,15 @@
@{/* Bot label */} @{/* Bot label */}
@if (message.Author.IsBot) @if (message.Author.IsBot)
{ {
<span class="chatlog__bot-label">BOT</span> // For cross-posts, the BOT tag is replaced with the SERVER tag
if (message.Kind != MessageKind.Reply && message.Reference is not null && message.Reference.GuildId != ExportContext.Request.Guild.Id)
{
<span class="chatlog__author-tag">SERVER</span>
}
else
{
<span class="chatlog__author-tag">BOT</span>
}
} }
@{/* Timestamp */} @{/* Timestamp */}

View file

@ -173,7 +173,7 @@
text-align: center; text-align: center;
} }
.chatlog__reference-symbol { .chatlog__reply-symbol {
height: 10px; height: 10px;
margin: 6px 4px 4px 36px; margin: 6px 4px 4px 36px;
border-left: 2px solid @Themed("#4f545c", "#c7ccd1"); border-left: 2px solid @Themed("#4f545c", "#c7ccd1");
@ -201,7 +201,7 @@
min-width: 0; min-width: 0;
} }
.chatlog__reference { .chatlog__reply {
display: flex; display: flex;
margin-bottom: 0.15rem; margin-bottom: 0.15rem;
align-items: center; align-items: center;
@ -212,49 +212,49 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.chatlog__reference-avatar { .chatlog__reply-avatar {
width: 16px; width: 16px;
height: 16px; height: 16px;
margin-right: 0.25rem; margin-right: 0.25rem;
border-radius: 50%; border-radius: 50%;
} }
.chatlog__reference-author { .chatlog__reply-author {
margin-right: 0.3rem; margin-right: 0.3rem;
font-weight: 600; font-weight: 600;
} }
.chatlog__reference-content { .chatlog__reply-content {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.chatlog__reference-link { .chatlog__reply-link {
cursor: pointer; cursor: pointer;
} }
.chatlog__reference-link * { .chatlog__reply-link * {
display: inline; display: inline;
pointer-events: none; pointer-events: none;
} }
.chatlog__reference-link .chatlog__markdown-quote { .chatlog__reply-link .chatlog__markdown-quote {
display: inline; display: inline;
} }
.chatlog__reference-link .chatlog__markdown-pre { .chatlog__reply-link .chatlog__markdown-pre {
display: inline; display: inline;
} }
.chatlog__reference-link:hover { .chatlog__reply-link:hover {
color: @Themed("#ffffff", "#2f3136"); color: @Themed("#ffffff", "#2f3136");
} }
.chatlog__reference-link:hover *:not(.chatlog__markdown-spoiler) { .chatlog__reply-link:hover *:not(.chatlog__markdown-spoiler) {
color: inherit; color: inherit;
} }
.chatlog__reference-edited-timestamp { .chatlog__reply-edited-timestamp {
margin-left: 0.25rem; margin-left: 0.25rem;
color: @Themed("#a3a6aa", "#5e6772"); color: @Themed("#a3a6aa", "#5e6772");
font-size: 0.75rem; font-size: 0.75rem;
@ -304,7 +304,7 @@
color: @Themed("#ffffff", "#2f3136"); color: @Themed("#ffffff", "#2f3136");
} }
.chatlog__bot-label { .chatlog__author-tag {
position: relative; position: relative;
top: -0.1rem; top: -0.1rem;
margin-left: 0.3rem; margin-left: 0.3rem;