// 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.Database.Models; using Dapper; using Remora.Discord.API; using Remora.Rest.Core; namespace Catalogger.Backend.Database.Repositories; public class GuildRepository(ILogger logger, DatabaseConnection conn) : IDisposable, IAsyncDisposable { private readonly ILogger _logger = logger.ForContext(); public async Task GetAsync(Optional id) => await GetAsync(id.Value.Value); public async Task GetAsync(Snowflake id) => await GetAsync(id.Value); public async Task GetAsync(ulong id) { _logger.Verbose("Getting guild config for {GuildId}", id); var guild = await conn.QueryFirstOrDefaultAsync( "select * from guilds where id = @Id", new { Id = id } ); if (guild == null) throw new CataloggerError("Guild not found, was not initialized during guild create"); return guild; } public async Task IsGuildKnown(ulong id) => await conn.ExecuteScalarAsync( "select exists(select id from guilds where id = @Id)", new { Id = id } ); public async Task AddGuildAsync(ulong id) => await conn.ExecuteAsync( """ insert into guilds (id, key_roles, banned_systems, channels) values (@Id, array[]::bigint[], array[]::text[], @Channels::jsonb) on conflict do nothing """, new { Id = id, Channels = new Guild.ChannelConfig() } ); public async Task BanSystemAsync(Snowflake guildId, Snowflake userId, string hid, Guid uuid) { await conn.ExecuteAsync( "update guilds set banned_systems = array_cat(banned_systems, @SystemIds) where id = @GuildId", new { GuildId = guildId.Value, SystemIds = (string[])[hid, uuid.ToString()] } ); await conn.ExecuteAsync( """ insert into pluralkit_systems (system_id, user_id, guild_id) values (@SystemId, @UserId, @GuildId) on conflict (system_id, user_id, guild_id) do nothing """, new { SystemId = uuid, UserId = userId.Value, GuildId = guildId.Value, } ); } public async Task UnbanSystemAsync(Snowflake guildId, Snowflake userId, string hid, Guid uuid) { await conn.ExecuteAsync( "update guilds set banned_systems = array_remove(array_remove(banned_systems, @Hid), @Uuid) where id = @Id", new { GuildId = guildId.Value, Hid = hid, Uuid = uuid.ToString(), } ); await conn.ExecuteAsync( """ delete from pluralkit_systems where system_id = @SystemId and user_id = @UserId and guild_id = @GuildId """, new { SystemId = uuid, UserId = userId.Value, GuildId = guildId.Value, } ); } public async Task GetSystemAccountsAsync(Snowflake guildId, Guid systemId) { var bannedAccounts = await conn.QueryAsync( "select * from pluralkit_systems where system_id = @SystemId and guild_id = @GuildId", new { SystemId = systemId, GuildId = guildId.Value } ); return bannedAccounts.Select(s => DiscordSnowflake.New(s.UserId)).ToArray(); } private record BannedSystem(Guid SystemId, ulong UserId, ulong GuildId); public async Task UpdateConfigAsync(Snowflake id, Guild config) => await conn.ExecuteAsync( """ update guilds set channels = @Channels::jsonb, messages = @Messages::jsonb, ignored_channels = @IgnoredChannels, ignored_roles = @IgnoredRoles, key_roles = @KeyRoles where id = @Id """, new { Id = id.Value, config.Channels, config.Messages, config.IgnoredChannels, config.IgnoredRoles, config.KeyRoles, } ); public async Task ImportConfigAsync( ulong id, Guild.ChannelConfig channels, Guild.MessageConfig messages, string[] bannedSystems, List keyRoles ) => await conn.ExecuteAsync( "update guilds set channels = @channels::jsonb, messages = @messages::jsonb, banned_systems = @bannedSystems, key_roles = @keyRoles where id = @id", new { id, channels, messages, bannedSystems, keyRoles, } ); public void Dispose() { conn.Dispose(); GC.SuppressFinalize(this); } public async ValueTask DisposeAsync() { await conn.DisposeAsync(); GC.SuppressFinalize(this); } }