summary refs log tree commit diff
path: root/src/api/util/handlers/Message.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/util/handlers/Message.ts')
-rw-r--r--src/api/util/handlers/Message.ts141
1 files changed, 8 insertions, 133 deletions
diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts

index ed41341e..1fb9a080 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { EmbedHandlers, randomString } from "@spacebar/api"; +import { EmbedHandlers, randomString, fillMessageUrlEmbeds } from "@spacebar/api"; import { Application, Attachment, @@ -69,13 +69,12 @@ import { UnfurledMediaItem, BaseMessageComponents, v1CompTypes, - PartialUser + PartialUser, } from "@spacebar/schemas"; const allow_empty = false; // TODO: check webhook, application, system author, stickers // TODO: embed gifs/videos/images -const LINK_REGEX = /<?https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)>?/g; function checkActionRow(row: ActionRowComponent, knownComponentIds: string[], errors: Record<string, { code?: string; message: string }>, rowIndex: number) { if (!row.components) { return; @@ -774,139 +773,15 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { // TODO: cache link result in db export async function postHandleMessage(message: Message) { - const conf = Config.get(); - const content = message.content?.replace(/ *`[^)]*` */g, ""); // remove markdown - - const linkMatches = content?.match(LINK_REGEX) || []; message.clean_data(); - const data = { ...message.toJSON() }; - - const currentNormalizedUrls = new Set<string>(); - for (const link of linkMatches) { - // Don't process links in <> - if (link.startsWith("<") && link.endsWith(">")) { - continue; - } - try { - const normalized = normalizeUrl(link); - currentNormalizedUrls.add(normalized); - } catch (e) { - /* empty */ - } - } - if (data.embeds != undefined) { - data.embeds?.forEach((embed) => { - if (!embed.type) { - embed.type = EmbedType.rich; - } - }); - } - // Filter out embeds that could be links, start from scratch - if (data.embeds != undefined) { - data.embeds = data.embeds?.filter((embed) => embed.type === "rich"); - } - - const seenNormalizedUrls = new Set<string>(); - const uniqueLinks: string[] = []; - - for (const link of linkMatches.slice(0, 20)) { - // embed max 20 links - TODO: make this configurable with instance policies - // Don't embed links in <> - if (link.startsWith("<") && link.endsWith(">")) continue; - - try { - const normalized = normalizeUrl(link); - - if (!seenNormalizedUrls.has(normalized)) { - seenNormalizedUrls.add(normalized); - uniqueLinks.push(link); - } - } catch (e) { - // Invalid URL, skip - } - } - - if (uniqueLinks.length === 0) { - // No valid unique links found, update message to remove old embeds - if (data.embeds != undefined) { - data.embeds = data.embeds?.filter((embed) => embed.type === "rich"); - } - // author value is already included in message.toJSON() - const event = { - event: "MESSAGE_UPDATE", - channel_id: message.channel_id, - data: { - ...message.toJSON(), - embeds: data.embeds == undefined ? message.embeds || [] : data.embeds, - }, - } satisfies MessageUpdateEvent; - const embeds = data.embeds == undefined ? [] : data.embeds; - await Promise.all([emitEvent(event), Message.update({ id: message.id, channel_id: message.channel_id }, { embeds: embeds })]); - return; - } - - const cachePromises = []; - - for (const link of uniqueLinks) { - let url: URL; - try { - url = new URL(link); - } catch (e) { - // Skip invalid URLs - continue; - } - - const normalizedUrl = normalizeUrl(link); - - // Check cache using normalized URL - const cached = await EmbedCache.findOne({ - where: { url: normalizedUrl }, - }); - - if (cached) { - if (data.embeds == undefined) { - data.embeds = []; - } - data.embeds?.push(cached.embed); - continue; - } - - // bit gross, but whatever! - const endpointPublic = conf.cdn.endpointPublic; // lol - const handler = url.hostname === new URL(endpointPublic!).hostname ? EmbedHandlers["self"] : EmbedHandlers[url.hostname] || EmbedHandlers["default"]; - try { - let res = await handler(url); - if (!res) continue; - // tried to use shorthand but types didn't like me L - if (!Array.isArray(res)) res = [res]; + message.embeds ??= []; + message.embeds.forEach((embed) => { + // we need to handle false-y values (empty string) here, so cant use ??= + embed.type ||= EmbedType.rich; + }); - for (const embed of res) { - // Cache with normalized URL - const cache = EmbedCache.create({ - url: normalizedUrl, - embed: embed, - }); - cachePromises.push(cache.save()); - if (data.embeds == undefined) { - data.embeds = []; - } - data.embeds?.push(embed); - } - } catch (e) { - console.error(`[Embeds] Error while generating embed for ${link}`, e); - } - } - const embeds = data.embeds == undefined ? [] : data.embeds; - await Promise.all([ - emitEvent({ - event: "MESSAGE_UPDATE", - channel_id: message.channel_id, - data: message.toJSON(), - } satisfies MessageUpdateEvent), - Message.update({ id: message.id, channel_id: message.channel_id }, { embeds: embeds }), - ...cachePromises, - ]); + if ((await getPermission(message.author_id, message.channel.guild_id, message.channel_id)).has(Permissions.FLAGS.EMBED_LINKS)) await fillMessageUrlEmbeds(message); } export async function sendMessage(opts: MessageOptions) {