finish ChannelUpdate responder

This commit is contained in:
sam 2024-08-20 18:18:17 +02:00
parent eb40872254
commit df8af75dd4
14 changed files with 155 additions and 63 deletions

View file

@ -1,4 +1,3 @@
using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Queries;
@ -16,6 +15,7 @@ public class ChannelCreateResponder(
DatabaseContext db,
RoleCache roleCache,
ChannelCache channelCache,
UserCache userCache,
WebhookExecutorService webhookExecutor) : IResponder<IChannelCreate>
{
public async Task<Result> RespondAsync(IChannelCreate ch, CancellationToken ct = default)
@ -57,13 +57,14 @@ public class ChannelCreateResponder(
}
else
{
var user = await userCache.GetUserAsync(overwrite.ID);
var embedFieldValue = "";
if (overwrite.Allow.GetPermissions().Count != 0)
embedFieldValue += $"\u2705 {overwrite.Allow.ToPrettyString()}";
if (overwrite.Deny.GetPermissions().Count != 0)
embedFieldValue += $"\n\n\u274c {overwrite.Deny.ToPrettyString()}";
builder.AddField($"Override for user {overwrite.ID}", embedFieldValue.Trim());
builder.AddField($"Override for {user?.Tag() ?? $"user {overwrite.ID}"}", embedFieldValue.Trim());
}
}

View file

