diff --git a/PluralKit.Bot/Commands/Admin.cs b/PluralKit.Bot/Commands/Admin.cs index e7ed749b..9e47feb6 100644 --- a/PluralKit.Bot/Commands/Admin.cs +++ b/PluralKit.Bot/Commands/Admin.cs @@ -1,8 +1,12 @@ using System.Text.RegularExpressions; +using Humanizer; using Dapper; using SqlKata; +using Myriad.Builders; +using Myriad.Extensions; +using Myriad.Cache; using Myriad.Rest; using Myriad.Types; @@ -14,11 +18,64 @@ public class Admin { private readonly BotConfig _botConfig; private readonly DiscordApiClient _rest; + private readonly IDiscordCache _cache; - public Admin(BotConfig botConfig, DiscordApiClient rest) + public Admin(BotConfig botConfig, DiscordApiClient rest, IDiscordCache cache) { _botConfig = botConfig; _rest = rest; + _cache = cache; + } + + public async Task CreateEmbed(Context ctx, PKSystem system) + { + string UntilLimit(int count, int limit) + { + var brackets = new List { 10, 25, 50, 100 }; + if (count == limit) + return "(at limit)"; + + foreach (var x in brackets) + { + if (limit - x <= count) + return $"(approx. {x} to limit)"; + } + + return ""; + } + + Task<(ulong Id, User? User)[]> GetUsers(IEnumerable ids) + { + async Task<(ulong Id, User? User)> Inner(ulong id) + { + var user = await _cache.GetOrFetchUser(_rest, id); + return (id, user); + } + + return Task.WhenAll(ids.Select(Inner)); + } + + var config = await ctx.Repository.GetSystemConfig(system.Id); + + // Fetch/render info for all accounts simultaneously + var accounts = await ctx.Repository.GetSystemAccounts(system.Id); + var users = (await GetUsers(accounts)).Select(x => x.User?.NameAndMention() ?? $"(deleted: `{x.Id}`)"); + + var eb = new EmbedBuilder() + .Title("System info") + .Color(DiscordUtils.Green) + .Field(new Embed.Field("System ID", $"`{system.Hid}`")) + .Field(new Embed.Field("Linked accounts", string.Join("\n", users).Truncate(1000))); + + var memberLimit = config.MemberLimitOverride ?? Limits.MaxMemberCount; + var memberCount = await ctx.Repository.GetSystemMemberCount(system.Id); + eb.Field(new Embed.Field("Member limit", $"{memberLimit} {UntilLimit(memberCount, memberLimit)}", true)); + + var groupLimit = config.GroupLimitOverride ?? Limits.MaxGroupCount; + var groupCount = await ctx.Repository.GetSystemGroupCount(system.Id); + eb.Field(new Embed.Field("Group limit", $"{groupLimit} {UntilLimit(groupCount, groupLimit)}", true)); + + return eb.Build(); } public async Task UpdateSystemId(Context ctx) @@ -37,6 +94,8 @@ public class Admin if (existingSystem != null) throw new PKError($"Another system already exists with ID `{newHid}`."); + await ctx.Reply(null, await CreateEmbed(ctx, target)); + if (!await ctx.PromptYesNo($"Change system ID of `{target.Hid}` to `{newHid}`?", "Change")) throw new PKError("ID change cancelled."); @@ -60,6 +119,9 @@ public class Admin if (existingMember != null) throw new PKError($"Another member already exists with ID `{newHid}`."); + var system = await ctx.Repository.GetSystem(target.System); + await ctx.Reply(null, await CreateEmbed(ctx, system)); + if (!await ctx.PromptYesNo( $"Change member ID of **{target.NameFor(LookupContext.ByNonOwner)}** (`{target.Hid}`) to `{newHid}`?", "Change" @@ -86,6 +148,9 @@ public class Admin if (existingGroup != null) throw new PKError($"Another group already exists with ID `{newHid}`."); + var system = await ctx.Repository.GetSystem(target.System); + await ctx.Reply(null, await CreateEmbed(ctx, system)); + if (!await ctx.PromptYesNo($"Change group ID of **{target.Name}** (`{target.Hid}`) to `{newHid}`?", "Change" )) @@ -103,6 +168,8 @@ public class Admin if (target == null) throw new PKError("Unknown system."); + await ctx.Reply(null, await CreateEmbed(ctx, target)); + if (!await ctx.PromptYesNo($"Reroll system ID `{target.Hid}`?", "Reroll")) throw new PKError("ID change cancelled."); @@ -124,6 +191,9 @@ public class Admin if (target == null) throw new PKError("Unknown member."); + var system = await ctx.Repository.GetSystem(target.System); + await ctx.Reply(null, await CreateEmbed(ctx, system)); + if (!await ctx.PromptYesNo( $"Reroll member ID for **{target.NameFor(LookupContext.ByNonOwner)}** (`{target.Hid}`)?", "Reroll" @@ -148,6 +218,9 @@ public class Admin if (target == null) throw new PKError("Unknown group."); + var system = await ctx.Repository.GetSystem(target.System); + await ctx.Reply(null, await CreateEmbed(ctx, system)); + if (!await ctx.PromptYesNo($"Reroll group ID for **{target.Name}** (`{target.Hid}`)?", "Change" )) @@ -176,7 +249,7 @@ public class Admin var currentLimit = config.MemberLimitOverride ?? Limits.MaxMemberCount; if (!ctx.HasNext()) { - await ctx.Reply($"Current member limit is **{currentLimit}** members."); + await ctx.Reply(null, await CreateEmbed(ctx, target)); return; } @@ -184,6 +257,7 @@ public class Admin if (!int.TryParse(newLimitStr, out var newLimit)) throw new PKError($"Couldn't parse `{newLimitStr}` as number."); + await ctx.Reply(null, await CreateEmbed(ctx, target)); if (!await ctx.PromptYesNo($"Update member limit from **{currentLimit}** to **{newLimit}**?", "Update")) throw new PKError("Member limit change cancelled."); @@ -204,7 +278,7 @@ public class Admin var currentLimit = config.GroupLimitOverride ?? Limits.MaxGroupCount; if (!ctx.HasNext()) { - await ctx.Reply($"Current group limit is **{currentLimit}** groups."); + await ctx.Reply(null, await CreateEmbed(ctx, target)); return; } @@ -212,6 +286,7 @@ public class Admin if (!int.TryParse(newLimitStr, out var newLimit)) throw new PKError($"Couldn't parse `{newLimitStr}` as number."); + await ctx.Reply(null, await CreateEmbed(ctx, target)); if (!await ctx.PromptYesNo($"Update group limit from **{currentLimit}** to **{newLimit}**?", "Update")) throw new PKError("Group limit change cancelled."); @@ -243,6 +318,7 @@ public class Admin throw Errors.AccountInOtherSystem(existingAccount, ctx.Config); var system = await ctx.Repository.GetSystem(systemId.Value!); + await ctx.Reply(null, await CreateEmbed(ctx, system)); if (!await ctx.PromptYesNo($"Associate account {account.NameAndMention()} with system `{system.Hid}`?", "Recover account")) throw new PKError("System recovery cancelled.");