Convert to Typescript
This commit is contained in:
224
src/commands/game.ts
Normal file
224
src/commands/game.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import {
|
||||
SlashCommandBuilder,
|
||||
EmbedBuilder,
|
||||
ChatInputCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import {
|
||||
listGameNames,
|
||||
getGame,
|
||||
setGame,
|
||||
deleteGame,
|
||||
deleteField,
|
||||
} from './utils/db/game';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('game')
|
||||
.setDescription('Perform ButlerBot game database operations.')
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand.setName('list').setDescription('List all games in the database.')
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('get')
|
||||
.setDescription('Get a game from the database.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('game')
|
||||
.setDescription('The name of the game to get.')
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('set')
|
||||
.setDescription('Set a key value pair on a game in the database.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('game')
|
||||
.setDescription('The name of the game to set the field in.')
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('key')
|
||||
.setDescription('The key or label to set.')
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('value')
|
||||
.setDescription('The value of the field to set.')
|
||||
.setRequired(true)
|
||||
.setMinLength(1)
|
||||
.setMaxLength(1024)
|
||||
)
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('delete')
|
||||
.setDescription('Delete a game, or a field from a game.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('game')
|
||||
.setDescription(
|
||||
'The name of the game to remove, or remove a field from.'
|
||||
)
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('key')
|
||||
.setDescription('The key or label of the field to remove.')
|
||||
.setRequired(false)
|
||||
)
|
||||
);
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Handle the interaction for the game command.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.deferReply();
|
||||
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
|
||||
switch (subcommand) {
|
||||
case 'list': {
|
||||
const gameNames = await listGameNames();
|
||||
|
||||
if (gameNames.length === 0) {
|
||||
await interaction.editReply('No games found in the database.');
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('Game Database')
|
||||
.setColor(0xff0000)
|
||||
.setDescription('List of games in the database.');
|
||||
|
||||
embed.addFields({
|
||||
name: 'Games',
|
||||
value: gameNames.map((game) => game.game).join('\n'),
|
||||
});
|
||||
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
break;
|
||||
}
|
||||
|
||||
case 'get': {
|
||||
const gameName = interaction.options.getString('game', true);
|
||||
|
||||
const game = await getGame(gameName);
|
||||
|
||||
if (!game) {
|
||||
await interaction.editReply(
|
||||
`Game ${gameName} not found in the database.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const embed = createEmbedFromGame(game);
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
} catch (error) {
|
||||
await interaction.editReply(
|
||||
'Embed too large to send. Game has not been retrieved.'
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'set': {
|
||||
const gameName = interaction.options.getString('game', true);
|
||||
const key = interaction.options.getString('key', true);
|
||||
const value = interaction.options.getString('value', true);
|
||||
|
||||
const oldGame = await getGame(gameName);
|
||||
await setGame(gameName, key, value);
|
||||
const updatedGame = await getGame(gameName);
|
||||
|
||||
try {
|
||||
const embed = createEmbedFromGame(updatedGame);
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
} catch (error) {
|
||||
// Revert game back to original state if the embed is too large.
|
||||
if (oldGame) {
|
||||
// If key already existed, revert to old value, else delete the key.
|
||||
if (oldGame[key]) {
|
||||
await setGame(gameName, key, oldGame[key]);
|
||||
} else {
|
||||
await deleteField(gameName, key);
|
||||
}
|
||||
}
|
||||
await interaction.editReply(
|
||||
'Embed too large to send. Game has not been updated.'
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
const gameName = interaction.options.getString('game', true);
|
||||
const key = interaction.options.getString('key');
|
||||
|
||||
if (key) {
|
||||
await deleteField(gameName, key);
|
||||
const updatedGame = await getGame(gameName);
|
||||
|
||||
if (!updatedGame) {
|
||||
await interaction.editReply(
|
||||
`Game ${gameName} deleted from the database.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const embed = createEmbedFromGame(updatedGame);
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
} catch (error) {
|
||||
await interaction.editReply(
|
||||
'Embed too large to send. Field deleted from game but game has not been retrieved.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await deleteGame(gameName);
|
||||
await interaction.editReply(
|
||||
`Game ${gameName} deleted from the database.`
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
await interaction.editReply('Unknown subcommand.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an embed from a game object.
|
||||
* @param game The game object containing key-value pairs.
|
||||
* @returns The embed object to be sent in the interaction.
|
||||
*/
|
||||
function createEmbedFromGame(game: any): EmbedBuilder {
|
||||
const embed = new EmbedBuilder().setTitle(game.game).setColor(0xff0000);
|
||||
|
||||
// Add fields for each key value pair - skip name, _id and guild.
|
||||
embed.addFields(
|
||||
Object.entries(game)
|
||||
.filter(([key]) => !['_id', 'game', 'guild'].includes(key))
|
||||
.map(([key, value]) => ({ name: key, value: String(value) }))
|
||||
);
|
||||
|
||||
if (embed.length > 6000) {
|
||||
throw new Error('Embed size exceeds maximum.');
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
Reference in New Issue
Block a user