diff --git a/PluralKit.Bot/Bot.cs b/PluralKit.Bot/Bot.cs index 2ce6232d..ec32a125 100644 --- a/PluralKit.Bot/Bot.cs +++ b/PluralKit.Bot/Bot.cs @@ -316,7 +316,15 @@ namespace PluralKit.Bot msg.Content.Substring(argPos).TrimStart().Length; argPos += trimStartLengthDiff; - await _tree.ExecuteCommand(new Context(_services, msg, argPos, cachedAccount?.System)); + try + { + await _tree.ExecuteCommand(new Context(_services, msg, argPos, cachedAccount?.System)); + } + catch (PKError) + { + // Only permission errors will ever bubble this far and be caught here instead of Context.Execute + // so we just catch and ignore these. TODO: this may need to change. + } } else if (cachedAccount != null) { @@ -329,7 +337,8 @@ namespace PluralKit.Bot } catch (PKError e) { - await arg.Channel.SendMessageAsync($"{Emojis.Error} {e.Message}"); + if (arg.Channel.HasPermission(ChannelPermission.SendMessages)) + await arg.Channel.SendMessageAsync($"{Emojis.Error} {e.Message}"); } } } @@ -343,7 +352,7 @@ namespace PluralKit.Bot // We'll fetch the event ID and send a user-facing error message. // ONLY IF this error's actually our problem. As for what defines an error as "our problem", // check the extension method :) - if (exc.IsOurProblem()) + if (exc.IsOurProblem() && _msg.Channel.HasPermission(ChannelPermission.SendMessages)) { var eid = evt.EventId; await _msg.Channel.SendMessageAsync( diff --git a/PluralKit.Bot/CommandSystem/Context.cs b/PluralKit.Bot/CommandSystem/Context.cs index cae120f6..77600daa 100644 --- a/PluralKit.Bot/CommandSystem/Context.cs +++ b/PluralKit.Bot/CommandSystem/Context.cs @@ -53,8 +53,17 @@ namespace PluralKit.Bot public bool HasNext(bool skipFlags = true) => RemainderOrNull(skipFlags) != null; public string FullCommand => _parameters.FullCommand; - public Task Reply(string text = null, Embed embed = null) => - Channel.SendMessageAsync(text, embed: embed); + public Task Reply(string text = null, Embed embed = null) + { + if (!this.BotHasPermission(ChannelPermission.SendMessages)) + // Will be "swallowed" during the error handler anyway, this message is never shown. + throw new PKError("PluralKit does not have permission to send messages in this channel."); + + if (embed != null && !this.BotHasPermission(ChannelPermission.EmbedLinks)) + throw new PKError("PluralKit does not have permission to send embeds in this channel. Please ensure I have the **Embed Links** permission enabled."); + + return Channel.SendMessageAsync(text, embed: embed); + } /// /// Checks if the next parameter is equal to one of the given keywords. Case-insensitive. diff --git a/PluralKit.Bot/Utils/ContextUtils.cs b/PluralKit.Bot/Utils/ContextUtils.cs index f104a645..ba411603 100644 --- a/PluralKit.Bot/Utils/ContextUtils.cs +++ b/PluralKit.Bot/Utils/ContextUtils.cs @@ -82,7 +82,7 @@ namespace PluralKit.Bot { try { - var msg = await ctx.Channel.SendMessageAsync(embed: await MakeEmbedForPage(0)); + var msg = await ctx.Reply(embed: await MakeEmbedForPage(0)); if (pageCount == 1) return; // If we only have one page, don't bother with the reaction/pagination logic, lol IEmote[] botEmojis = { new Emoji("\u23EA"), new Emoji("\u2B05"), new Emoji("\u27A1"), new Emoji("\u23E9"), new Emoji(Emojis.Error) }; await msg.AddReactionsAsync(botEmojis); @@ -147,7 +147,7 @@ namespace PluralKit.Bot { var pageCount = (items.Count-1) / pageSize + 1; // Send the original message - var msg = await ctx.Channel.SendMessageAsync($"**[Page {currPage + 1}/{pageCount}]**\n{description}\n{MakeOptionList(currPage)}"); + var msg = await ctx.Reply($"**[Page {currPage + 1}/{pageCount}]**\n{description}\n{MakeOptionList(currPage)}"); // Add back/forward reactions and the actual indicator emojis async Task AddEmojis() @@ -186,7 +186,7 @@ namespace PluralKit.Bot { } else { - var msg = await ctx.Channel.SendMessageAsync($"{description}\n{MakeOptionList(0)}"); + var msg = await ctx.Reply($"{description}\n{MakeOptionList(0)}"); // Add the relevant reactions (we don't care too much about awaiting) async Task AddEmojis()