@ -1,9 +1,9 @@
using System.Diagnostics;
using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services;
using Humanizer;
using Remora.Discord.API.Abstractions.Gateway.Events;
using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.Extensions.Embeds;
@ -39,18 +39,21 @@ public class ChannelUpdateResponder(
var builder = new EmbedBuilder()
.WithTitle(evt.Type switch
{
ChannelType.GuildVoice => "Voice channel created",
ChannelType.GuildCategory => "Category channel created",
ChannelType.GuildAnnouncement or ChannelType.GuildText => "Text channel created",
_ => "Channel created"
ChannelType.GuildVoice => "Voice channel edited",
ChannelType.GuildCategory => "Category channel edited",
ChannelType.GuildAnnouncement or ChannelType.GuildText => "Text channel edited",
_ => "Channel edited"
})
.WithColour(DiscordUtils.Blue)
.WithFooter($"ID: {evt.ID} | Name: {evt.Name}")
.WithCurrentTimestamp();
if (oldChannel.ParentID != evt.ParentID)
builder.AddField("Category",
CategoryUpdate(oldChannel.ParentID.OrDefault(), evt.ParentID.OrDefault()));
{
var categoryUpdate = CategoryUpdate(oldChannel.ParentID.OrDefault(), evt.ParentID.OrDefault());
if (!string.IsNullOrWhiteSpace(categoryUpdate))
builder.AddField("Category", categoryUpdate);
}
if (oldChannel.Name != evt.Name)
builder.AddField("Name", $"**Before:** {oldChannel.Name}\n**After:** {evt.Name}");
@ -69,12 +72,32 @@ public class ChannelUpdateResponder(
var oldOverrides = oldChannel.PermissionOverwrites.OrDefault() ?? [];
var newOverrides = evt.PermissionOverwrites.OrDefault() ?? [];
var addedOverrides = newOverrides.Where(o => oldOverrides.All(o2 => o.ID != o2.ID));
var addedOverrides = newOverrides.Where(o => oldOverrides.All(o2 => o.ID != o2.ID)).ToList();
var removedOverrides = oldOverrides.Where(o => newOverrides.All(o2 => o.ID != o2.ID)).ToList();
// Overrides filtered to ones that exist in both lists, but have different allow or deny values
var editedOverrides = newOverrides.Where(o => oldOverrides.Any(o2 =>
o.ID == o2.ID && (o.Allow.Value != o2.Allow.Value || o.Deny.Value != o2.Deny.Value)));
if (addedOverrides.Count != 0)
{
var addedOverrideNames = new List<string>();
foreach (var o in addedOverrides)
{
if (o.Type is PermissionOverwriteType.Member)
{
var user = await userCache.GetUserAsync(o.ID);
addedOverrideNames.Add(user != null ? $"<@{user.ID}>" : $"user {o.ID}");
}
else
{
addedOverrideNames.Add(roleCache.TryGet(o.ID, out var role) ? role.Name : $"role {o.ID}");
break;
}
builder.AddField("Added overrides", string.Join(", ", addedOverrideNames));
}
}
if (removedOverrides.Count != 0)
{
var removedOverrideNames = new List<string>();
@ -94,18 +117,40 @@ public class ChannelUpdateResponder(
builder.AddField("Removed overrides", string.Join(", ", removedOverrideNames));
}
foreach (var overwrite in editedOverrides)
{
var perms = string.Join("\n",
PermissionUpdate(oldOverrides.First(o => o.ID == overwrite.ID), overwrite));
if (string.IsNullOrWhiteSpace(perms)) continue;
builder.AddField(await OverwriteName(overwrite), perms.Trim());
}
foreach (var overwrite in addedOverrides)
{
var embedFieldValue = "";
if (overwrite.Allow.GetPermissions().Count != 0)
embedFieldValue += $"\u2705 {overwrite.Allow.ToPrettyString()}";
if (overwrite.Deny.GetPermissions().Count != 0)
embedFieldValue += $"\n\n\u274c {overwrite.Deny.ToPrettyString()}";
if (string.IsNullOrWhiteSpace(embedFieldValue)) continue;
builder.AddField(await OverwriteName(overwrite), embedFieldValue.Trim());
}
// Sometimes we get channel update events for channels that didn't actually have anything loggable change.
// If that happens, there will be no embed fields, so just check for that
if (builder.Fields.Count == 0) return Result.Success;
await webhookExecutor.QueueLogAsync(guildConfig, LogChannelType.ChannelUpdate,
builder.Build().GetOrThrow());
return Result.Success;
}
finally
{
channelCache.Set(evt);
}
throw new NotImplementedException();
}
private string CategoryUpdate(Snowflake? oldCategory, Snowflake? newCategory)
@ -117,4 +162,57 @@ public class ChannelUpdateResponder(
value += $"\n**After:** {newChannel.Name}";
return value.Trim();
}
private async Task<string> OverwriteName(IPermissionOverwrite overwrite)
{
switch (overwrite.Type)
{
case PermissionOverwriteType.Role:
return roleCache.TryGet(overwrite.ID, out var role)
? $"Override for {role.Name}"
: $"Override for role {overwrite.ID}";
case PermissionOverwriteType.Member:
var user = await userCache.GetUserAsync(overwrite.ID);
return user != null ? $"Override for {user.Tag()}" : $"Override for user {overwrite.ID}";
default:
throw new ArgumentOutOfRangeException(nameof(overwrite), overwrite.Type,
"Invalid PermissionOverwriteType");
}
}
private static IEnumerable<string> PermissionUpdate(IPermissionOverwrite oldOverwrite,
IPermissionOverwrite newOverwrite)
{
foreach (var perm in Enum.GetValues<DiscordPermission>())
{
if (newOverwrite.Allow.HasPermission(perm) && !oldOverwrite.Allow.HasPermission(perm) &&
!oldOverwrite.Deny.HasPermission(perm))
{
yield return $"\u2b1c \u279c \u2705 {perm.Humanize(LetterCasing.Title)}";
}
else if (newOverwrite.Deny.HasPermission(perm) && !oldOverwrite.Allow.HasPermission(perm) &&
!oldOverwrite.Deny.HasPermission(perm))
{
yield return $"\u2b1c \u279c \u274c {perm.Humanize(LetterCasing.Title)}";
}
else if (newOverwrite.Allow.HasPermission(perm) && oldOverwrite.Deny.HasPermission(perm))
{
yield return $"\u274c \u279c \u2705 {perm.Humanize(LetterCasing.Title)}";
}
else if (newOverwrite.Deny.HasPermission(perm) && oldOverwrite.Allow.HasPermission(perm))
{
yield return $"\u2705 \u279c \u274c {perm.Humanize(LetterCasing.Title)}";
}
else if (!newOverwrite.Allow.HasPermission(perm) && !newOverwrite.Deny.HasPermission(perm) &&
oldOverwrite.Allow.HasPermission(perm))
{
yield return $"\u2705 \u279c \u2b1c {perm.Humanize(LetterCasing.Title)}";
}
else if (!newOverwrite.Allow.HasPermission(perm) && !newOverwrite.Deny.HasPermission(perm) &&
oldOverwrite.Allow.HasPermission(perm))
{
yield return $"\u274c \u279c \u2b1c {perm.Humanize(LetterCasing.Title)}";
}
}
}
}

