2021-05-06 13:30:51 +00:00
|
|
|
import {Webhook, TextChannel, NewsChannel, Permissions, Collection} from "discord.js";
|
|
|
|
import {client} from "..";
|
|
|
|
import {Config} from "../structures";
|
|
|
|
|
|
|
|
export const webhookStorage = new Collection<string, Webhook>(); // Channel ID: Webhook
|
|
|
|
const WEBHOOK_PATTERN = /https:\/\/discord\.com\/api\/webhooks\/(\d{17,})\/(.+)/;
|
|
|
|
const ID_PATTERN = /(\d{17,})/;
|
|
|
|
|
|
|
|
// Resolve any available webhooks available for a selected channel.
|
|
|
|
export async function resolveWebhook(channel: TextChannel | NewsChannel): Promise<Webhook | null> {
|
2021-05-17 22:12:14 +00:00
|
|
|
if (channel.guild.me?.permissions.has(Permissions.FLAGS.MANAGE_WEBHOOKS)) {
|
2021-05-06 13:30:51 +00:00
|
|
|
const webhooksInChannel = await channel.fetchWebhooks();
|
|
|
|
|
|
|
|
if (webhooksInChannel.size > 0) return webhooksInChannel.first()!;
|
|
|
|
else return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const [channelID, webhook] of webhookStorage.entries()) if (channel.id === channelID) return webhook;
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function registerWebhook(url: string): boolean {
|
|
|
|
if (WEBHOOK_PATTERN.test(url)) {
|
|
|
|
const [_, id, token] = WEBHOOK_PATTERN.exec(url)!;
|
|
|
|
Config.webhooks[id] = token;
|
|
|
|
Config.save();
|
|
|
|
refreshWebhookCache();
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function deleteWebhook(urlOrID: string): boolean {
|
|
|
|
let id: string | null = null;
|
|
|
|
|
|
|
|
if (WEBHOOK_PATTERN.test(urlOrID)) id = WEBHOOK_PATTERN.exec(urlOrID)![1];
|
|
|
|
else if (ID_PATTERN.test(urlOrID)) id = ID_PATTERN.exec(urlOrID)![1];
|
|
|
|
|
|
|
|
if (id) {
|
|
|
|
delete Config.webhooks[id];
|
|
|
|
Config.save();
|
|
|
|
refreshWebhookCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
return !!id;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will return the target channel of a webhook create/edit/delete event.
|
|
|
|
// No permission is needed to receive this event, but since you only get the target channel, all stored webhooks must be fetched again.
|
|
|
|
// You can't rely on guilds giving the bot the manage webhooks permission.
|
|
|
|
client.on("webhookUpdate", refreshWebhookCache);
|
|
|
|
client.on("ready", refreshWebhookCache);
|
|
|
|
|
|
|
|
// Reload webhook objects from the storage.
|
|
|
|
export async function refreshWebhookCache(): Promise<void> {
|
|
|
|
webhookStorage.clear();
|
|
|
|
|
|
|
|
for (const [id, token] of Object.entries(Config.webhooks)) {
|
|
|
|
// If there are stored webhook IDs/tokens that don't work, delete those webhooks from storage.
|
|
|
|
try {
|
|
|
|
const webhook = await client.fetchWebhook(id, token);
|
2021-10-29 12:52:46 +00:00
|
|
|
webhookStorage.set(webhook.channelId, webhook);
|
2021-05-06 13:30:51 +00:00
|
|
|
} catch {
|
|
|
|
delete Config.webhooks[id];
|
|
|
|
Config.save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|