all repos — stealth-developers @ 3730c396e5f98ab5f0415bcb62f978689a5ff938

bot(tickets): restore perf improvements
vi did:web:vt3e.cat
Fri, 03 Jul 2026 21:14:51 +0100
commit

3730c396e5f98ab5f0415bcb62f978689a5ff938

parent

09081644ff2bf482c3c68319af758a28e1626a15

M apps/bot/src/feats/guild-actor.tsapps/bot/src/feats/guild-actor.ts

@@ -33,7 +33,7 @@ avatar: member.user.avatarURL(),

}, }); - if (actor) GUILD_ACTORS.set(guild.id, actor); + if (actor) GUILD_ACTORS.set(guild.id, actor.actor); logger.info({ actor }, `upserted guild actor for ${guild.id} (${guild.name})`); return actor;
M apps/bot/src/feats/tickets/actions/comments.tsapps/bot/src/feats/tickets/actions/comments.ts

@@ -48,7 +48,6 @@ * @param reasons

* @param cleanup whether to delete the ticket channel immediately after closing * @returns */ - export async function addComment(ctx: TicketContext, comment: string) { const { actor, guild, ticket } = ctx;
M apps/bot/src/feats/tickets/actions/lifecycle.tsapps/bot/src/feats/tickets/actions/lifecycle.ts

@@ -18,7 +18,6 @@ ContainerBuilder,

type Guild, OverwriteType, PermissionFlagsBits, - TextChannel, TextDisplayBuilder, } from "discord.js"; import { upsertGuildActor } from "f/guild-actor";

@@ -27,7 +26,7 @@

import type { AnyUser } from "@/types"; import { client } from "@/client"; -import { PublicError, getCategory, logger, upsertUser } from "@/lib"; +import { PublicError, logger, upsertUser } from "@/lib"; import type { CreateTicketArgs, NewTicketContext, TicketContext } from "../types";

@@ -42,21 +41,16 @@

