diff --git a/backend/src/data/Webhooks.ts b/backend/src/data/Webhooks.ts index d8632274..ce69b2c8 100644 --- a/backend/src/data/Webhooks.ts +++ b/backend/src/data/Webhooks.ts @@ -16,6 +16,16 @@ export class Webhooks extends BaseRepository { return entity; } + async find(id: string): Promise { + const result = await this.repository.findOne({ + where: { + id, + }, + }); + + return result ? this._processEntityFromDB(result) : null; + } + async findByChannelId(channelId: string): Promise { const result = await this.repository.findOne({ where: { diff --git a/backend/src/plugins/Cases/functions/postToCaseLogChannel.ts b/backend/src/plugins/Cases/functions/postToCaseLogChannel.ts index f48fdd0d..1d363d60 100644 --- a/backend/src/plugins/Cases/functions/postToCaseLogChannel.ts +++ b/backend/src/plugins/Cases/functions/postToCaseLogChannel.ts @@ -56,8 +56,12 @@ export async function postCaseToCaseLogChannel( const [channelId, messageId] = theCase.log_message_id.split("-"); try { + const poster = pluginData.getPlugin(InternalPosterPlugin); const channel = pluginData.guild.channels.resolve(channelId as Snowflake) as TextChannel; - await channel.messages.edit(messageId as Snowflake, caseEmbed); + const message = await channel.messages.fetch(messageId); + if (message) { + await poster.editMessage(message, caseEmbed); + } return; } catch {} // tslint:disable-line:no-empty } diff --git a/backend/src/plugins/InternalPoster/InternalPosterPlugin.ts b/backend/src/plugins/InternalPoster/InternalPosterPlugin.ts index 14f074d2..2f35c1bd 100644 --- a/backend/src/plugins/InternalPoster/InternalPosterPlugin.ts +++ b/backend/src/plugins/InternalPoster/InternalPosterPlugin.ts @@ -12,6 +12,7 @@ import { mapToPublicFn } from "../../pluginUtils"; import { Webhooks } from "../../data/Webhooks"; import { Queue } from "../../Queue"; import { sendMessage } from "./functions/sendMessage"; +import { editMessage } from "./functions/editMessage"; const defaultOptions: PluginOptions = { config: {}, @@ -28,6 +29,7 @@ export const InternalPosterPlugin = zeppelinGuildPlugin, + message: Message, + content: MessageOptions, +): Promise { + if (!(message.channel instanceof TextChannel || message.channel instanceof NewsChannel)) { + return; + } + + const channel = message.channel as TextChannel | NewsChannel; + + await pluginData.state.queue.add(async () => { + if (message.webhookId) { + const webhook = await pluginData.state.webhooks.find(message.webhookId); + if (!webhook) { + // Webhook message but we're missing the token -> can't edit + return; + } + + const webhookClient = new WebhookClient({ + id: webhook.id, + token: webhook.token, + }); + await webhookClient.editMessage(message.id, content).catch(async (err) => { + // Unknown Webhook, remove from DB + if (isDiscordAPIError(err) && err.code === 10015) { + await pluginData.state.webhooks.delete(webhookClient.id); + return; + } + + throw err; + }); + return; + } + + await message.edit(content).catch(noop); + }); +} diff --git a/backend/src/plugins/InternalPoster/functions/getOrCreateWebhookClientForChannel.ts b/backend/src/plugins/InternalPoster/functions/getOrCreateWebhookClientForChannel.ts new file mode 100644 index 00000000..cc582495 --- /dev/null +++ b/backend/src/plugins/InternalPoster/functions/getOrCreateWebhookClientForChannel.ts @@ -0,0 +1,24 @@ +import { GuildPluginData } from "knub"; +import { InternalPosterPluginType } from "../types"; +import { NewsChannel, TextChannel, WebhookClient } from "discord.js"; +import { getOrCreateWebhookForChannel } from "./getOrCreateWebhookForChannel"; + +export async function getOrCreateWebhookClientForChannel( + pluginData: GuildPluginData, + channel: TextChannel | NewsChannel, +): Promise { + if (!pluginData.state.webhookClientCache.has(channel.id)) { + const webhookInfo = await getOrCreateWebhookForChannel(pluginData, channel); + if (webhookInfo) { + const client = new WebhookClient({ + id: webhookInfo[0], + token: webhookInfo[1], + }); + pluginData.state.webhookClientCache.set(channel.id, client); + } else { + pluginData.state.webhookClientCache.set(channel.id, null); + } + } + + return pluginData.state.webhookClientCache.get(channel.id) ?? null; +} diff --git a/backend/src/plugins/InternalPoster/functions/sendMessage.ts b/backend/src/plugins/InternalPoster/functions/sendMessage.ts index aecd7735..bc52ac05 100644 --- a/backend/src/plugins/InternalPoster/functions/sendMessage.ts +++ b/backend/src/plugins/InternalPoster/functions/sendMessage.ts @@ -4,6 +4,7 @@ import { InternalPosterPluginType } from "../types"; import { getOrCreateWebhookForChannel } from "./getOrCreateWebhookForChannel"; import { APIMessage } from "discord-api-types"; import { isDiscordAPIError } from "../../../utils"; +import { getOrCreateWebhookClientForChannel } from "./getOrCreateWebhookClientForChannel"; export type InternalPosterMessageResult = { id: string; @@ -29,47 +30,34 @@ export async function sendMessage( content: MessageOptions, ): Promise { return pluginData.state.queue.add(async () => { - if (!pluginData.state.webhookClientCache.has(channel.id)) { - const webhookInfo = await getOrCreateWebhookForChannel(pluginData, channel); - if (webhookInfo) { - const client = new WebhookClient({ - id: webhookInfo[0], - token: webhookInfo[1], - }); - pluginData.state.webhookClientCache.set(channel.id, client); - } else { - pluginData.state.webhookClientCache.set(channel.id, null); - } + const webhookClient = await getOrCreateWebhookClientForChannel(pluginData, channel); + if (!webhookClient) { + return sendDirectly(channel, content); } - const webhookClient = pluginData.state.webhookClientCache.get(channel.id); - if (webhookClient) { - return webhookClient - .send({ - ...content, - ...(pluginData.client.user && { - username: pluginData.client.user.username, - avatarURL: pluginData.client.user.avatarURL() || pluginData.client.user.defaultAvatarURL, - }), - }) - .then((apiMessage) => ({ - id: apiMessage.id, - channelId: apiMessage.channel_id, - })) - .catch(async (err) => { - // Unknown Webhook - if (isDiscordAPIError(err) && err.code === 10015) { - await pluginData.state.webhooks.delete(webhookClient.id); - pluginData.state.webhookClientCache.delete(channel.id); + return webhookClient + .send({ + ...content, + ...(pluginData.client.user && { + username: pluginData.client.user.username, + avatarURL: pluginData.client.user.avatarURL() || pluginData.client.user.defaultAvatarURL, + }), + }) + .then((apiMessage) => ({ + id: apiMessage.id, + channelId: apiMessage.channel_id, + })) + .catch(async (err) => { + // Unknown Webhook + if (isDiscordAPIError(err) && err.code === 10015) { + await pluginData.state.webhooks.delete(webhookClient.id); + pluginData.state.webhookClientCache.delete(channel.id); - // Fallback to regular message for this log message - return sendDirectly(channel, content); - } + // Fallback to regular message for this log message + return sendDirectly(channel, content); + } - throw err; - }); - } - - return sendDirectly(channel, content); + throw err; + }); }); }