feat: alter langauge to use 'project'
willow hai@wlo.moe
Tue, 27 May 2025 22:59:51 +0100
3 files changed,
58 insertions(+),
56 deletions(-)
M
src/config.ts
→
src/config.ts
@@ -13,9 +13,23 @@ database: z.string(),
collection: z.string(), }); +// record +// projects: { +// [gameInitials: string]: { name: string, displayName: string, iconURL: string }, +// [gameInitials: string]: { name: string, displayName: string, iconURL: string }, +// } +const projectSchema = z.record( + z.object({ + name: z.string(), + displayName: z.string(), + iconURL: z.string().optional(), + }), +); + const schema = z.object({ discord: discordSchema, mongodb: mongodbSchema, + projects: projectSchema, }); function validateConfig() {
M
src/database/schemas.ts
→
src/database/schemas.ts
@@ -1,6 +1,12 @@
import { type Document, Schema, model } from "mongoose"; import { z } from "zod"; +import config from "../config"; +const uniqueProjects = Object.keys(config.data.projects) as [ + string, + ...string[], +]; + // zod schemas for validation export const guildSchema = z.object({ guild_id: z.string(),@@ -25,7 +31,7 @@ export const bugSchema = z.object({
bug_id: z.number(), user_id: z.string(), status: z.enum(["open", "closed"]).default("open"), - game: z.enum(["wft", "gw", "ab"]), + project: z.enum(uniqueProjects), title: z.string(), description: z.string(), sent: z.boolean().default(false),@@ -73,7 +79,7 @@ bug_id: { type: Number, required: true, unique: true },
user_id: { type: String, required: true, ref: "User" }, status: { type: String, enum: ["open", "closed"], default: "open" }, title: { type: String, required: true }, - game: { type: String, enum: ["wft", "gw", "ab"], required: true }, + project: { type: String, enum: uniqueProjects, required: true }, description: { type: String, required: true }, sent: { type: Boolean, default: false }, message_id: String,
M
src/interactions/commands/bug.ts
→
src/interactions/commands/bug.ts
@@ -17,6 +17,7 @@ StringSelectMenuOptionBuilder,
TextInputBuilder, TextInputStyle, } from "discord.js"; +import config from "../../config.ts"; import { BugModel, type BugType,@@ -30,35 +31,13 @@
const logger = new Logger("bug-command"); // misc -const GAME_MAP = { - gw: { - name: "ground war", - iconURL: - "https://tr.rbxcdn.com/180DAY-7f58a11cdd59397e06d2b291326df71b/150/150/Image/Webp/noFilter", - }, - wft: { - name: "warfare tycoon", - iconURL: - "https://tr.rbxcdn.com/180DAY-ed309245ae50b509504c403a433ec0d2/150/150/Image/Webp/noFilter", - }, - ab: { - name: "airsoft battles", - iconURL: - "https://tr.rbxcdn.com/180DAY-43ff702ae43b081ec8db160d1a1d6636/150/150/Image/Webp/noFilter", - }, -}; +const PROJECT_MAP = config.data.projects; + +function getProjectName(value: string): string { + const project = PROJECT_MAP[value as keyof typeof PROJECT_MAP]; + if (!project) return "unknown project"; -function getGameName(value: string): string { - switch (value) { - case "wft": - return "warfare tycoon"; - case "gw": - return "ground war"; - case "ab": - return "airsoft battles"; - default: - return value; - } + return project.name; } async function updateBugEmbed(@@ -72,7 +51,7 @@ const channel = await client.channels.fetch(channelId);
if (!channel?.isTextBased() || !("messages" in channel)) return; const message = await channel.messages.fetch(messageId); - const gameInfo = GAME_MAP[bug.game as keyof typeof GAME_MAP]; + const projectInfo = PROJECT_MAP[bug.project as keyof typeof PROJECT_MAP]; const embed = new EmbedBuilder() .setAuthor({@@ -80,15 +59,16 @@ name: message.embeds[0].author?.name || "unknown user",
url: message.embeds[0].author?.url, iconURL: message.embeds[0].author?.iconURL, }) - .setThumbnail(gameInfo.iconURL) .setTitle(bug.title) .setColor(bug.status === "closed" ? 0x95a5a6 : 0xff6b6b) .setDescription(bug.description) .setFooter({ - text: `${gameInfo.name} • bug #${bug.bug_id} • ${bug.status}`, + text: `${projectInfo.name} • bug #${bug.bug_id} • ${bug.status}`, }) .setTimestamp(); + if (projectInfo.iconURL) embed.setThumbnail(projectInfo.iconURL); + // disable buttons if closed const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents( new ButtonBuilder()@@ -118,30 +98,31 @@ }
} // command stuff +const choices = Object.entries(PROJECT_MAP).map(([key, project]) => ({ + name: project.displayName, + value: key, +})); + const commandData = new SlashCommandBuilder() .setName("bug") .setDescription("report a bug") .addStringOption((option) => option - .setName("game") - .setDescription("which game this bug affects") + .setName("project") + .setDescription("which project this bug affects") .setRequired(true) - .addChoices( - { name: "warfare tycoon", value: "wft" }, - { name: "ground war", value: "gw" }, - { name: "airsoft battles", value: "ab" }, - ), + .addChoices(...choices), ); async function execute( _client: Client, interaction: ChatInputCommandInteraction, ) { - const game = interaction.options.getString("game", true); + const project = interaction.options.getString("project", true); const modal = new ModalBuilder() - .setCustomId(`bug:${game}`) - .setTitle(`report bug - ${getGameName(game)}`); + .setCustomId(`bug:${project}`) + .setTitle(`report bug - ${getProjectName(project)}`); const titleInput = new TextInputBuilder() .setCustomId("title")@@ -228,7 +209,7 @@ }
return; } - const game = customIdParts[1]; + const project = customIdParts[1]; try { await createUserIfNotExists(interaction.user.id, interaction.guild.id);@@ -238,7 +219,7 @@
const bug = new BugModel({ bug_id: bugId, user_id: interaction.user.id, - game, + project, title, description, status: "open",@@ -264,7 +245,7 @@ });
} if (channel?.isTextBased() && "send" in channel) { - const gameInfo = GAME_MAP[game as keyof typeof GAME_MAP]; + const projectInfo = PROJECT_MAP[project as keyof typeof PROJECT_MAP]; const embed = new EmbedBuilder() .setAuthor({@@ -272,12 +253,13 @@ name: interaction.user.displayName,
url: `https://discord.com/users/${interaction.user.id}`, iconURL: interaction.user?.avatarURL() || undefined, }) - .setThumbnail(gameInfo.iconURL) .setTitle(title) .setColor(0xff6b6b) .setDescription(description) - .setFooter({ text: `${gameInfo.name} • bug #${bugId}` }) + .setFooter({ text: `${projectInfo.name} • bug #${bugId}` }) .setTimestamp(); + + if (projectInfo.iconURL) embed.setThumbnail(projectInfo.iconURL); const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents( new ButtonBuilder()@@ -312,7 +294,7 @@ });
await thread.members.add(interaction.user.id); await thread.send({ - content: `thread created for bug #${bugId}. use this space to discuss the bug report, provide additional details, or ask questions.`, + content: `thread created for bug #${bugId} affecting ${projectInfo.displayName}. use this space to discuss the bug report, provide additional details, or ask questions.`, }); bug.thread_id = thread.id;@@ -352,8 +334,8 @@ const [, action, bugId] = interaction.customId.split(":");
if (action === "new") { const selectMenu = new StringSelectMenuBuilder() - .setCustomId("bug:game-select") - .setPlaceholder("select a game") + .setCustomId("bug:project-select") + .setPlaceholder("select a project") .addOptions( new StringSelectMenuOptionBuilder() .setLabel("warfare tycoon")@@ -371,7 +353,7 @@ selectMenu,
); return interaction.reply({ - content: "select a game to report a bug for:", + content: "select a project to report a bug for:", components: [row], flags: ["Ephemeral"], });@@ -498,12 +480,12 @@ async function selectMenuExecute(
_client: Client, interaction: StringSelectMenuInteraction, ) { - if (interaction.customId !== "bug:game-select") return; + if (interaction.customId !== "bug:project-select") return; - const game = interaction.values[0]; + const project = interaction.values[0]; const modal = new ModalBuilder() - .setCustomId(`bug:${game}`) - .setTitle(`report bug - ${getGameName(game)}`); + .setCustomId(`bug:${project}`) + .setTitle(`report bug - ${getProjectName(project)}`); const titleInput = new TextInputBuilder() .setCustomId("title")