export async function createTicket( ctx: NewTicketContext, args?: CreateTicketArgs, -): Promise<{ channelId: string; publicId: string }> { +): Promise<{ channelId: string; publicId: string; setupPromise: Promise<void> }> { const isOnBehalf = !!args?.for; const publicId = randomUUID(); - const dbGuild = ctx.dbGuild; - if (!dbGuild) throw new PublicError("Failed to create ticket: Guild not found in database"); - - const moderators = await getModerators(dbGuild.id); - if (!moderators) throw new PublicError("Failed to create ticket: No moderators found"); + const { dbGuild, creatorActor: creator } = ctx; - const creator = ctx.creatorActor; - if (!creator) throw new PublicError("Failed to create ticket: Creator user not found"); + const subjectUser = isOnBehalf + ? (args?.dbFor ?? (args?.for ? await upsertUser(args.for, ctx.guild) : creator)) + : creator; - const subject = isOnBehalf ? args?.for : ctx.creatorUser; - const subjectUser = subject ? await upsertUser(subject, ctx.guild) : creator; if (!subjectUser) throw new PublicError("Failed to create ticket: Subject user not found"); if (isOnBehalf && !creator.moderator)

@@ -66,41 +60,38 @@ if (!dbGuild.ticketCategory)

throw new PublicError( "Ticket category is not set up in this guild. Please contact an administrator.", ); - const ticketCategory = await getCategory(dbGuild.ticketCategory); - let createdChannel: TextChannel | undefined = undefined; - const canDm = await canDmUser(subject); + const [txResult, canDm] = await Promise.all([ + Result.fromAsync(async () => { + return await db.transaction(async (tx) => { + const [maxTicket] = await tx + .select({ localId: tickets.localId }) + .from(tickets) + .where(eq(tickets.guildId, creator.guildId)) + .orderBy(desc(tickets.localId)) + .limit(1); - let ticketId: string | undefined = undefined; + const localId = (maxTicket?.localId ?? 0) + 1; - const txResult = await Result.fromAsync(async () => { - return await db.transaction(async (tx) => { - const [maxTicket] = await tx - .select({ localId: tickets.localId }) - .from(tickets) - .where(eq(tickets.guildId, creator.guildId)) - .orderBy(desc(tickets.localId)) - .limit(1); + const [ticket] = await tx + .insert(tickets) + .values({ + id: publicId, + guildId: creator.guildId, + localId: localId, + status: "provisioning", + openedAt: new Date(), + openedBy: creator.id, + subject: subjectUser.id, + }) + .returning(); - const localId = (maxTicket?.localId ?? 0) + 1; - - const [ticket] = await tx - .insert(tickets) - .values({ - id: publicId, - guildId: creator.guildId, - localId: localId, - status: "provisioning", - openedAt: new Date(), - openedBy: creator.id, - subject: subjectUser.id, - }) - .returning(); - - if (!ticket) throw new PublicError("Failed to add ticket to database, please try again."); - return { ticket, localId }; - }); - }); + if (!ticket) throw new PublicError("Failed to add ticket to database, please try again."); + return { ticket, localId }; + }); + }), + canDmUser(isOnBehalf ? args?.for : ctx.creatorUser), + ]); if (txResult.isErr()) { const error = txResult.unwrapErr();

@@ -114,174 +105,180 @@ throw new PublicError(message);

} const { ticket, localId } = txResult.unwrap(); - ticketId = ticket.id; - const setupResult = await Result.fromAsync(async () => { - const channel = await ctx.guild.channels.create({ - type: ChannelType.GuildText, - parent: ticketCategory, - name: `ticket-${String(localId).padStart(4, "0")}`, - permissionOverwrites: [ - { - id: ctx.guild.id, - type: OverwriteType.Role, - deny: [PermissionFlagsBits.ViewChannel], - }, - { - id: dbGuild.moderatorRole!, - type: OverwriteType.Role, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.ManageChannels, - PermissionFlagsBits.CreatePrivateThreads, - ], - }, - { - id: client.user!.id, - type: OverwriteType.Member, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.ManageChannels, - PermissionFlagsBits.CreatePrivateThreads, - ], - }, - { - id: subjectUser.discordId!, - type: OverwriteType.Member, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.AttachFiles, - ], - }, + const permissionOverwrites = [ + { + id: ctx.guild.id, + type: OverwriteType.Role, + deny: [PermissionFlagsBits.ViewChannel], + }, + { + id: client.user!.id, + type: OverwriteType.Member, + allow: [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.ManageChannels, + PermissionFlagsBits.CreatePrivateThreads, + ], + }, + { + id: subjectUser.discordId!, + type: OverwriteType.Member, + allow: [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.AttachFiles, + ], + }, + ]; + + if (dbGuild.moderatorRole) { + permissionOverwrites.push({ + id: dbGuild.moderatorRole, + type: OverwriteType.Role, + allow: [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.ManageChannels, + PermissionFlagsBits.CreatePrivateThreads, ], }); + } - if (!channel) throw new PublicError("Failed to create Discord channel."); - createdChannel = channel; + const channel = await ctx.guild.channels.create({ + type: ChannelType.GuildText, + parent: dbGuild.ticketCategory, + name: `ticket-${String(localId).padStart(4, "0")}`, + permissionOverwrites, + }); + + if (!channel) { + await Result.fromAsync(() => db.delete(tickets).where(eq(tickets.id, ticket.id))); + throw new PublicError("Failed to create Discord channel."); + } + + const setupPromise = (async () => { + try { + const greeting = dbGuild.ticketGreeting; + const components = []; + + if (greeting) { + components.push( + new ContainerBuilder() + .setAccentColor(0x3a9027) + .addTextDisplayComponents( + new TextDisplayBuilder({ + content: greeting.replaceAll("{user}", `<@${subjectUser.discordId}>`), + }), + ) + .addActionRowComponents( + new ActionRowBuilder<ButtonBuilder>().addComponents( + TicketButtonPresets.claimTicketButton(publicId), + TicketButtonPresets.closeTicketButton(publicId), + ), + ), + ); + } - const greeting = dbGuild.ticketGreeting; - const components = []; + if (!canDm) { + components.push( + new ContainerBuilder() + .setAccentColor(0xdf8e1d) + .addTextDisplayComponents( + new TextDisplayBuilder().setContent("## I can't DM you!"), + new TextDisplayBuilder().setContent( + [ + "You won't receive a notification once your ticket has been handled.", + `To check the outcome, you can use the \`/ticket view\` command with the ID \`${ticket.localId}\``, + "or, see all of your tickets with `/ticket manage list`.", + ].join(" "), + ), + ), + ); + } - if (greeting) { components.push( new ContainerBuilder() .setAccentColor(0x3a9027) .addTextDisplayComponents( new TextDisplayBuilder({ - content: greeting.replaceAll("{user}", `<@${subjectUser.discordId}>`), + content: [ + "# Uploading Videos\n", + "You can either upload your video directly to this channel, or", + "you can use the button below to upload it directly to us, which", + "allows you to upload videos up to 2GB in size.", + ].join(" "), }), ) .addActionRowComponents( new ActionRowBuilder<ButtonBuilder>().addComponents( - TicketButtonPresets.claimTicketButton(publicId), - TicketButtonPresets.closeTicketButton(publicId), + TicketButtonPresets.uploadLink(publicId), ), ), ); - } - if (!canDm) { - components.push( - new ContainerBuilder() - .setAccentColor(0xdf8e1d) - .addTextDisplayComponents( - new TextDisplayBuilder().setContent("## I can't DM you!"), - new TextDisplayBuilder().setContent( - [ - "You won't receive a notification once your ticket has been handled.", - `To check the outcome, you can use the \`/ticket view\` command with the ID \`${ticket.localId}\``, - "or, see all of your tickets with `/ticket manage list`.", - ].join(" "), - ), - ), - ); - } + const sendGreeting = channel.send({ + components, + flags: ["IsComponentsV2"], + }); - components.push( - new ContainerBuilder() - .setAccentColor(0x3a9027) - .addTextDisplayComponents( - new TextDisplayBuilder({ - content: [ - "# Uploading Videos\n", - "You can either upload your video directly to this channel, or", - "you can use the button below to upload it directly to us, which", - "allows you to upload videos up to 2GB in size.", - ].join(" "), - }), - ) - .addActionRowComponents( - new ActionRowBuilder<ButtonBuilder>().addComponents( - TicketButtonPresets.uploadLink(publicId), - ), - ), - ); + const createModeratorThread = async (): Promise<string | null> => { + try { + const modThread = await channel.threads.create({ + name: `Moderator Thread - #${String(ticket.localId).padStart(4, "0")}`, + type: ChannelType.PrivateThread, + autoArchiveDuration: 10080, + reason: "Private discussion thread for moderators", + }); - await channel.send({ - components, - flags: ["IsComponentsV2"], - }); + await Promise.all([ + modThread.send({ + content: `This thread is only visible to moderators, use it to discuss the ticket.`, + }), + channel.send({ + content: `Moderator thread created at ${modThread.url}`, + }), + ]); - await db - .update(tickets) - .set({ channelId: channel.id, status: "open" }) - .where(eq(tickets.id, ticket.id)); + return modThread.id; + } catch (threadError) { + logger.error( + threadError, + `Failed to create private moderator thread for ticket ${ticket.id}`, + ); + return null; + } + }; - try { - const modThread = await channel.threads.create({ - name: `Moderator Thread - #${String(ticket.localId).padStart(4, "0")}`, - type: ChannelType.PrivateThread, - autoArchiveDuration: 10080, - reason: "Private discussion thread for moderators", - }); + const [_, threadId] = await Promise.all([sendGreeting, createModeratorThread()]); - await modThread.send({ - content: `This thread is only visible to moderators, use it to discuss the ticket.`, - }); - - await channel.send({ - content: `Moderator thread created at ${modThread.url}`, + await editTicket(ticket.id, { + channelId: channel.id, + status: "open", + threadId: threadId, }); - await db.update(tickets).set({ threadId: modThread.id }).where(eq(tickets.id, ticket.id)); - } catch (threadError) { - logger.error( - threadError, - `Failed to create private moderator thread for ticket ${ticket.id}`, - ); - } - - return channel; - }); - - if (setupResult.isErr()) { - if (createdChannel) { - await Result.fromAsync(() => (createdChannel as TextChannel).delete()); + addParticipant( + ctx.guild.id, + { + actor: subjectUser, + ticketId: ticket.id, + role: "subject", + reason: "subject of ticket", + }, + true, + ) + .then() + .catch(); + } catch (error) { + await Result.fromAsync(() => channel.delete()); + await Result.fromAsync(() => db.delete(tickets).where(eq(tickets.id, ticket.id))); + logger.error(error, `failed background setup for ticket ${ticket.id}; deleted channel.`); + throw error; } - - await Result.fromAsync(() => db.delete(tickets).where(eq(tickets.id, ticketId!))); - - const error = setupResult.unwrapErr(); - const message = - error instanceof PublicError - ? `Failed to create ticket: ${error.message}` - : "There was an error creating the ticket."; - - if (error instanceof Error) logger.error(error.stack, error.message); - - throw new PublicError(message); - } - - await addParticipant(ctx.guild.id, { - actor: subjectUser, - ticketId: ticketId!, - role: "subject", - reason: "subject of ticket", - }); + })(); - const channel = setupResult.unwrap(); - return { channelId: channel.id, publicId }; + console.timeEnd("createTicketExec"); + return { channelId: channel.id, publicId, setupPromise }; } export async function triggerCloseTicket(user: AnyUser, guild: Guild, channelId: string) {

@@ -294,7 +291,7 @@

const ticket = await getTicketByChannelId(channelId); if (!ticket) throw new PublicError("Failed to close ticket: Ticket not found in database"); - return TicketModalPresets.close(ticket.id, Boolean(dbUser.moderator)); + return TicketModalPresets.close(ticket.id, Boolean(dbUser.actor.moderator)); } /**

@@ -392,7 +389,7 @@ );

if (messageRes.isErr()) { await addTicketComment({ - actorId: botActor.id, + actorId: botActor.actor.id, ticketId: result.id, content: `User has DMs closed, a notification was not sent.`, });

@@ -401,7 +398,7 @@

const logChannel = dbGuild.ticketLogChannel; if (!logChannel) { await addTicketComment({ - actorId: botActor.id, + actorId: botActor.actor.id, ticketId: result.id, content: `No log channel was found, a notification was not sent.`, });

@@ -419,7 +416,7 @@ );

if (message.isErr()) { await addTicketComment({ - actorId: botActor.id, + actorId: botActor.actor.id, ticketId: result.id, content: `Failed to send log message: ${message.unwrapErr()}`, });
M apps/bot/src/feats/tickets/buttons.tsapps/bot/src/feats/tickets/buttons.ts

@@ -18,8 +18,6 @@ import { TicketModalPresets } from "./modals";

export const newTicketButton = useGetTicketData.button("b-open-ticket", { async run(interaction, _, { actor, guild }) { - await interaction.deferReply({ flags: ["Ephemeral"] }); - if (!guild || !interaction.guild) { return errorMessage(interaction, "You must run this command in a guild"); } else if (!actor) {

@@ -36,19 +34,31 @@

const ticketResult = await Result.fromAsync(async () => func); if (ticketResult.isErr()) { const error = ticketResult.unwrapErr(); - - if (error instanceof PublicError) { - return errorMessage(interaction, error.message); - } else { - console.error(error); - return errorMessage(interaction, "An unexpected error occurred while creating the ticket."); - } + return errorMessage( + interaction, + error instanceof PublicError + ? error.message + : "An unexpected error occurred while creating the ticket.", + ); } - const { channelId } = ticketResult.unwrap(); - return interaction.editReply({ + const { channelId, setupPromise } = ticketResult.unwrap(); + + await interaction.reply({ content: `Opened ticket <#${channelId}>.`, + flags: ["Ephemeral"], }); + + try { + await setupPromise; + } catch { + await interaction + .editReply({ + content: + "An error occurred during ticket setup, and the ticket was closed. Please try again.", + }) + .catch(() => {}); + } }, });
M apps/bot/src/feats/tickets/commands.tsapps/bot/src/feats/tickets/commands.ts

@@ -16,7 +16,7 @@ } from "@stealth-developers/db";

import { ActionRowBuilder, ButtonBuilder, ContainerBuilder, TextDisplayBuilder } from "discord.js"; import { ChannelType } from "discord.js"; -import { PublicError, errorMessage, getTextChannel, handleError, logger, upsertUser } from "@/lib"; +import { PublicError, errorMessage, getTextChannel, handleError, upsertUser } from "@/lib"; import { useGetTicketData } from "@/middleware"; import { getGuildActor } from "../guild-actor";

@@ -33,7 +33,6 @@

ticketCommand.subcommand("new", { description: "Open a new ticket.", async run(interaction, _, { actor, guild }) { - await interaction.deferReply({ flags: ["Ephemeral"] }); if (!guild || !interaction.guild) { return errorMessage(interaction, "You must run this command in a guild"); } else if (!actor) {

@@ -50,19 +49,31 @@

const ticketResult = await Result.fromAsync(async () => func); if (ticketResult.isErr()) { const error = ticketResult.unwrapErr(); + return errorMessage( + interaction, + error instanceof PublicError + ? error.message + : "An unexpected error occurred while creating the ticket.", + ); + } - if (error instanceof PublicError) { - return errorMessage(interaction, error.message); - } else { - console.error(error); - return errorMessage(interaction, "An unexpected error occurred while creating the ticket."); - } - } + const { channelId, setupPromise } = ticketResult.unwrap(); - const { channelId } = ticketResult.unwrap(); - return interaction.editReply({ + await interaction.reply({ content: `Opened ticket <#${channelId}>.`, + flags: ["Ephemeral"], }); + + try { + await setupPromise; + } catch { + await interaction + .editReply({ + content: + "An error occurred during ticket setup, and the ticket was closed. Please try again.", + }) + .catch(() => {}); + } }, });

@@ -73,8 +84,6 @@ user: option.user("The user to open the ticket for", { required: true }),

reason: option.string("The reason for opening the ticket"), }, async run(interaction, args, { actor, guild }) { - await interaction.deferReply({ flags: ["Ephemeral"] }); - if (!guild || !interaction.guild) { return errorMessage(interaction, "You must run this command in a guild"); } else if (!actor) {

@@ -106,7 +115,7 @@ dbGuild: guild,

}, { for: args.user, - dbFor: forActor, + dbFor: forActor.actor, reason: args.reason, }, );

@@ -114,19 +123,31 @@

const ticketResult = await Result.fromAsync(async () => func); if (ticketResult.isErr()) { const error = ticketResult.unwrapErr(); + return errorMessage( + interaction, + error instanceof PublicError + ? error.message + : "An unexpected error occurred while creating the ticket.", + ); + } - if (error instanceof PublicError) { - return errorMessage(interaction, error.message); - } else { - logger.error(error); - return errorMessage(interaction, "An unexpected error occurred while creating the ticket."); - } - } + const { channelId, setupPromise } = ticketResult.unwrap(); - const { channelId } = ticketResult.unwrap(); - return interaction.editReply({ + await interaction.reply({ content: `Opened ticket <#${channelId}>.`, + flags: ["Ephemeral"], }); + + try { + await setupPromise; + } catch { + await interaction + .editReply({ + content: + "An error occurred during ticket setup, and the ticket was closed. Please try again.", + }) + .catch(() => {}); + } }, });

@@ -135,8 +156,12 @@ description: "View a ticket",

options: { ticket: option.number("The ticket's ID", { required: true }), }, - async run(interaction, args, { guild, actor, user }) { - if (guild && actor) { + async run(interaction, args, ctx) { + if (!ctx.user) return errorMessage(interaction, "Failed to fetch your profile"); + const activeUser = ctx.user as NonNullable<typeof ctx.user>; + + if (ctx.guild && ctx.actor) { + const { guild, actor } = ctx; const ticket = await getTicketByGuild(guild.id, args.ticket); if (!ticket) return errorMessage(interaction, `Ticket with ID ${args.ticket} not found.`);

@@ -145,19 +170,13 @@ return errorMessage(interaction, "You don't have permission to view this ticket.");

const container = actions.getTicketContainer(ticket, !actor.moderator); await interaction.reply({ components: [container], flags: ["Ephemeral", "IsComponentsV2"] }); - return; - } - - if (user) { - const ticket = await getTicketByUser(user.id, args.ticket); + } else if (activeUser) { + const ticket = await getTicketByUser(activeUser.id, args.ticket); if (!ticket) return errorMessage(interaction, `Ticket with ID ${args.ticket} not found.`); const container = actions.getTicketContainer(ticket, false); await interaction.reply({ components: [container], flags: ["Ephemeral", "IsComponentsV2"] }); - return; } - - await errorMessage(interaction, "We couldn't find a ticket with that ID."); }, });

@@ -389,7 +408,7 @@

await actions.addParticipant( interaction.guild.id, { - actor: participant, + actor: participant.actor, ticketId: ticket.id, role: "participant", reason: args.reason,

@@ -704,7 +723,7 @@

const dbActor = await upsertUser(user, interaction.guild); if (!dbActor) return errorMessage(interaction, "Failed to add moderator."); - await editActor(dbActor.id, { + await editActor(dbActor.actor.id, { moderator: true, });

@@ -730,7 +749,7 @@

const dbActor = await upsertUser(user, interaction.guild); if (!dbActor) return errorMessage(interaction, "Failed to remove moderator."); - await editActor(dbActor.id, { + await editActor(dbActor.actor.id, { moderator: false, });
M apps/bot/src/feats/tickets/listeners.tsapps/bot/src/feats/tickets/listeners.ts

@@ -80,9 +80,9 @@

const authorDb = await upsertUser(message.author, message.guild); if (!authorDb) return; - const isModerator = authorDb.moderator; + const isModerator = authorDb.actor.moderator; const isBot = message.author.bot; - const isSubject = authorDb?.discordId === ticket.subjectActor?.discordId; + const isSubject = authorDb?.actor.discordId === ticket.subjectActor?.discordId; const role = isModerator ? "moderator" : isBot ? "bot" : isSubject ? "subject" : "participant"; const subjectDiscordId = ticket.subjectActor?.discordId;

@@ -165,7 +165,7 @@ const messageResult = await Result.fromAsync(

await createTicketMessageWithAttachments({ id: messageId, ticketId: ticket.id, - actorId: authorDb.id, + actorId: authorDb.actor.id, messageId: message.id, content: anonymisedContent, actorRole: role,

@@ -182,11 +182,11 @@ })),

}), ); - if (authorDb.id === ticket?.claimedBy) { + if (authorDb.actor.id === ticket?.claimedBy) { await editTicket(ticket.id, { lastClaimantActivityAt: new Date(), }); - } else if (authorDb.id === ticket.subject) { + } else if (authorDb.actor.id === ticket.subject) { await editTicket(ticket.id, { lastSubjectActivityAt: new Date(), });
M apps/bot/src/lib/db.tsapps/bot/src/lib/db.ts

@@ -1,5 +1,5 @@

import { upsertActor } from "@stealth-developers/db"; -import { Guild, GuildMember, User } from "discord.js"; +import { Guild, GuildMember, PermissionsBitField, User } from "discord.js"; import type { AnyUser } from "@/types";

@@ -23,11 +23,10 @@ displayName = nick || globalName || user.username;

avatar = member.avatar || user.avatar; if (member instanceof GuildMember) { - isModerator = member.permissions.has("ModerateMembers"); + isModerator = member.permissions.has(PermissionsBitField.Flags.ModerateMembers); } else if (member.permissions) { - const { PermissionsBitField } = await import("discord.js"); const perms = new PermissionsBitField(BigInt(member.permissions)); - isModerator = perms.has("ModerateMembers"); + isModerator = perms.has(PermissionsBitField.Flags.ModerateMembers); } } else { const user = input;

@@ -36,10 +35,15 @@ username = user.username;

displayName = user.displayName; avatar = user.avatar; - try { - const member = await guild.members.fetch(user.id); - isModerator = member.permissions.has("ModerateMembers"); - } catch {} + const cachedMember = guild.members.cache.get(user.id); + if (cachedMember) { + isModerator = cachedMember.permissions.has(PermissionsBitField.Flags.ModerateMembers); + } else { + try { + const member = await guild.members.fetch(user.id); + isModerator = member.permissions.has(PermissionsBitField.Flags.ModerateMembers); + } catch {} + } } return upsertActor({
M apps/bot/src/middleware/index.tsapps/bot/src/middleware/index.ts

@@ -1,48 +1,26 @@

import { HaltExecution } from "@purrkit/router"; import { Result } from "@sapphire/framework"; -import { - getTicketByChannelId, - getTicketByGuild, - getTicketById, - upsertGuild, -} from "@stealth-developers/db"; +import { getTicketByChannelId, getTicketByGuild, getTicketById } from "@stealth-developers/db"; import { kitten } from "@/client"; import { getTextChannel, logger, upsertUser } from "@/lib"; const base = kitten.builder(); -export const useGetData = base - .use(async (interaction) => { - if (!interaction.guild) return {}; - - const user = await upsertUser(interaction.user, interaction.guild); - if (!user) throw new HaltExecution("Failed to add you to the database. Please try again."); - - return { user }; - }) - .use(async (interaction) => { - if (!interaction.guild) return {}; - - const actor = await upsertUser(interaction.user, interaction.guild); - if (!actor) throw new HaltExecution("Failed to add you to the database. Please try again."); - - return { actor }; - }) - .use(async (interaction) => { - if (!interaction.guild) return {}; +export const useGetData = base.use(async (interaction) => { + if (!interaction.guild) return {}; - const guild = await upsertGuild({ - discordId: interaction.guild.id, - icon: interaction.guild.iconURL(), - name: interaction.guild.name, - }); + const memberOrUser = interaction.member ?? interaction.user; + const result = await upsertUser(memberOrUser, interaction.guild); - if (!guild) - throw new HaltExecution("Failed to find your guild in the database. Please try again."); + if (!result) throw new HaltExecution("Failed to add you to the database. Please try again."); - return { guild }; - }); + return { + user: result.user, + actor: result.actor, + guild: result.guild, + }; +}); export const useGetTicketData = useGetData.use(async (interaction, { guild }) => { if (interaction.isChatInputCommand()) {

@@ -56,7 +34,7 @@ }

if (interaction.isButton()) { const customId = interaction.customId; - if (customId.includes("ticket:")) { + if (customId.includes("ticket")) { const ticketId = customId.split(":")[1]; if (ticketId) { const ticket = await getTicketById(ticketId);

@@ -74,6 +52,8 @@ }

return { ticket, ticketChannel: ticketChannelResult.unwrap() }; } + } else { + return {}; } }
M pkgs/db/src/utils/user.tspkgs/db/src/utils/user.ts

@@ -46,13 +46,15 @@ avatar: string | null;

}; moderator: boolean; }) { - const dbGuild = await upsertGuild(data.guild); - const dbUser = await upsertUser({ - id: data.user.discordId, - username: data.user.username, - displayName: data.user.displayName, - avatar: data.user.avatar, - }); + const [dbGuild, dbUser] = await Promise.all([ + upsertGuild(data.guild), + upsertUser({ + id: data.user.discordId, + username: data.user.username, + displayName: data.user.displayName, + avatar: data.user.avatar, + }), + ]); if (!dbGuild || !dbUser) { throw new Error("Failed to upsert guild or user");

@@ -83,7 +85,13 @@ },

}) .returning(); - return actor; + if (!actor) throw new Error("Failed to insert actor"); + + return { + actor: actor, + user: dbUser, + guild: dbGuild, + }; } export async function setActorPin(id: number, pin: string) {