feat: handle media in bug reports
vi v@vt3e.cat
Sun, 01 Mar 2026 03:47:06 +0000
3 files changed,
74 insertions(+),
21 deletions(-)
M
src/events/messageCreate.ts
→
src/events/messageCreate.ts
@@ -24,8 +24,12 @@ event: Events.MessageCreate,
async execute(client: Client, message: Message) { if (!client.user) return; - if (message.content.includes("grok is this true")) { - if (message.channel.isSendable()) await message.channel.send("yeh"); + const triggers = ["grok is this true", "grok is this false "]; + if ( + message.channel.isSendable() && + message.content.includes("grok is this true") + ) { + message.channel.send("yeh"); } const ticket = db@@ -43,7 +47,6 @@ if (!ticket) return;
try { const isSystem = message.author.id === client.user.id; - const isReporter = message.author.id === ticket.authorId; const isModerator = await hasManagerPermissions( message?.member as GuildMember, );
M
src/interactions/commands/bug/modals.ts
→
src/interactions/commands/bug/modals.ts
@@ -1,5 +1,9 @@
+import { unlink, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; import { bugs, db } from "@/database"; import { getGuild } from "@/utils/queries"; +import { AttachmentBuilder } from "discord.js"; import type { Client, ModalSubmitInteraction } from "discord.js"; import { eq, sql } from "drizzle-orm"; import {@@ -55,8 +59,43 @@ closedAt: null,
}) .returning(); - // TODO)) media uploads to s3 - const container = await constructContainer(bug[0], interaction.user.id); + const tempFiles: string[] = []; + let attachment: AttachmentBuilder | undefined; + + if (media) { + for (const [_, _attachment] of media) { + try { + const fileUrl = _attachment.url; + const fileName = _attachment.name; + if (!fileUrl) continue; + + const res = await fetch(fileUrl); + if (!res.ok) continue; + + const arrayBuffer = await res.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + + const safeName = fileName.replace(/[^a-zA-Z0-9._-]/g, "_"); + const tmpPath = path.join( + os.tmpdir(), + `${Date.now()}-${Math.random().toString(36).slice(2)}-${safeName}`, + ); + + await writeFile(tmpPath, buffer); + tempFiles.push(tmpPath); + + attachment = new AttachmentBuilder(buffer, { name: fileName }); + } catch (err) { + console.error("error processing uploaded file:", err); + } + } + } + + const container = await constructContainer( + bug[0], + interaction.user.id, + attachment, + ); if (!container) return; const { data, exists } = await getGuild(interaction.guildId);@@ -68,11 +107,19 @@
const channel = await interaction.guild?.channels.fetch(channelId); if (!channel || !channel.isSendable()) return; - // send message const message = await channel.send({ components: [container], flags: ["IsComponentsV2"], + ...(attachment ? { files: [attachment] } : {}), }); + + for (const filePath of tempFiles) { + try { + await unlink(filePath); + } catch (err) { + console.error("error deleting temp file:", err); + } + } // thread function truncateTitle(title: string, maxLength: number): string {