apps/bot/src/feats/bugs/modals.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
import db, { eq, sql } from "@stealth-developers/db";
import { bugs } from "@stealth-developers/db/src/schemas/bugs";
import { AttachmentBuilder } from "discord.js";
import { errorMessage, getTextChannel } from "@/lib";
import { useGetData } from "@/middleware";
import { constructBugContainer } from "./shared";
export const bugModal = useGetData.modal("bug-report", {
run: async (interaction, _, { actor, guild }) => {
if (!actor || !guild)
return errorMessage(interaction, "You must be in a server to report a bug.");
const { fields: _fields } = interaction;
const fields = {
affected: _fields.getStringSelectValues("affected"),
title: _fields.getTextInputValue("title"),
description: _fields.getTextInputValue("description"),
media: _fields.getUploadedFiles("media", false),
};
await interaction.deferReply({ flags: ["Ephemeral"] });
const bugRes = await db.transaction(async (tx) => {
const [res] = await tx
.select({ count: sql<number>`COUNT(*)`.mapWith(Number) })
.from(bugs)
.where(eq(bugs.guildId, guild.id));
if (!res) return null;
const { count } = res;
const bugNumber = count + 1;
return await tx
.insert(bugs)
.values({
guildId: guild.id,
actorId: actor.id,
bugNumber: bugNumber,
status: "open",
title: fields.title,
description: fields.description,
affectedProjects: [...fields.affected],
sent: false,
messageId: null,
threadId: null,
createdAt: new Date(),
updatedAt: new Date(),
closedAt: null,
})
.returning();
});
if (!bugRes) return errorMessage(interaction, "Failed to create bug report.");
const bug = bugRes[0];
if (!bug) return errorMessage(interaction, "Failed to create bug report.");
let attachment: AttachmentBuilder | undefined;
if (fields.media && fields.media.size > 0) {
const [_, _attachment] = Array.from(fields.media)[0]!;
try {
const fileUrl = _attachment.url;
const fileName = _attachment.name;
if (fileUrl) {
const res = await fetch(fileUrl);
if (res.ok) {
const arrayBuffer = await res.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
attachment = new AttachmentBuilder(buffer, { name: fileName });
}
}
} catch (err) {
console.error("error processing uploaded file:", err);
}
}
const container = await constructBugContainer(bug, actor, attachment);
if (!container) return;
const channel = await getTextChannel("1512924775842840767");
if (!channel) return errorMessage(interaction, "Failed to send bug report.");
const message = await channel.send({
components: [container],
flags: ["IsComponentsV2"],
...(attachment ? { files: [attachment] } : {}),
});
function truncateTitle(title: string, maxLength: number): string {
return title.length > maxLength ? `${title.substring(0, maxLength)}...` : title;
}
const paddedNumber = bug.bugNumber.toString().padStart(4, "0");
const threadName = `#${paddedNumber} ${truncateTitle(fields.title, 150)}`;
const thread = await message.startThread({
name: threadName,
autoArchiveDuration: 1440,
});
await db
.update(bugs)
.set({ threadId: thread.id, messageId: message.id })
.where(eq(bugs.id, bug.id));
thread.send({
content: "Use this space to discuss the bug, provide additional details, or ask questions.",
});
interaction.editReply(
`Bug #${paddedNumber} created successfully! Find it here: ${message.url}`,
);
},
});
|