View file

@ -1,6 +1,5 @@
using System.Text.RegularExpressions;
using App.Metrics;
using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Models;

View file

@ -1,11 +1,9 @@
using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services;
using Humanizer;
using Microsoft.VisualBasic;
using NodaTime;
using Remora.Discord.API;
using Remora.Discord.API.Abstractions.Gateway.Events;

View file

@ -1,4 +1,3 @@
using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Queries;
@ -39,7 +38,6 @@ public class MessageUpdateResponder(
return Result.Success;
}
_logger.Debug("Guild is {GuildId}", msg.GuildID.Value);
var guildConfig = await db.GetGuildAsync(msg.GuildID.Value, ct);
if (await messageRepository.IsMessageIgnoredAsync(msg.ID.Value, ct))
@ -48,12 +46,12 @@ public class MessageUpdateResponder(
return Result.Success;
}
var logChannel = webhookExecutor.GetLogChannel(guildConfig, LogChannelType.MessageUpdate, msg.ChannelID,
msg.Author.ID.Value);
if (logChannel == null) return Result.Success;
try
{
var logChannel = webhookExecutor.GetLogChannel(guildConfig, LogChannelType.MessageUpdate, msg.ChannelID,
msg.Author.ID.Value);
if (logChannel == null) return Result.Success;
var oldMessage = await messageRepository.GetMessageAsync(msg.ID.Value, ct);
if (oldMessage == null)
{
@ -112,15 +110,26 @@ public class MessageUpdateResponder(
}
finally
{
if (!await messageRepository.UpdateMessageAsync(msg, ct) && msg.ApplicationID.Is(DiscordUtils.PkUserId))
// Messages should be *saved* if any of the message events are enabled for this channel, but should only
// be *logged* if the MessageUpdate event is enabled, so we check if we should save here.
// You also can't return early in `finally` blocks, so this has to be nested :(
if (webhookExecutor.GetLogChannel(guildConfig, LogChannelType.MessageUpdate, msg.ChannelID,
msg.Author.ID.Value) != null || webhookExecutor.GetLogChannel(guildConfig,
LogChannelType.MessageDelete, msg.ChannelID,
msg.Author.ID.Value) != null || webhookExecutor.GetLogChannel(guildConfig,
LogChannelType.MessageDeleteBulk, msg.ChannelID,
msg.Author.ID.Value) != null)
{
_logger.Debug(
"Message {MessageId} wasn't stored yet and was proxied by PluralKit, fetching proxy information from its API",
msg.ID);
var pkMsg = await pluralkitApi.GetPluralKitMessageAsync(msg.ID.Value, ct);
if (pkMsg != null)
await messageRepository.SetProxiedMessageDataAsync(msg.ID.Value, pkMsg.Original, pkMsg.Sender,
pkMsg.System?.Id, pkMsg.Member?.Id);
if (!await messageRepository.UpdateMessageAsync(msg, ct) && msg.ApplicationID.Is(DiscordUtils.PkUserId))
{
_logger.Debug(
"Message {MessageId} wasn't stored yet and was proxied by PluralKit, fetching proxy information from its API",
msg.ID);
var pkMsg = await pluralkitApi.GetPluralKitMessageAsync(msg.ID.Value, ct);
if (pkMsg != null)
await messageRepository.SetProxiedMessageDataAsync(msg.ID.Value, pkMsg.Original, pkMsg.Sender,
pkMsg.System?.Id, pkMsg.Member?.Id);
}
}
}
}