feat: codes command
vi v@vt3e.cat
Sun, 01 Mar 2026 00:45:15 +0000
4 files changed,
213 insertions(+),
5 deletions(-)
M
src/events/messageCreate.ts
→
src/events/messageCreate.ts
@@ -6,6 +6,7 @@ ButtonBuilder,
ButtonStyle, type Client, Events, + type GuildMember, type Message, } from "discord.js"; import { and, eq } from "drizzle-orm";@@ -13,14 +14,15 @@ import { nanoid } from "nanoid";
import config from "@/config"; import { loggers } from "@/utils/logging"; +import { hasManagerPermissions } from "@/utils/permissions"; const logger = loggers.events.child({ name: "messageCreate" }); type UploadStatus = "queued" | "uploading" | "done" | "failed"; export default { event: Events.MessageCreate, - async execute(_client: Client, message: Message) { - if (message.author.bot) return; + 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");@@ -40,12 +42,19 @@
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, + ); + const authorType = isSystem ? "system" : isModerator ? "staff" : "user"; + const savedMessage = db .insert(ticketMessages) .values({ ticketId: ticket.id, authorId: message.author.id, - authorType: "user", + authorType: authorType, content: message.content, createdAt: message.createdAt, })
A
src/interactions/commands/codes.ts
@@ -0,0 +1,73 @@
+import config from "@/config"; +import { text } from "@/utils/components"; +import { tsExact, tsRelative } from "@/utils/profile"; +import { + type ChatInputCommandInteraction, + type Client, + ContainerBuilder, + SlashCommandBuilder, +} from "discord.js"; + +const commandData = new SlashCommandBuilder() + .setName("codes") + .setDescription(`Get the codes for all ${config.terminology}s`) + .addUserOption((option) => + option + .setName("user") + .setDescription("Optional user to mention") + .setRequired(false), + ); + +async function execute( + _client: Client, + interaction: ChatInputCommandInteraction, +) { + const user = interaction.options.getUser("user"); + + const container = new ContainerBuilder(); + const containerTextArr = ["## Codes"]; + + for (const project of Object.values(config.projects)) { + containerTextArr.push(`### ${project.displayName}`); + if (!project.codes || project.codes.length === 0) { + containerTextArr.push("No codes available."); + continue; + } + for (const code of project.codes) { + const codeText = code.expired ? `~~${code.code}~~` : `**${code.code}**`; + const addedString = code.addedAt + ? `added ${tsRelative(code.addedAt)}` + : undefined; + const lineParts = [ + `- ${codeText}`, + addedString ? `(${addedString})` : undefined, + ].filter(Boolean); + + containerTextArr.push(lineParts.join(" ")); + } + } + + const containerText = text(containerTextArr.join("\n")); + const footerText = text( + [ + `\n-# Please tell <@${config.developerId}> if this is incorrect`, + user ? `<@${user.id}>` : undefined, + ] + .filter(Boolean) + .join(" • "), + ); + + container.addTextDisplayComponents(containerText, footerText); + await interaction.reply({ + components: [container], + flags: ["IsComponentsV2"], + ...(user + ? { allowedMentions: { users: [user?.id] } } + : { allowedMentions: { users: [] } }), + }); +} + +export default { + data: commandData, + execute, +};
M
src/utils/transcripts.ts
→
src/utils/transcripts.ts
@@ -38,8 +38,9 @@ const lines = messages.map((msg) => {
const msgAttachments = attachmentMap.get(msg.id) ?? []; const time = new Date(msg.createdAt).toISOString(); - const author = - msg.authorType === "user" ? "reporter" : `<@${msg.authorId}>`; + let author = "reporter"; + if (msg.authorType === "system") author = "system"; + if (msg.authorType === "staff") author = `<@${msg.authorId}>`; let text = `[${time}] ${author}: ${msg.content}`;