From 8e869571eb1cf1af296f4f05807d37da8a84586d Mon Sep 17 00:00:00 2001 From: FloatingMilkshake Date: Tue, 30 Jul 2024 23:02:04 -0400 Subject: [PATCH] Add !debug overrides add --- Commands/Debug.cs | 36 ++++++++++ Events/InteractionEvents.cs | 134 ++++++++++++++++++++++++++++++++++++ Structs.cs | 24 +++++++ 3 files changed, 194 insertions(+) diff --git a/Commands/Debug.cs b/Commands/Debug.cs index cc736d96..66d743bd 100644 --- a/Commands/Debug.cs +++ b/Commands/Debug.cs @@ -2,6 +2,8 @@ { internal class Debug : BaseCommandModule { + public static Dictionary OverridesPendingAddition = new(); + [Group("debug")] [Aliases("troubleshoot", "unbug", "bugn't", "helpsomethinghasgoneverywrong")] [Description("Commands and things for fixing the bot in the unlikely event that it breaks a bit.")] @@ -345,6 +347,40 @@ public async Task ImportAll(CommandContext ctx) await msg.ModifyAsync($"{Program.cfgjson.Emoji.Success} All overrides imported successfully!"); } + [Command("add")] + [Description("Insert an override into the db. Useful if you want to add an override for a user who has left.")] + [IsBotOwner] + public async Task Add(CommandContext ctx, + [Description("The user to add an override for.")] DiscordUser user, + [Description("The channel to add the override to.")] DiscordChannel channel, + [Description("Allowed permissions. Use a permission integer. See https://discordlookup.com/permissions-calculator.")] int allowedPermissions, + [Description("Denied permissions. Use a permission integer. See https://discordlookup.com/permissions-calculator.")] int deniedPermissions) + { + // Confirm permission overrides before we do anything. + var parsedAllowedPerms = (DiscordPermissions)allowedPermissions; + var parsedDeniedPerms = (DiscordPermissions)deniedPermissions; + + var confirmButton = new DiscordButtonComponent(DiscordButtonStyle.Success, "debug-overrides-add-confirm-callback", "Yes"); + var cancelButton = new DiscordButtonComponent(DiscordButtonStyle.Danger, "debug-overrides-add-cancel-callback", "No"); + + var confirmationMessage = await ctx.RespondAsync(new DiscordMessageBuilder().WithContent( + $"{Program.cfgjson.Emoji.ShieldHelp} Just to confirm, you want to add the following override for {user.Mention} to {channel.Mention}?\n" + + $"**Allowed:** {parsedAllowedPerms}\n" + + $"**Denied:** {parsedDeniedPerms}\n") + .AddComponents([confirmButton, cancelButton])); + + OverridesPendingAddition.Add(confirmationMessage.Id, new PendingUserOverride + { + ChannelId = channel.Id, + Overwrite = new MockUserOverwrite + { + Id = user.Id, + Allowed = parsedAllowedPerms, + Denied = parsedDeniedPerms + } + }); + } + [Command("remove")] [Description("Remove a user's overrides for a channel from the database.")] public async Task Remove(CommandContext ctx, diff --git a/Events/InteractionEvents.cs b/Events/InteractionEvents.cs index 81cb6178..760166a4 100644 --- a/Events/InteractionEvents.cs +++ b/Events/InteractionEvents.cs @@ -66,6 +66,140 @@ await LogChannelHelper.LogDeletedMessagesAsync( await e.Interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().WithContent($"{cfgjson.Emoji.Success} Done!").AsEphemeral(true)); } + else if (e.Id == "debug-overrides-add-confirm-callback") + { + await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate); + + var overridesPendingAddition = Commands.Debug.OverridesPendingAddition; + if (!overridesPendingAddition.ContainsKey(e.Message.Id)) + { + await e.Channel.SendMessageAsync(new DiscordMessageBuilder().WithContent($"{cfgjson.Emoji.Error} {e.User.Mention}, this action has already been completed!").WithReply(e.Message.Id)); + + // Remove buttons from original message so this doesn't happen again + var originalMsgWithoutButtons = new DiscordMessageBuilder(e.Message); + originalMsgWithoutButtons.ClearComponents(); + await e.Message.ModifyAsync(originalMsgWithoutButtons); + + return; + } + + // Get override data + var pendingOverride = overridesPendingAddition.GetValueOrDefault(e.Message.Id); + var mockOverwrite = pendingOverride.Overwrite; + var channelId = pendingOverride.ChannelId; + + // This is really cursed, but it effectively converts our mock DiscordOverwrite into an actual one so that it can be added to the current list of overwrites. + // Since the mock overwrite serializes into the same format as a DiscordOverwrite, we can serialize it and then deserialize it back to DiscordOverwrite to convert it. + var newOverwrite = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(mockOverwrite)); + + // Get current overrides for user in db + var userOverwrites = await db.HashGetAsync("overrides", mockOverwrite.Id); + if (userOverwrites.IsNullOrEmpty) + { + // No overwrites for this user yet, create a list and add to it + + var overwrites = new Dictionary { { channelId.ToString(), newOverwrite } }; + await db.HashSetAsync("overrides", mockOverwrite.Id, JsonConvert.SerializeObject(overwrites)); + } + else + { + // Overwrites for user exist, add to them + + var overwrites = JsonConvert.DeserializeObject>(userOverwrites); + if (overwrites.ContainsKey(channelId.ToString())) + { + // Require extra confirmation for merging permissions! + var mergeConfirmResponse = new DiscordMessageBuilder() + .WithContent($"{cfgjson.Emoji.Warning} **Caution:** This user already has an override for <#{channelId}>! Do you want to merge the permissions? Here are their **current** permissions:\n**Allowed:** {overwrites[channelId.ToString()].Allowed}\n**Denied:** {overwrites[channelId.ToString()].Denied}") + .AddComponents(new DiscordButtonComponent(DiscordButtonStyle.Danger, "debug-overrides-add-merge-confirm-callback", "Merge"), new DiscordButtonComponent(DiscordButtonStyle.Primary, "debug-overrides-add-cancel-callback", "Cancel")); + + await e.Message.ModifyAsync(mergeConfirmResponse); + return; + } + else + { + overwrites.Add(channelId.ToString(), newOverwrite); + } + // Update db + await db.HashSetAsync("overrides", mockOverwrite.Id, JsonConvert.SerializeObject(overwrites)); + } + + // Remove from db so the override is not added again + overridesPendingAddition.Remove(e.Message.Id); + + // Respond + await e.Message.ModifyAsync(new DiscordMessageBuilder().WithContent($"{cfgjson.Emoji.Success} Successfully added the following override for <@{newOverwrite.Id}> to <#{pendingOverride.ChannelId}>!\n**Allowed:** {newOverwrite.Allowed}\n**Denied:** {newOverwrite.Denied}")); + } + else if (e.Id == "debug-overrides-add-cancel-callback") + { + await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate); + + var overridesPendingAddition = Commands.Debug.OverridesPendingAddition; + if (!overridesPendingAddition.ContainsKey(e.Message.Id)) + { + await e.Channel.SendMessageAsync(new DiscordMessageBuilder().WithContent($"{cfgjson.Emoji.Error} {e.User.Mention}, this action has already been completed!").WithReply(e.Message.Id)); + + // Remove buttons from original message so this doesn't happen again + var originalMsgWithoutButtons = new DiscordMessageBuilder(e.Message); + originalMsgWithoutButtons.ClearComponents(); + await e.Message.ModifyAsync(originalMsgWithoutButtons); + + return; + } + + await e.Message.ModifyAsync(new DiscordMessageBuilder().WithContent($"{Program.cfgjson.Emoji.Error} Cancelled! Nothing was changed.")); + overridesPendingAddition.Remove(e.Message.Id); + } + else if (e.Id == "debug-overrides-add-merge-confirm-callback") + { + // User already has an overwrite for the requested channel! + // Merge the permissions of the current & new overrides. + + await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate); + + var overridesPendingAddition = Commands.Debug.OverridesPendingAddition; + if (!overridesPendingAddition.ContainsKey(e.Message.Id)) + { + await e.Channel.SendMessageAsync(new DiscordMessageBuilder().WithContent($"{cfgjson.Emoji.Error} {e.User.Mention}, this action has already been completed!").WithReply(e.Message.Id)); + + // Remove buttons from original message so this doesn't happen again + var originalMsgWithoutButtons = new DiscordMessageBuilder(e.Message); + originalMsgWithoutButtons.ClearComponents(); + await e.Message.ModifyAsync(originalMsgWithoutButtons); + + return; + } + + // Get new override data + var pendingOverride = overridesPendingAddition.GetValueOrDefault(e.Message.Id); + var mockOverwrite = pendingOverride.Overwrite; + var channelId = pendingOverride.ChannelId; + var newOverwrite = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(mockOverwrite)); + + // Existing override data + var userOverwrites = await db.HashGetAsync("overrides", mockOverwrite.Id); + var overwrites = JsonConvert.DeserializeObject>(userOverwrites); + + // Merge permissions + var existingOverwrite = overwrites[channelId.ToString()]; + var newMockOverwrite = new MockUserOverwrite + { + Id = mockOverwrite.Id, + Allowed = newOverwrite.Allowed | existingOverwrite.Allowed, + Denied = newOverwrite.Denied | existingOverwrite.Denied + }; + + // Cursed conversion again + newOverwrite = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(newMockOverwrite)); + + overwrites[channelId.ToString()] = newOverwrite; + + // Update db + await db.HashSetAsync("overrides", mockOverwrite.Id, JsonConvert.SerializeObject(overwrites)); + + // Respond + await e.Message.ModifyAsync(new DiscordMessageBuilder().WithContent($"{cfgjson.Emoji.Success} Override successfully added. <@{newOverwrite.Id}> already had an override in <#{pendingOverride.ChannelId}>, so here are their new permissions:\n**Allowed:** {newOverwrite.Allowed}\n**Denied:** {newOverwrite.Denied}")); + } else { await e.Interaction.CreateResponseAsync(DiscordInteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent("Unknown interaction. I don't know what you are asking me for.").AsEphemeral(true)); diff --git a/Structs.cs b/Structs.cs index 996ed021..8e5316af 100644 --- a/Structs.cs +++ b/Structs.cs @@ -611,4 +611,28 @@ public class UserNote public WarningType Type { get; set; } } + public class PendingUserOverride + { + [JsonProperty("channelId")] + public ulong ChannelId { get; set; } + + [JsonProperty("overwrite")] + public MockUserOverwrite Overwrite { get; set; } + } + + public class MockUserOverwrite + { + [JsonProperty("type")] + public int Type { get; } = 1; + + [JsonProperty("allow")] + public DiscordPermissions Allowed { get; set; } + + [JsonProperty("deny")] + public DiscordPermissions Denied { get; set; } + + [JsonProperty("id")] + public ulong Id { get; set; } + } + }