diff --git a/src/commands/github-mapping.ts b/src/commands/github-mapping.ts index aa30745..d7d59ce 100644 --- a/src/commands/github-mapping.ts +++ b/src/commands/github-mapping.ts @@ -1,6 +1,61 @@ import { ApplicationIntegrationType, ChatInputCommandInteraction, Client, InteractionContextType, MessageFlags, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js'; import { Database } from '../shared/Database'; -import { getIdFromInput } from '../utils'; +import { getIdFromInput, SetSeverity } from '../utils'; + +const userRegex = new RegExp(/^\d{16,20}$/); + +async function addUserMapping(interaction: ChatInputCommandInteraction) { + const githubUsername = interaction.options.getString('github-name', true); + const discordId = getIdFromInput(interaction.options.getString('discord-user', true)); + if (!userRegex.test(discordId)) throw new Error('The provided Discord user ID is invalid.'); + + const existingMappingId = await Database.getGithubFromDiscordId(discordId); + const existingMappingName = await Database.getDiscordIdFromGithub(githubUsername); + + if (existingMappingId) throw new Error(`<@${discordId}> (${discordId}) is already mapped to \`${existingMappingId}\``); + if (existingMappingName) throw new Error(`\`${githubUsername}\` is already mapped to <@${existingMappingName}> (${existingMappingName})`); + + await Database.putGithubUserMapping(discordId, githubUsername); + + await interaction.editReply({ + embeds: [{ + ...SetSeverity('success'), + + title: 'GitHub/Discord Mapping | Add', + description: `\`${githubUsername}\` has been linked to <@${discordId}>`, + }], + }); +} + +async function removeUserMapping(interaction: ChatInputCommandInteraction) { + const discordId = getIdFromInput(interaction.options.getString('discord-user', true)); + if (!userRegex.test(discordId)) throw new Error('The provided Discord user ID is invalid.'); + + if (!await Database.removeGithubUserMapping(discordId)) throw new Error('No existing GitHub mapping was found.'); + + await interaction.editReply({ + embeds: [{ + ...SetSeverity('success'), + + title: 'GitHub/Discord Mapping | Remove', + description: `<@${discordId}> is no longer linked.`, + }], + }); +} + +async function listUserMapping(interaction: ChatInputCommandInteraction) { + const allMappings = await Database.getAllGithubUserMappings(); + if (allMappings.length < 1) throw new Error('No GitHub mappings have been configured.'); + + await interaction.editReply({ + embeds: [{ + ...SetSeverity('success'), + + title: 'GitHub/Discord Mapping | List', + description: allMappings.map(m => `- <@${m.discord_id}> (${m.discord_id}) - ${m.github_username}`).join('\n'), + }] + }); +} export default { name: 'github-mapping', @@ -44,37 +99,17 @@ export default { .setDescription('List all github-discord mappings.') ), handler: async function (client: Client, interaction: ChatInputCommandInteraction) { - await interaction.deferReply({ flags: [MessageFlags.Ephemeral] }); + if (!interaction.inGuild()) return; + await interaction.deferReply({ flags: MessageFlags.Ephemeral }); - const subcommand = await interaction.options.getSubcommand(true); - - if (subcommand == 'add') { - const discordUserInput = interaction.options.getString('discord-user', true); - - const idToUse = getIdFromInput(discordUserInput); - - const githubName = interaction.options.getString('github-name', true); - - const existingMappingId = await Database.getGithubFromDiscordId(idToUse); - const existingMappingName = await Database.getDiscordIdFromGithub(githubName); - - if (existingMappingId) return interaction.editReply(`Discord user id is already mapped to ${existingMappingId}`); - if (existingMappingName) return interaction.editReply(`Github username is already mapped to <@${existingMappingName}> (${existingMappingName})`); - - Database.putGithubUserMapping(idToUse, githubName); - - return interaction.editReply('Mapping added.'); - } else if (subcommand == 'remove') { - const discordUserInput = interaction.options.getString('discord-user', true); - - const idToUse = getIdFromInput(discordUserInput); - - Database.removeGithubUserMapping(idToUse); - return interaction.editReply('Mapping removed.'); - } else if (subcommand == 'list') { - const allMappings = await Database.getAllGithubUserMappings(); - - return interaction.editReply(allMappings.map(m => `- <@${m.discord_id}> (${m.discord_id}) - ${m.github_username}`).join('\n')); + try { + switch (interaction.options.getSubcommand(true)) { + case 'add': return await addUserMapping(interaction); + case 'remove': return await removeUserMapping(interaction); + case 'list': return await listUserMapping(interaction); + } + } catch (error: Error | any) { + await interaction.editReply({ content: error.message }).catch(() => {}); } } -}; \ No newline at end of file +}; diff --git a/src/shared/Database.ts b/src/shared/Database.ts index df67766..d3a761e 100644 --- a/src/shared/Database.ts +++ b/src/shared/Database.ts @@ -364,8 +364,9 @@ export class Database { }); } - static async removeGithubUserMapping(discordId: string) { - await Database.db.run('DELETE from github_user_mapping WHERE discord_id_hash = ?', Encrypter.encrypt(discordId)); + static async removeGithubUserMapping(discordId: string): Promise { + const result = await Database.db.run('DELETE FROM github_user_mapping WHERE discord_id_hash = ?', Encrypter.hash(discordId)); + return (result.changes ?? 0) > 0; } //#endregion