// 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 System.Net; using Catalogger.Backend.Api.Middleware; using Catalogger.Backend.Database.Models; using Microsoft.AspNetCore.Mvc; using NodaTime; using Remora.Discord.API; namespace Catalogger.Backend.Api; public partial class GuildsController { [Authorize] [HttpGet("config")] public async Task ExportConfigAsync(string id) { var (guildId, _) = await ParseGuildAsync(id); var guildConfig = await guildRepository.GetAsync(guildId); return Ok(await ToExport(guildConfig)); } [Authorize] [HttpPost("config")] public async Task ImportConfigAsync( string id, [FromBody] GuildConfigExport export ) { var (guildId, _) = await ParseGuildAsync(id); if (export.Id != guildId.Value) throw new ApiError( HttpStatusCode.BadRequest, ErrorCode.BadRequest, "This backup is not from this server." ); // Filter invites to *only* those that exist for this guild. // Blame past me for not making (code, guild_id) a unique index >:| var cachedInvites = (await inviteCache.TryGetAsync(guildId)).ToList(); var invites = export.Invites.Where(i => cachedInvites.Any(ci => i.Code == ci.Code)); await guildRepository.ImportConfigAsync( guildId.Value, export.Channels, export.BannedSystems, export.KeyRoles ); await inviteRepository.ImportInvitesAsync( guildId, invites.Select(i => new Invite { Code = i.Code, Name = i.Name, GuildId = guildId.Value, }) ); await watchlistRepository.ImportWatchlistAsync( guildId, export.Watchlist.Select(w => new Watchlist { GuildId = guildId.Value, UserId = w.UserId, ModeratorId = w.ModeratorId, AddedAt = w.AddedAt, Reason = w.Reason, }) ); return NoContent(); } private async Task ToExport(Database.Models.Guild config) { var id = DiscordSnowflake.New(config.Id); var invites = await inviteRepository.GetGuildInvitesAsync(id); var watchlist = await watchlistRepository.GetGuildWatchlistAsync(id); return new GuildConfigExport( config.Id, config.Channels, config.BannedSystems, config.KeyRoles, invites.Select(i => new InviteExport(i.Code, i.Name)), watchlist.Select(w => new WatchlistExport(w.UserId, w.AddedAt, w.ModeratorId, w.Reason)) ); } public record GuildConfigExport( ulong Id, Database.Models.Guild.ChannelConfig Channels, string[] BannedSystems, ulong[] KeyRoles, IEnumerable Invites, IEnumerable Watchlist ); public record InviteExport(string Code, string Name); public record WatchlistExport(ulong UserId, Instant AddedAt, ulong ModeratorId, string Reason); }