Skip to content

Commit

Permalink
Add support for has:invite filter that matches messages with guild …
Browse files Browse the repository at this point in the history
…invites (#1188)
  • Loading branch information
Tyrrrz authored Jan 18, 2024
1 parent 4e69ff3 commit d8e43d8
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 15 deletions.
35 changes: 30 additions & 5 deletions DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public async Task I_can_filter_the_export_to_only_include_messages_that_contain_
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
.Should()
.ContainSingle("Some random text");
.AllBe("Some random text");
}

[Fact]
Expand Down Expand Up @@ -66,7 +66,7 @@ public async Task I_can_filter_the_export_to_only_include_messages_that_were_sen
}

[Fact]
public async Task I_can_filter_the_export_to_only_include_messages_that_contain_the_specified_content()
public async Task I_can_filter_the_export_to_only_include_messages_that_contain_images()
{
// Arrange
using var file = TempFile.Create();
Expand All @@ -87,7 +87,32 @@ public async Task I_can_filter_the_export_to_only_include_messages_that_contain_
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
.Should()
.ContainSingle("This has image");
.AllBe("This has image");
}

[Fact]
public async Task I_can_filter_the_export_to_only_include_messages_that_contain_guild_invites()
{
// Arrange
using var file = TempFile.Create();

Check failure on line 97 in DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs

View workflow job for this annotation

GitHub Actions / test

I can filter the export to only include messages that contain guild invites

Expected Json.Parse(File.ReadAllTextAsync(file.Path)).GetProperty("messages").EnumerateArray().Select(j => j.GetProperty("content").GetString())[0] to be "This has invite" with a length of 15, but "This has invite https://discord.gg/2SUWKFnHSm" has a length of 45, differs near " ht" (index 15). With configuration: - Use declared types and members - Compare enums by value - Compare tuples by their properties - Compare anonymous types by their properties - Compare records by their members - Include non-browsable members - Include all non-private properties - Include all non-private fields - Match member by name (or throw) - Be strict about the order of items in byte arrays - Be strict about the order of collections when IsNullOrEmpty(s.Path) - Without automatic conversion.

// Act
await new ExportChannelsCommand
{
Token = Secrets.DiscordToken,
ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json,
OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("has:invite")
}.ExecuteAsync(new FakeConsole());

// Assert
Json.Parse(await File.ReadAllTextAsync(file.Path))
.GetProperty("messages")
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
.Should()
.AllBe("This has invite");
}

[Fact]
Expand All @@ -112,7 +137,7 @@ public async Task I_can_filter_the_export_to_only_include_messages_that_have_bee
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
.Should()
.ContainSingle("This is pinned");
.AllBe("This is pinned");
}

[Fact]
Expand All @@ -137,6 +162,6 @@ public async Task I_can_filter_the_export_to_only_include_messages_that_contain_
.EnumerateArray()
.Select(j => j.GetProperty("content").GetString())
.Should()
.ContainSingle("This has mention");
.AllBe("This has mention");
}
}
11 changes: 8 additions & 3 deletions DiscordChatExporter.Core/Exporting/Filtering/HasMessageFilter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Core.Markdown.Parsing;

namespace DiscordChatExporter.Core.Exporting.Filtering;

Expand All @@ -10,14 +10,19 @@ internal class HasMessageFilter(MessageContentMatchKind kind) : MessageFilter
public override bool IsMatch(Message message) =>
kind switch
{
MessageContentMatchKind.Link
=> Regex.IsMatch(message.Content, "https?://\\S*[^\\.,:;\"\'\\s]"),
MessageContentMatchKind.Link => MarkdownParser.ExtractLinks(message.Content).Any(),
MessageContentMatchKind.Embed => message.Embeds.Any(),
MessageContentMatchKind.File => message.Attachments.Any(),
MessageContentMatchKind.Video => message.Attachments.Any(file => file.IsVideo),
MessageContentMatchKind.Image => message.Attachments.Any(file => file.IsImage),
MessageContentMatchKind.Sound => message.Attachments.Any(file => file.IsAudio),
MessageContentMatchKind.Pin => message.IsPinned,
MessageContentMatchKind.Invite
=> MarkdownParser
.ExtractLinks(message.Content)
.Select(l => l.Url)
.Select(Invite.TryGetCodeFromUrl)
.Any(c => !string.IsNullOrWhiteSpace(c)),
_
=> throw new InvalidOperationException(
$"Unknown message content match kind '{kind}'."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ internal enum MessageContentMatchKind
Video,
Image,
Sound,
Pin
Pin,
Invite
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,28 @@ from close in Character.EqualTo(open)
.IgnoreThen(
Parse.OneOf(
Span.EqualToIgnoreCase("link")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Link)),
.IgnoreThen(Parse.Return(MessageContentMatchKind.Link))
.Try(),
Span.EqualToIgnoreCase("embed")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Embed)),
.IgnoreThen(Parse.Return(MessageContentMatchKind.Embed))
.Try(),
Span.EqualToIgnoreCase("file")
.IgnoreThen(Parse.Return(MessageContentMatchKind.File)),
.IgnoreThen(Parse.Return(MessageContentMatchKind.File))
.Try(),
Span.EqualToIgnoreCase("video")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Video)),
.IgnoreThen(Parse.Return(MessageContentMatchKind.Video))
.Try(),
Span.EqualToIgnoreCase("image")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Image)),
.IgnoreThen(Parse.Return(MessageContentMatchKind.Image))
.Try(),
Span.EqualToIgnoreCase("sound")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Sound)),
Span.EqualToIgnoreCase("pin").IgnoreThen(Parse.Return(MessageContentMatchKind.Pin))
Span.EqualToIgnoreCase("pin")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Pin))
.Try(),
Span.EqualToIgnoreCase("invite")
.IgnoreThen(Parse.Return(MessageContentMatchKind.Invite))
.Try()
)
)
.Select(k => (MessageFilter)new HasMessageFilter(k))
Expand Down

0 comments on commit d8e43d8

Please sign in to comment.