// 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; using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Database; using Catalogger.Backend.Extensions; using Catalogger.Backend.Services; using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; using Remora.Results; using Guild = Catalogger.Backend.Database.Models.Guild; namespace Catalogger.Backend.Bot.Responders.Guilds; public class GuildCreateResponder( Config config, ILogger logger, DatabaseContext db, GuildCache guildCache, EmojiCache emojiCache, ChannelCache channelCache, RoleCache roleCache, IMemberCache memberCache, IInviteCache inviteCache, WebhookExecutorService webhookExecutor, GuildFetchService guildFetchService ) : IResponder, IResponder { private readonly ILogger _logger = logger.ForContext(); public async Task RespondAsync(IGuildCreate evt, CancellationToken ct = default) { ulong guildId; string? guildName = null; if (evt.Guild.TryPickT0(out var guild, out var unavailableGuild)) { _logger.Verbose( "Received guild create for available guild {GuildName} / {GuildId})", guild.Name, guild.ID ); guildId = guild.ID.ToUlong(); guildName = guild.Name; guildCache.Set(guild); emojiCache.Set(guild.ID, guild.Emojis); foreach (var c in guild.Channels) channelCache.Set(c, guild.ID); foreach (var r in guild.Roles) roleCache.Set(r, guild.ID); if (!await memberCache.IsGuildCachedAsync(guild.ID)) guildFetchService.EnqueueGuild(guild.ID); } else { _logger.Verbose( "Received guild create for unavailable guild {GuildId}", unavailableGuild.ID ); guildId = unavailableGuild.ID.ToUlong(); } var tx = await db.Database.BeginTransactionAsync(ct); if (await db.Guilds.FindAsync([guildId], ct) != null) return Result.Success; db.Add(new Guild { Id = guildId }); await db.SaveChangesAsync(ct); await tx.CommitAsync(ct); _logger.Information("Joined new guild {GuildName} / {GuildId}", guildName, guildId); if (config.Discord.GuildLogId != null && evt.Guild.IsT0) webhookExecutor.QueueLog( config.Discord.GuildLogId.Value, new EmbedBuilder() .WithTitle("Joined new guild") .WithDescription($"Joined new guild **{guild.Name}**") .WithFooter($"ID: {guild.ID}") .WithCurrentTimestamp() #pragma warning disable CS8604 // Possible null reference argument. .WithThumbnailUrl(guild.IconUrl()) #pragma warning restore CS8604 // Possible null reference argument. .Build() .GetOrThrow() ); return Result.Success; } public async Task RespondAsync(IGuildDelete evt, CancellationToken ct = default) { if (evt.IsUnavailable.OrDefault(false)) { _logger.Debug("Guild {GuildId} became unavailable", evt.ID); return Result.Success; } // Clear the cache for this guild guildCache.Remove(evt.ID, out _); emojiCache.Remove(evt.ID); channelCache.RemoveGuild(evt.ID); roleCache.RemoveGuild(evt.ID); await memberCache.RemoveAllMembersAsync(evt.ID); await inviteCache.RemoveAsync(evt.ID); if (!guildCache.TryGet(evt.ID, out var guild)) { _logger.Information("Left uncached guild {GuildId}", evt.ID); return Result.Success; } _logger.Information("Left guild {GuildName} / {GuildId}", guild.Name, guild.ID); if (config.Discord.GuildLogId != null) webhookExecutor.QueueLog( config.Discord.GuildLogId.Value, new EmbedBuilder() .WithTitle("Left guild") .WithDescription($"Left guild **{guild.Name}**") .WithFooter($"ID: {guild.ID}") .WithCurrentTimestamp() #pragma warning disable CS8604 // Possible null reference argument. .WithThumbnailUrl(guild.IconUrl()) #pragma warning restore CS8604 // Possible null reference argument. .Build() .GetOrThrow() ); return Result.Success; } }