// Copyright (C) 2021-present sam (starshines.gay) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Database; using Catalogger.Backend.Database.Queries; using Catalogger.Backend.Extensions; using Catalogger.Backend.Services; using Remora.Discord.API; 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.Results; namespace Catalogger.Backend.Bot.Responders.Guilds; public class GuildEmojisUpdateResponder( ILogger logger, DatabaseContext db, EmojiCache emojiCache, WebhookExecutorService webhookExecutor ) : IResponder { private readonly ILogger _logger = logger.ForContext(); public async Task RespondAsync(IGuildEmojisUpdate evt, CancellationToken ct = default) { try { if (!emojiCache.TryGet(evt.GuildID, out var oldEmoji)) { _logger.Information( "Previous emoji for {GuildId} were not in cache, ignoring event", evt.GuildID ); return Result.Success; } IEmbed embed; // As far as I know, only one emoji can be added or removed at once. var added = evt.Emojis.FirstOrDefault(e => oldEmoji.All(o => o.ID != e.ID)); var removed = oldEmoji.FirstOrDefault(o => evt.Emojis.All(e => o.ID != e.ID)); var updated = evt.Emojis.FirstOrDefault(e => oldEmoji.Any(o => o.ID == e.ID && o.Name != e.Name) ); if (added != null) { var url = CDN.GetEmojiUrl(added).GetOrThrow().ToString(); embed = new EmbedBuilder() .WithTitle("Emoji created") .WithDescription($"{FormatEmoji(added)} [{added.Name}]({url})") .WithThumbnailUrl(url) .WithFooter($"ID: {added.ID}") .WithColour(DiscordUtils.Green) .WithCurrentTimestamp() .Build() .GetOrThrow(); } else if (removed != null) { var url = CDN.GetEmojiUrl(removed).GetOrThrow().ToString(); embed = new EmbedBuilder() .WithTitle("Emoji removed") .WithDescription($"[{removed.Name}]({url})") .WithThumbnailUrl(url) .WithFooter($"ID: {removed.ID}") .WithColour(DiscordUtils.Red) .WithCurrentTimestamp() .Build() .GetOrThrow(); } else if (updated != null) { var url = CDN.GetEmojiUrl(updated).GetOrThrow().ToString(); var previous = oldEmoji.First(o => o.ID == updated.ID); embed = new EmbedBuilder() .WithTitle("Emoji renamed") .WithDescription( $""" {FormatEmoji(updated)} [{updated.Name}]({url}) {previous.Name} → {updated.Name} """ ) .WithThumbnailUrl(url) .WithFooter($"ID: {updated.ID}") .WithColour(DiscordUtils.Green) .WithCurrentTimestamp() .Build() .GetOrThrow(); } else { _logger.Warning( "Received emoji update event for {GuildId} but all emoji were identical, not logging", evt.GuildID ); return Result.Success; } var guildConfig = await db.GetGuildAsync(evt.GuildID, false, ct); webhookExecutor.QueueLog(guildConfig, LogChannelType.GuildEmojisUpdate, embed); return Result.Success; } finally { emojiCache.Set(evt.GuildID, evt.Emojis); } } private static string FormatEmoji(IEmoji emoji) => emoji.IsAnimated.OrDefault(false) ? $"" : $"<:{emoji.Name}:{emoji.ID}>"; }