feat: member role and key role logging

This commit is contained in:
sam 2024-10-11 21:29:02 +02:00
parent d445b5ba44
commit a56cb87294
3 changed files with 140 additions and 6 deletions

View file

@ -28,6 +28,7 @@ public class AuditLogResponder(AuditLogCache auditLogCache, ILogger logger)
case AuditLogEvent.MemberBanRemove:
auditLogCache.SetUnban(evt.GuildID, evt.TargetID, evt.UserID.Value, evt.Reason);
break;
case AuditLogEvent.MemberRoleUpdate:
case AuditLogEvent.MemberUpdate:
auditLogCache.SetMemberUpdate(
evt.GuildID,
@ -38,8 +39,9 @@ public class AuditLogResponder(AuditLogCache auditLogCache, ILogger logger)
break;
default:
_logger.Debug(
"Received audit log event {Id} that we don't care about, ignoring",
evt.ID
"Received audit log event {Id} with type {Type} that we don't care about, ignoring",
evt.ID,
evt.ActionType
);
break;
}

View file

@ -8,6 +8,7 @@ using Remora.Discord.API.Abstractions.Gateway.Events;
using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.Extensions.Embeds;
using Remora.Discord.Gateway.Responders;
using Remora.Rest.Core;
using Remora.Results;
namespace Catalogger.Backend.Bot.Responders.MemberUpdate;
@ -16,6 +17,7 @@ public class GuildMemberUpdateResponder(
ILogger logger,
DatabaseContext db,
UserCache userCache,
RoleCache roleCache,
IMemberCache memberCache,
WebhookExecutorService webhookExecutor,
AuditLogCache auditLogCache
@ -67,6 +69,14 @@ public class GuildMemberUpdateResponder(
{
return await HandleTimeoutAsync(newMember, ct);
}
if (
newMember.Roles.Except(oldMember.Roles).Any()
|| oldMember.Roles.Except(newMember.Roles).Any()
)
{
return await HandleRoleUpdateAsync(newMember, oldMember.Roles, ct);
}
}
finally
{
@ -234,4 +244,120 @@ public class GuildMemberUpdateResponder(
);
return Result.Success;
}
private async Task<Result> HandleRoleUpdateAsync(
IGuildMemberUpdate member,
IReadOnlyList<Snowflake> oldRoles,
CancellationToken ct = default
)
{
var guildConfig = await db.GetGuildAsync(member.GuildID, ct);
var guildRoles = roleCache.GuildRoles(member.GuildID).ToList();
var keyRoleUpdate = new EmbedBuilder()
.WithAuthor(member.User.Tag(), null, member.User.AvatarUrl())
.WithTitle("Key roles added or removed")
.WithDescription($"<@{member.User.ID}>")
.WithColour(DiscordUtils.Purple)
.WithFooter($"User ID: {member.User.ID}")
.WithCurrentTimestamp();
var roleUpdate = new EmbedBuilder()
.WithAuthor(member.User.Tag(), null, member.User.AvatarUrl())
.WithTitle("Roles added or removed")
.WithDescription($"<@{member.User.ID}>")
.WithColour(DiscordUtils.Purple)
.WithFooter($"User ID: {member.User.ID}")
.WithCurrentTimestamp();
var addedRoles = member.Roles.Except(oldRoles).Select(s => s.Value).ToList();
var removedRoles = oldRoles.Except(member.Roles).Select(s => s.Value).ToList();
if (addedRoles.Count != 0)
{
roleUpdate.AddField("Added", string.Join(", ", addedRoles.Select(id => $"<@&{id}>")));
// Add all added key roles to the log
if (!addedRoles.Except(guildConfig.KeyRoles).Any())
{
var value = string.Join(
"\n",
addedRoles
.Where(guildConfig.KeyRoles.Contains)
.Select(id =>
{
var role = guildRoles.FirstOrDefault(r => r.ID.Value == id);
return role != null ? $"{role.Name} <@&{role.ID}>" : $"<@&{id}>";
})
);
keyRoleUpdate.AddField("Added", value);
}
}
if (removedRoles.Count != 0)
{
roleUpdate.AddField(
"Removed",
string.Join(", ", removedRoles.Select(id => $"<@&{id}>"))
);
// Add all removed key roles to the log
if (!removedRoles.Except(guildConfig.KeyRoles).Any())
{
var value = string.Join(
"\n",
removedRoles
.Where(guildConfig.KeyRoles.Contains)
.Select(id =>
{
var role = guildRoles.FirstOrDefault(r => r.ID.Value == id);
return role != null ? $"{role.Name} <@&{role.ID}>" : $"<@&{id}>";
})
);
keyRoleUpdate.AddField("Added", value);
}
}
// If there are any fields in the role update embed, we should send it
if (roleUpdate.Fields.Count != 0)
{
webhookExecutor.QueueLog(
guildConfig,
LogChannelType.GuildMemberUpdate,
roleUpdate.Build().GetOrThrow()
);
}
// Do the same for the key role update embed, but we also need to fetch the moderator that updated them
if (keyRoleUpdate.Fields.Count != 0)
{
if (
auditLogCache.TryGetMemberUpdate(member.GuildID, member.User.ID, out var actionData)
)
{
var moderator = await userCache.GetUserAsync(actionData.ModeratorId);
keyRoleUpdate.AddField(
"Responsible moderator",
moderator == null
? $"*(unknown user {actionData.ModeratorId}) <@{actionData.ModeratorId}>*"
: $"{moderator.Tag()} <@{moderator.ID}>"
);
}
else
{
keyRoleUpdate.AddField("Responsible moderator", "*(unknown)*");
}
// Finally, send the embed
webhookExecutor.QueueLog(
guildConfig,
LogChannelType.GuildKeyRoleUpdate,
keyRoleUpdate.Build().GetOrThrow()
);
}
return Result.Success;
}
}