feat: add editing support to InternalPoster

This commit is contained in:
Dragory 2021-11-02 23:10:37 +02:00
parent ecd9a5863c
commit 31f18ba27f
No known key found for this signature in database
GPG key ID: 5F387BA66DF8AAC1
6 changed files with 113 additions and 39 deletions

View file

@ -16,6 +16,16 @@ export class Webhooks extends BaseRepository {
return entity;
}
async find(id: string): Promise<Webhook | null> {
const result = await this.repository.findOne({
where: {
id,
},
});
return result ? this._processEntityFromDB(result) : null;
}
async findByChannelId(channelId: string): Promise<Webhook | null> {
const result = await this.repository.findOne({
where: {

View file

@ -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
}

View file

@ -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<InternalPosterPluginType> = {
config: {},
@ -28,6 +29,7 @@ export const InternalPosterPlugin = zeppelinGuildPlugin<InternalPosterPluginType
// prettier-ignore
public: {
sendMessage: mapToPublicFn(sendMessage),
editMessage: mapToPublicFn(editMessage),
},
async beforeLoad(pluginData) {

View file

@ -0,0 +1,46 @@
import { Message, MessageOptions, NewsChannel, TextChannel, WebhookClient } from "discord.js";
import { GuildPluginData } from "knub";
import { InternalPosterPluginType } from "../types";
import { isDiscordAPIError, noop } from "../../../utils";
/**
* Sends a message using a webhook or direct API requests, preferring webhooks when possible.
*/
export async function editMessage(
pluginData: GuildPluginData<InternalPosterPluginType>,
message: Message,
content: MessageOptions,
): Promise<void> {
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);
});
}

View file

@ -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<InternalPosterPluginType>,
channel: TextChannel | NewsChannel,
): Promise<WebhookClient | null> {
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;
}

View file

@ -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<InternalPosterMessageResult | null> {
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;
});
});
}