Fix various issues with proxying and webhook caching

This commit is contained in:
Ske
2019-07-10 23:16:17 +02:00
parent 8940226385
commit ca56fd419b
4 changed files with 61 additions and 7 deletions

View File

@@ -77,12 +77,19 @@ namespace PluralKit.Bot
}
public async Task HandleMessageAsync(IMessage message) {
var results = await _connection.QueryAsync<PKMember, PKSystem, ProxyDatabaseResult>("select members.*, systems.* from members, systems, accounts where members.system = systems.id and accounts.system = systems.id and accounts.uid = @Uid", (member, system) => new ProxyDatabaseResult { Member = member, System = system }, new { Uid = message.Author.Id });
var results = await _connection.QueryAsync<PKMember, PKSystem, ProxyDatabaseResult>(
"select members.*, systems.* from members, systems, accounts where members.system = systems.id and accounts.system = systems.id and accounts.uid = @Uid",
(member, system) =>
new ProxyDatabaseResult { Member = member, System = system }, new { Uid = message.Author.Id });
// Find a member with proxy tags matching the message
var match = GetProxyTagMatch(message.Content, results);
if (match == null) return;
// We know message.Channel can only be ITextChannel as PK doesn't work in DMs/groups
// Afterwards we ensure the bot has the right permissions, otherwise bail early
if (!await EnsureBotPermissions(message.Channel as ITextChannel)) return;
// Fetch a webhook for this channel, and send the proxied message
var webhook = await _webhookCache.GetWebhook(message.Channel as ITextChannel);
var hookMessage = await ExecuteWebhook(webhook, match.InnerText, match.ProxyName, match.Member.AvatarUrl, message.Attachments.FirstOrDefault());
@@ -96,8 +103,42 @@ namespace PluralKit.Bot
await message.DeleteAsync();
}
private async Task<bool> EnsureBotPermissions(ITextChannel channel)
{
var guildUser = await channel.Guild.GetCurrentUserAsync();
var permissions = guildUser.GetPermissions(channel);
if (!permissions.ManageWebhooks)
{
await channel.SendMessageAsync(
$"{Emojis.Error} PluralKit does not have the *Manage Webhooks* permission in this channel, and thus cannot proxy messages. Please contact a server administrator to remedy this.");
return false;
}
if (!permissions.ManageMessages)
{
await channel.SendMessageAsync(
$"{Emojis.Error} PluralKit does not have the *Manage Messages* permission in this channel, and thus cannot delete the original trigger message. Please contact a server administrator to remedy this.");
return false;
}
return true;
}
private async Task<IMessage> ExecuteWebhook(IWebhook webhook, string text, string username, string avatarUrl, IAttachment attachment) {
var client = new DiscordWebhookClient(webhook);
// TODO: DiscordWebhookClient's ctor does a call to GetWebhook that may be unnecessary, see if there's a way to do this The Hard Way :tm:
// TODO: this will probably crash if there are multiple consecutive failures, perhaps have a loop instead?
DiscordWebhookClient client;
try
{
client = new DiscordWebhookClient(webhook);
}
catch (InvalidOperationException)
{
// webhook was deleted or invalid
webhook = await _webhookCache.InvalidateAndRefreshWebhook(webhook);
client = new DiscordWebhookClient(webhook);
}
ulong messageId;
if (attachment != null) {
@@ -108,6 +149,8 @@ namespace PluralKit.Bot
} else {
messageId = await client.SendMessageAsync(text, username: username, avatarUrl: avatarUrl);
}
// TODO: SendMessageAsync should return a full object(??), see if there's a way to avoid the extra server call here
return await webhook.Channel.GetMessageAsync(messageId);
}