From f1025ce1296f4fb29efd27bac4bd1b2964917e18 Mon Sep 17 00:00:00 2001 From: Ean Milligan Date: Tue, 22 Jul 2025 01:19:20 -0400 Subject: [PATCH] Implement slash commands for most things, some bugfixes and god knows what else --- deno.json | 3 +- .../managers/handler/workerComplete.ts | 8 +- .../managers/handler/workerTerminate.ts | 2 +- src/artigen/managers/manager.d.ts | 1 + src/artigen/utils/escape.ts | 3 + src/commands/_index.ts | 46 +++-- src/commands/aliasCmd.ts | 158 ++++++++++++--- src/commands/aliasCmd/aliasAddUpdate.ts | 190 ++++++++++-------- src/commands/aliasCmd/aliasDelete.ts | 175 ++++++++-------- src/commands/aliasCmd/clone.ts | 143 ++++++------- src/commands/aliasCmd/list.ts | 44 ++-- src/commands/aliasCmd/rename.ts | 148 +++++++------- src/commands/aliasCmd/reservedWords.ts | 1 + src/commands/aliasCmd/run.ts | 94 +++++---- src/commands/aliasCmd/view.ts | 86 ++++---- src/commands/heatmap.ts | 59 +++--- src/commands/help.ts | 13 +- src/commands/info.ts | 29 +-- src/commands/privacy.ts | 41 ++-- src/commands/report.ts | 61 +++--- src/commands/rip.ts | 31 +-- src/commands/roll.ts | 32 ++- src/commands/stats.ts | 17 +- src/commands/toggleInline.ts | 123 +++++++----- src/commands/version.ts | 33 +-- src/events/interactionCreate.ts | 142 +++++++++++-- src/events/messageCreate.ts | 15 +- src/events/ready.ts | 2 + src/mod.d.ts | 5 + src/utils/utils.ts | 33 ++- 30 files changed, 1076 insertions(+), 662 deletions(-) create mode 100644 src/mod.d.ts diff --git a/deno.json b/deno.json index 3ea71b2..adf9013 100644 --- a/deno.json +++ b/deno.json @@ -39,6 +39,7 @@ "events/": "./src/events/", "utils/": "./src/utils/", "src/api.ts": "./src/api.ts", - "src/events.ts": "./src/events.ts" + "src/events.ts": "./src/events.ts", + "src/mod.d.ts": "./src/mod.d.ts" } } diff --git a/src/artigen/managers/handler/workerComplete.ts b/src/artigen/managers/handler/workerComplete.ts index 61ba329..7ce8de5 100644 --- a/src/artigen/managers/handler/workerComplete.ts +++ b/src/artigen/managers/handler/workerComplete.ts @@ -28,7 +28,7 @@ import utils from 'utils/utils.ts'; const getUserIdForEmbed = (rollRequest: QueuedRoll): bigint => { if (rollRequest.apiRoll) return rollRequest.api.userId; - if (rollRequest.ddRoll) return rollRequest.dd.originalMessage.authorId; + if (rollRequest.ddRoll) return rollRequest.dd.authorId; return 0n; }; @@ -227,7 +227,7 @@ Please click on "<@${botId}> *Click to see attachment*" above this message to se file: pubAttachments, }) .then((attachmentMsg) => toggleWebView(attachmentMsg, getUserIdForEmbed(rollRequest).toString(), false)) - .catch((e) => console.log(e)); + .catch((e) => utils.commonLoggers.messageSendError('workerComplete.ts:230', newMsg as DiscordenoMessage, e)); } else { pubAttachments.forEach((file) => { newMsg && @@ -237,7 +237,7 @@ Please click on "<@${botId}> *Click to see attachment*" above this message to se file, }) .then((attachmentMsg) => toggleWebView(attachmentMsg, getUserIdForEmbed(rollRequest).toString(), false)) - .catch((e) => console.log(e)); + .catch((e) => utils.commonLoggers.messageSendError('workerComplete.ts:240', newMsg as DiscordenoMessage, e)); }); } } @@ -271,7 +271,7 @@ Please click on "<@${botId}> *Click to see attachment*" above this message to se embeds: [ ( await generateRollEmbed( - rollRequest.dd.originalMessage.authorId, + rollRequest.dd.authorId, { error: true, errorMsg: diff --git a/src/artigen/managers/handler/workerTerminate.ts b/src/artigen/managers/handler/workerTerminate.ts index aad81ec..e5d3bf7 100644 --- a/src/artigen/managers/handler/workerTerminate.ts +++ b/src/artigen/managers/handler/workerTerminate.ts @@ -28,7 +28,7 @@ export const terminateWorker = async (rollWorker: Worker, rollRequest: QueuedRol embeds: [ ( await generateRollEmbed( - rollRequest.dd.originalMessage.authorId, + rollRequest.dd.authorId, { error: true, errorCode: 'TooComplex', diff --git a/src/artigen/managers/manager.d.ts b/src/artigen/managers/manager.d.ts index cd8bc8d..9c3c608 100644 --- a/src/artigen/managers/manager.d.ts +++ b/src/artigen/managers/manager.d.ts @@ -26,6 +26,7 @@ interface DDQueuedRoll extends BaseQueuedRoll { dd: { myResponse: DiscordenoMessage; originalMessage: DiscordenoMessage; + authorId: bigint; }; } interface TestResultFail { diff --git a/src/artigen/utils/escape.ts b/src/artigen/utils/escape.ts index 2331720..90d2434 100644 --- a/src/artigen/utils/escape.ts +++ b/src/artigen/utils/escape.ts @@ -29,6 +29,9 @@ export const cmdSplitRegex = new RegExp(`(${escapePrefixPostfix(config.prefix)}) // breaks the string on the following: (\*\*) ** for exponents ([+()*/^] for basic algebra (?])- for breaking on - correctly with fate dice) (x\d+(\.\d*)?) x# for variables export const mathSplitRegex = /(\*\*)|([+()*/^]|(?])-)|([xy]\d+(\.\d*)?)/g; +// breaks the string on spaces and newlines, but keeps them in the array to allow for recreating the input correctly +export const argSpacesSplitRegex = /([ \n]+)/g; + // Internal is used for recursive text replacement, these will always be the top level as they get replaced with config.prefix/postfix when exiting each level export const openInternal = '\u2045'; export const closeInternal = '\u2046'; diff --git a/src/commands/_index.ts b/src/commands/_index.ts index db3ee76..7c260d4 100644 --- a/src/commands/_index.ts +++ b/src/commands/_index.ts @@ -1,24 +1,30 @@ -import { alias } from 'commands/aliasCmd.ts'; +import { upsertSlashCommands } from '@discordeno'; + +import { alias, aliasSC } from 'commands/aliasCmd.ts'; import { api } from 'commands/apiCmd.ts'; import { audit } from 'commands/audit.ts'; import { emoji } from 'commands/emoji.ts'; import { handleMentions } from 'commands/handleMentions.ts'; -import { heatmap } from 'commands/heatmap.ts'; -import { help } from 'commands/help.ts'; -import { info } from 'commands/info.ts'; +import { heatmap, heatmapSC } from 'commands/heatmap.ts'; +import { help, helpSC } from 'commands/help.ts'; +import { info, infoSC } from 'commands/info.ts'; import { optIn } from 'commands/optIn.ts'; import { optOut } from 'commands/optOut.ts'; import { ping } from 'commands/ping.ts'; -import { privacy } from 'commands/privacy.ts'; -import { rip } from 'commands/rip.ts'; -import { report } from 'commands/report.ts'; -import { roll } from 'commands/roll.ts'; +import { privacy, privacySC } from 'commands/privacy.ts'; +import { report, reportSC } from 'commands/report.ts'; +import { rip, ripSC } from 'commands/rip.ts'; +import { roll, rollSC } from 'commands/roll.ts'; import { rollHelp } from 'commands/rollHelp.ts'; -import { stats } from 'commands/stats.ts'; -import { toggleInline } from 'commands/toggleInline.ts'; -import { version } from 'commands/version.ts'; +import { stats, statsSC } from 'commands/stats.ts'; +import { toggleInline, toggleInlineSC } from 'commands/toggleInline.ts'; +import { version, versionSC } from 'commands/version.ts'; -export default { +export const announceSlashCommands = () => { + upsertSlashCommands([aliasSC, heatmapSC, helpSC, infoSC, privacySC, reportSC, ripSC, rollSC, statsSC, toggleInlineSC, versionSC]); +}; + +export const commands = { alias, api, audit, @@ -31,11 +37,25 @@ export default { optOut, ping, privacy, - rip, report, + rip, roll, rollHelp, stats, toggleInline, version, }; + +export const slashCommandDetails = { + aliasSC, + heatmapSC, + helpSC, + infoSC, + privacySC, + ripSC, + reportSC, + rollSC, + statsSC, + toggleInlineSC, + versionSC, +}; diff --git a/src/commands/aliasCmd.ts b/src/commands/aliasCmd.ts index 13b3d40..3337c38 100644 --- a/src/commands/aliasCmd.ts +++ b/src/commands/aliasCmd.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { ApplicationCommandOption, CreateGlobalApplicationCommand, DiscordApplicationCommandOptionTypes, DiscordenoMessage } from '@discordeno'; import aliasCommands from 'commands/aliasCmd/_index.ts'; @@ -9,11 +9,122 @@ import { queries } from 'db/common.ts'; import { failColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; -export const alias = (message: DiscordenoMessage, argSpaces: string[]) => { +const aliasNameOption = (action: string, rename = false): ApplicationCommandOption => ({ + type: DiscordApplicationCommandOptionTypes.String, + name: `alias-name${rename ? '-new' : ''}`, + description: `The ${rename ? 'new ' : ''}name of the alias${rename ? '' : `you wish to ${action}`}.`, + required: true, +}); + +const rollStringOption = (action: string): ApplicationCommandOption => ({ + type: DiscordApplicationCommandOptionTypes.String, + name: 'roll-string', + description: `The the full roll string to ${action}.`, + required: true, +}); + +const verificationCodeOption: ApplicationCommandOption = { + type: DiscordApplicationCommandOptionTypes.String, + name: 'verification-code', + description: 'The four digit confirmation code for deletion. Can be left blank to generate one.', + required: false, +}; + +const aliasOptions = (guildMode: boolean): ApplicationCommandOption[] => [ + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'help', + description: `Opens the help library to the ${guildMode ? 'Guild' : 'Personal'} Mode Alias System section.`, + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'list-all', + description: `List all available aliases ${guildMode ? 'in this Guild' : 'on your account'}.`, + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'view', + description: `Preview the roll string behind an alias ${guildMode ? 'in this Guild' : 'on your account'}.`, + options: [aliasNameOption('view')], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'create', + description: `Create a new alias ${guildMode ? 'in this Guild' : 'on your account'}.`, + options: [aliasNameOption('create'), rollStringOption('create')], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'replace', + description: `Update an alias ${guildMode ? 'in this Guild' : 'on your account'} with a new roll string.`, + options: [aliasNameOption('replace'), rollStringOption('replace the old one with')], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'rename', + description: `Rename an alias ${guildMode ? 'in this Guild' : 'on your account'}.`, + options: [aliasNameOption('rename'), aliasNameOption('rename', true)], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'delete-one', + description: `Delete an alias from ${guildMode ? 'this Guild' : 'your account'}.`, + options: [aliasNameOption('delete'), verificationCodeOption], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'delete-all', + description: `Delete all aliases from ${guildMode ? 'this Guild' : 'your account'}.`, + options: [verificationCodeOption], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'copy', + description: `Copy an alias from ${guildMode ? 'this Guild' : 'your account'} to ${guildMode ? 'your account' : 'this Guild'}.`, + options: [aliasNameOption(`copy to ${guildMode ? 'your personal account' : 'this guild'}`)], + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'run', + description: `Runs the specified ${guildMode ? 'Guild' : 'Personal'} alias.`, + options: [ + aliasNameOption('run'), + { + type: DiscordApplicationCommandOptionTypes.String, + name: 'y-variables', + description: 'A space separated list of numbers. Can be left blank if an alias does not require any.', + required: false, + }, + ], + }, +]; + +export const aliasSC: CreateGlobalApplicationCommand = { + name: 'alias', + description: 'Custom Roll Alias system, create and use Roll Aliases for easily reusing the same rolls.', + options: [ + { + type: DiscordApplicationCommandOptionTypes.SubCommandGroup, + name: 'personal', + description: 'Manage and run Personal aliases.', + options: aliasOptions(false), + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommandGroup, + name: 'guild', + description: 'Manage and run Guild aliases.', + options: aliasOptions(true), + }, + ], +}; + +export const alias = (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, argSpaces: string[]) => { // Light telemetry to see how many times a command is being run - dbClient.execute(queries.callIncCnt('alias')).catch((e) => utils.commonLoggers.dbError('aliasCmd.ts:16', 'call sproc INC_CNT on', e)); + dbClient.execute(queries.callIncCnt('alias')).catch((e) => utils.commonLoggers.dbError('aliasCmd.ts:125', 'call sproc INC_CNT on', e)); // argSpaces will come in with a space or \n before every real arg, so extra shifts exist to remove them argSpaces.shift(); @@ -27,17 +138,15 @@ export const alias = (message: DiscordenoMessage, argSpaces: string[]) => { argSpaces.shift(); } - if (guildMode && message.guildId === 0n) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Guild Aliases can only be modified from within the desired guild.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasCmd.ts:38', message, e)); + if (guildMode && BigInt(msgOrInt.guildId) === 0n) { + utils.sendOrInteract(msgOrInt, 'aliasCmd.ts:140', { + embeds: [ + { + color: failColor, + title: 'Guild Aliases can only be modified from within the desired guild.', + }, + ], + }); return; } @@ -46,44 +155,45 @@ export const alias = (message: DiscordenoMessage, argSpaces: string[]) => { case 'h': case '?': case '': - message.send(generateHelpMessage('alias')).catch((e: Error) => utils.commonLoggers.messageSendError('aliasCmd.ts:47', message, e)); + utils.sendOrInteract(msgOrInt, 'aliasCmd.ts:156', generateHelpMessage('alias')); break; case 'list': case 'list-all': - aliasCommands.list(message, guildMode); + aliasCommands.list(msgOrInt, guildMode); break; case 'add': case 'create': case 'set': - aliasCommands.add(message, guildMode, argSpaces); + aliasCommands.add(msgOrInt, guildMode, argSpaces); break; case 'update': case 'replace': - aliasCommands.update(message, guildMode, argSpaces); + aliasCommands.update(msgOrInt, guildMode, argSpaces); break; case 'preview': case 'view': - aliasCommands.view(message, guildMode, argSpaces); + aliasCommands.view(msgOrInt, guildMode, argSpaces); break; case 'delete': case 'remove': - aliasCommands.deleteOne(message, guildMode, argSpaces); + case 'delete-one': + aliasCommands.deleteOne(msgOrInt, guildMode, argSpaces); break; case 'delete-all': case 'remove-all': - aliasCommands.deleteAll(message, guildMode, argSpaces); + aliasCommands.deleteAll(msgOrInt, guildMode, argSpaces); break; case 'clone': case 'copy': - aliasCommands.clone(message, guildMode, argSpaces); + aliasCommands.clone(msgOrInt, guildMode, argSpaces); break; case 'rename': - aliasCommands.rename(message, guildMode, argSpaces); + aliasCommands.rename(msgOrInt, guildMode, argSpaces); break; case 'run': case 'execute': default: - aliasCommands.run(message, guildMode, aliasArg, argSpaces); + aliasCommands.run(msgOrInt, guildMode, aliasArg, argSpaces); break; } }; diff --git a/src/commands/aliasCmd/aliasAddUpdate.ts b/src/commands/aliasCmd/aliasAddUpdate.ts index 7045e7a..bec8784 100644 --- a/src/commands/aliasCmd/aliasAddUpdate.ts +++ b/src/commands/aliasCmd/aliasAddUpdate.ts @@ -1,4 +1,5 @@ import { DiscordenoMessage, EmbedField, hasGuildPermissions } from '@discordeno'; +import { log, LogTypes as LT } from '@Log4Deno'; import config from '~config'; @@ -17,6 +18,8 @@ import dbClient from 'db/client.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { failColor, infoColor1, successColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; interface QueryShape { @@ -31,18 +34,21 @@ const sortYVars = (a: string, b: string) => { return 0; }; -const handleAddUpdate = async (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[], replaceAlias: boolean) => { - if (guildMode && !(await hasGuildPermissions(message.guildId, message.authorId, ['ADMINISTRATOR']))) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: Only Guild Owners and Admins can add/update guild aliases`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:45', message, e)); +const handleAddUpdate = async ( + msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, + guildMode: boolean, + argSpaces: string[], + replaceAlias: boolean, +) => { + if (guildMode && !(await hasGuildPermissions(BigInt(msgOrInt.guildId), utils.getAuthorIdFromMessageOrInteraction(msgOrInt), ['ADMINISTRATOR']))) { + utils.sendOrInteract(msgOrInt, 'aliasAddUpdate.ts:43', { + embeds: [ + { + color: failColor, + title: `Error: Only Guild Owners and Admins can add/update guild aliases`, + }, + ], + }); return; } @@ -50,35 +56,31 @@ const handleAddUpdate = async (message: DiscordenoMessage, guildMode: boolean, a argSpaces.shift(); if (aliasName.length > config.limits.alias.maxNameLength) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Error: Alias Name is too long', - description: - `\`${aliasName}\` (\`${aliasName.length}\` characters) is longer than the allowed max length of \`${config.limits.alias.maxNameLength}\` characters. Please choose a shorter alias name.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:64', message, e)); + utils.sendOrInteract(msgOrInt, 'aliasAddUpdate.ts:59', { + embeds: [ + { + color: failColor, + title: 'Error: Alias Name is too long', + description: + `\`${aliasName}\` (\`${aliasName.length}\` characters) is longer than the allowed max length of \`${config.limits.alias.maxNameLength}\` characters. Please choose a shorter alias name.`, + }, + ], + }); return; } if (ReservedWords.includes(aliasName?.toLowerCase())) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: \`${aliasName}\` is a reserved word`, - description: `Please choose a different name for this alias. + utils.sendOrInteract(msgOrInt, 'aliasAddUpdate.ts:74', { + embeds: [ + { + color: failColor, + title: `Error: \`${aliasName}\` is a reserved word`, + description: `Please choose a different name for this alias. You cannot use any of the following reserved words: \`${ReservedWords.join('`, `')}\`.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:33', message, e)); + }, + ], + }); return; } @@ -86,52 +88,55 @@ You cannot use any of the following reserved words: \`${ReservedWords.join('`, ` const query: QueryShape[] = await dbClient .query( `SELECT aliasName FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [message.guildId, 0n, aliasName.toLowerCase()] : [0n, message.authorId, aliasName.toLowerCase()], + guildMode ? [BigInt(msgOrInt.guildId), 0n, aliasName.toLowerCase()] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName.toLowerCase()], ) .catch((e0) => { utils.commonLoggers.dbError('add.ts:44', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `add-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:47', message, e)); + utils.sendOrInteract( + msgOrInt, + 'aliasAddUpdate.ts:97', + generateAliasError( + 'DB Query Failed.', + `add-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; if (!replaceAlias && query.length) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: \`${aliasName}\` already exists as a ${guildMode ? 'guild' : 'personal'} alias`, - description: 'Please choose a different name for this alias.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:63', message, e)); + utils.sendOrInteract(msgOrInt, 'aliasAddUpdate.ts:109', { + embeds: [ + { + color: failColor, + title: `Error: \`${aliasName}\` already exists as a ${guildMode ? 'guild' : 'personal'} alias`, + description: 'Please choose a different name for this alias.', + }, + ], + }); return; } else if (replaceAlias && !query.length) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: \`${aliasName}\` does not exist as a ${guildMode ? 'guild' : 'personal'} alias`, - description: `If you are trying to create a new ${guildMode ? 'guild' : 'personal'} alias, please run the following command: + utils.sendOrInteract(msgOrInt, 'aliasAddUpdate.ts:121', { + embeds: [ + { + color: failColor, + title: `Error: \`${aliasName}\` does not exist as a ${guildMode ? 'guild' : 'personal'} alias`, + description: `If you are trying to create a new ${guildMode ? 'guild' : 'personal'} alias, please run the following command: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}add\` followed by the desired alias name and roll string. If you are trying to update an existing alias, but forgot the name, please run the following command to view all your ${guildMode ? 'guild ' : ''}aliases: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}list\``, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:63', message, e)); + }, + ], + }); return; } const rawRollStr = argSpaces.join('').trim(); - const newMsg: DiscordenoMessage | void = await message - .send({ + const newMsg: DiscordenoMessage | void = await utils.sendOrInteract( + msgOrInt, + 'aliasAddUpdate.ts:139', + { embeds: [ { color: infoColor1, @@ -141,13 +146,14 @@ If you are trying to update an existing alias, but forgot the name, please run t \`${rawRollStr}\``, }, ], - }) - .catch((e) => { - utils.commonLoggers.dbError('add.ts:78', 'query', e); - errorOut = true; - }); + }, + true, + ); - if (errorOut || !newMsg) return; + if (!newMsg) { + log(LT.ERROR, `My message didn't send! ${msgOrInt}`); + return; + } const [modifiers, remainingArgs] = getModifiers(argSpaces); const failedRollMsg = `The provided roll string (listed below) encountered an error. Please try this roll outside the roll alias system and resolve the error before trying again. @@ -313,25 +319,38 @@ If you are trying to update an existing alias, but forgot the name, please run t .execute('UPDATE aliases SET rollStr = ?, yVarCnt = ? WHERE guildid = ? AND userid = ? AND aliasName = ?', [ rawRollStr, modifiers.yVars.size, - guildMode ? message.guildId : 0n, - guildMode ? 0n : message.authorId, + guildMode ? BigInt(msgOrInt.guildId) : 0n, + guildMode ? 0n : utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName.toLowerCase(), ]) .catch((e0) => { utils.commonLoggers.dbError('add.ts:169', 'update', e0); newMsg - .edit(generateAliasError('DB Update Failed.', `add-q1-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:170', message, e)); + .edit( + generateAliasError( + 'DB Update Failed.', + `add-q1-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ) + .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:170', msgOrInt, e)); errorOut = true; }); } else { const currentAliases: QueryShape[] = await dbClient - .query('SELECT aliasName FROM aliases WHERE guildid = ? AND userid = ?', guildMode ? [message.guildId, 0n] : [0n, message.authorId]) + .query( + 'SELECT aliasName FROM aliases WHERE guildid = ? AND userid = ?', + guildMode ? [BigInt(msgOrInt.guildId), 0n] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt)], + ) .catch((e0) => { utils.commonLoggers.dbError('add.ts:266', 'get count', e0); newMsg - .edit(generateAliasError('DB Query Failed.', `add-q2-${guildMode ? 't' : 'f'}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:269', message, e)); + .edit( + generateAliasError( + 'DB Query Failed.', + `add-q2-${guildMode ? 't' : 'f'}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ) + .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:269', msgOrInt, e)); errorOut = true; }); if (errorOut) return; @@ -339,8 +358,8 @@ If you are trying to update an existing alias, but forgot the name, please run t if (currentAliases.length < (guildMode ? config.limits.alias.free.guild : config.limits.alias.free.user)) { await dbClient .execute('INSERT INTO aliases(guildid,userid,aliasName,rollStr,yVarCnt,premium) values(?,?,?,?,?,?)', [ - guildMode ? message.guildId : 0n, - guildMode ? 0n : message.authorId, + guildMode ? BigInt(msgOrInt.guildId) : 0n, + guildMode ? 0n : utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName.toLowerCase(), rawRollStr, modifiers.yVars.size, @@ -349,8 +368,13 @@ If you are trying to update an existing alias, but forgot the name, please run t .catch((e0) => { utils.commonLoggers.dbError('add.ts:169', 'insert into', e0); newMsg - .edit(generateAliasError('DB Insert Failed.', `add-q3-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:187', message, e)); + .edit( + generateAliasError( + 'DB Insert Failed.', + `add-q3-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ) + .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:187', msgOrInt, e)); errorOut = true; }); } else { @@ -386,9 +410,9 @@ If you need this limit raised, please join the [support server](${config.links.s }, ], }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:321', message, e)); + .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:321', msgOrInt, e)); }; // Using wrappers to limit "magic" booleans -export const add = (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => handleAddUpdate(message, guildMode, argSpaces, false); -export const update = (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => handleAddUpdate(message, guildMode, argSpaces, true); +export const add = (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => handleAddUpdate(msgOrInt, guildMode, argSpaces, false); +export const update = (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => handleAddUpdate(msgOrInt, guildMode, argSpaces, true); diff --git a/src/commands/aliasCmd/aliasDelete.ts b/src/commands/aliasCmd/aliasDelete.ts index 99522bd..25c741a 100644 --- a/src/commands/aliasCmd/aliasDelete.ts +++ b/src/commands/aliasCmd/aliasDelete.ts @@ -7,24 +7,24 @@ import dbClient from 'db/client.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { failColor, successColor, warnColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; -const handleDelete = async (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[], deleteAll: boolean) => { - if (guildMode && !(await hasGuildPermissions(message.guildId, message.authorId, ['ADMINISTRATOR']))) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Error: Only Guild Owners and Admins can delete guild aliases', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:16', message, e)); +const handleDelete = async (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[], deleteAll: boolean) => { + if (guildMode && !(await hasGuildPermissions(BigInt(msgOrInt.guildId), utils.getAuthorIdFromMessageOrInteraction(msgOrInt), ['ADMINISTRATOR']))) { + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:16', { + embeds: [ + { + color: failColor, + title: 'Error: Only Guild Owners and Admins can delete guild aliases', + }, + ], + }); return; } - const verificationCode = (guildMode ? message.guildId : message.authorId).toString().slice(-4); + const verificationCode = (guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)).toString().slice(-4); const aliasName = (argSpaces.shift() || '').trim(); argSpaces.shift(); const userEnteredVCode = (argSpaces.shift() || '').trim(); @@ -32,52 +32,46 @@ const handleDelete = async (message: DiscordenoMessage, guildMode: boolean, argS if (!deleteAll) { if (!aliasName) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Error: Please specify one alias to delete', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:38', message, e)); + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:36', { + embeds: [ + { + color: failColor, + title: 'Error: Please specify one alias to delete', + }, + ], + }); return; } else if (!userEnteredVCode) { - message - .send({ - embeds: [ - { - color: warnColor, - title: `Deletion is permanent, please confirm you want to delete \`${aliasName}\``, - description: `Are you sure you want to delete the ${guildMode ? 'guild' : 'personal'} alias \`${aliasName}\`? + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:47', { + embeds: [ + { + color: warnColor, + title: `Deletion is permanent, please confirm you want to delete \`${aliasName}\``, + description: `Are you sure you want to delete the ${guildMode ? 'guild' : 'personal'} alias \`${aliasName}\`? If you are certain you want to delete \`${aliasName}\` from ${guildMode ? 'this guild' : 'your account'}, please run the following command: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}delete ${aliasName} ${verificationCode}\``, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:54', message, e)); + }, + ], + }); return; } else if (userEnteredVCode !== verificationCode) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Error: Incorrect verification code', - description: `If you are certain you want to delete \`${aliasName}\` from ${guildMode ? 'this guild' : 'your account'}, please run the following command: + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:62', { + embeds: [ + { + color: failColor, + title: 'Error: Incorrect verification code', + description: `If you are certain you want to delete \`${aliasName}\` from ${guildMode ? 'this guild' : 'your account'}, please run the following command: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}delete ${aliasName} ${verificationCode}\``, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:70', message, e)); + }, + ], + }); return; } else if (userEnteredVCode === verificationCode) { const deleteResults = await dbClient .execute('DELETE FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?', [ - guildMode ? message.guildId : 0n, - guildMode ? 0n : message.authorId, + guildMode ? BigInt(msgOrInt.guildId) : 0n, + guildMode ? 0n : utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName, ]) .catch((e) => { @@ -85,12 +79,17 @@ If you are certain you want to delete \`${aliasName}\` from ${guildMode ? 'this errorOut = true; }); if (errorOut || !deleteResults) { - message - .send(generateAliasError('Delete failed.', `delete-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:86', message, e)); + utils.sendOrInteract( + msgOrInt, + 'aliasDelete.ts:86', + generateAliasError( + 'Delete failed.', + `delete-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); return; } else if (deleteResults.affectedRows) { - message.send({ + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:95', { embeds: [ { color: successColor, @@ -100,7 +99,7 @@ If you are certain you want to delete \`${aliasName}\` from ${guildMode ? 'this ], }); } else { - message.send({ + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:105', { embeds: [ { color: warnColor, @@ -114,58 +113,60 @@ Please run \`${config.prefix}ra ${guildMode ? 'guild ' : ''}list\` to view the c } return; } else { - message - .send(generateAliasError('How are you here?', 'deleteOne-how')) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:117', message, e)); + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:119', generateAliasError('How are you here?', 'deleteOne-how')); return; } } else { // We're in deleteAll mode, so aliasName will carry the user verification code. // Since one wasn't provided, prompt for confirmation if (!aliasName) { - message - .send({ - embeds: [ - { - color: warnColor, - title: 'Deletion is permanent, please confirm you want to delete all aliases', - description: `Are you sure you want to delete all aliases for ${guildMode ? 'this guild' : 'your account'}? + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:119', { + embeds: [ + { + color: warnColor, + title: 'Deletion is permanent, please confirm you want to delete all aliases', + description: `Are you sure you want to delete all aliases for ${guildMode ? 'this guild' : 'your account'}? If you are certain you want to delete all aliases for ${guildMode ? 'this guild' : 'your account'}, please run the following command: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}delete-all ${verificationCode}\``, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:137', message, e)); + }, + ], + }); return; } else if (aliasName !== verificationCode) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Error: Incorrect verification code', - description: `If you are certain you want to delete all aliases for ${guildMode ? 'this guild' : 'your account'}, please run the following command: + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:142', { + embeds: [ + { + color: failColor, + title: 'Error: Incorrect verification code', + description: `If you are certain you want to delete all aliases for ${guildMode ? 'this guild' : 'your account'}, please run the following command: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}delete-all ${verificationCode}\``, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:70', message, e)); + }, + ], + }); return; } else if (aliasName === verificationCode) { const deleteResults = await dbClient - .execute('DELETE FROM aliases WHERE guildid = ? AND userid = ?', [guildMode ? message.guildId : 0n, guildMode ? 0n : message.authorId]) + .execute('DELETE FROM aliases WHERE guildid = ? AND userid = ?', [ + guildMode ? BigInt(msgOrInt.guildId) : 0n, + guildMode ? 0n : utils.getAuthorIdFromMessageOrInteraction(msgOrInt), + ]) .catch((e) => { utils.commonLoggers.dbError('aliasDelete.ts:159', 'delete from aliases', e); errorOut = true; }); if (errorOut || !deleteResults) { - message - .send(generateAliasError('Delete failed.', `delete-q1-${guildMode ? 't' : 'f'}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:165', message, e)); + utils.sendOrInteract( + msgOrInt, + 'aliasDelete.ts:165', + generateAliasError( + 'Delete failed.', + `delete-q1-${guildMode ? 't' : 'f'}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); return; } else if (deleteResults.affectedRows) { - message.send({ + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:174', { embeds: [ { color: successColor, @@ -175,7 +176,7 @@ If you are certain you want to delete all aliases for ${guildMode ? 'this guild' ], }); } else { - message.send({ + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:184', { embeds: [ { color: warnColor, @@ -190,14 +191,12 @@ If anything shows up there after running this command, please \`${config.prefix} } return; } else { - message - .send(generateAliasError('How are you here?', 'deleteAll-how')) - .catch((e: Error) => utils.commonLoggers.messageSendError('aliasDelete.ts:194', message, e)); + utils.sendOrInteract(msgOrInt, 'aliasDelete.ts:199', generateAliasError('How are you here?', 'deleteAll-how')); return; } } }; // Using wrappers to limit "magic" booleans -export const deleteOne = (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => handleDelete(message, guildMode, argSpaces, false); -export const deleteAll = (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => handleDelete(message, guildMode, argSpaces, true); +export const deleteOne = (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => handleDelete(msgOrInt, guildMode, argSpaces, false); +export const deleteAll = (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => handleDelete(msgOrInt, guildMode, argSpaces, true); diff --git a/src/commands/aliasCmd/clone.ts b/src/commands/aliasCmd/clone.ts index b4c37e0..3879058 100644 --- a/src/commands/aliasCmd/clone.ts +++ b/src/commands/aliasCmd/clone.ts @@ -7,6 +7,8 @@ import dbClient from 'db/client.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { failColor, successColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; interface QueryShape { @@ -15,34 +17,30 @@ interface QueryShape { rollStr: string; } -export const clone = async (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => { - if (!guildMode && !(await hasGuildPermissions(message.guildId, message.authorId, ['ADMINISTRATOR']))) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: Only Guild Owners and Admins can copy a personal alias to a guild aliases`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:16', message, e)); +export const clone = async (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => { + if (!guildMode && !(await hasGuildPermissions(BigInt(msgOrInt.guildId), utils.getAuthorIdFromMessageOrInteraction(msgOrInt), ['ADMINISTRATOR']))) { + utils.sendOrInteract(msgOrInt, 'clone.ts:22', { + embeds: [ + { + color: failColor, + title: `Error: Only Guild Owners and Admins can copy a personal alias to a guild aliases`, + }, + ], + }); return; } const aliasName = (argSpaces.shift() || '').trim().toLowerCase(); if (!aliasName) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: Please specify an alias to copy to ${guildMode ? 'your account' : 'this guild'}`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:32', message, e)); + utils.sendOrInteract(msgOrInt, 'clone.ts:37', { + embeds: [ + { + color: failColor, + title: `Error: Please specify an alias to copy to ${guildMode ? 'your account' : 'this guild'}`, + }, + ], + }); return; } @@ -50,13 +48,18 @@ export const clone = async (message: DiscordenoMessage, guildMode: boolean, argS const query: QueryShape[] = await dbClient .query( `SELECT aliasName, yVarCnt, rollStr FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [message.guildId, 0n, aliasName] : [0n, message.authorId, aliasName], + guildMode ? [BigInt(msgOrInt.guildId), 0n, aliasName] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName], ) .catch((e0) => { utils.commonLoggers.dbError('clone.ts:51', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `clone-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:54', message, e)); + utils.sendOrInteract( + msgOrInt, + 'clone.ts:57', + generateAliasError( + 'DB Query Failed.', + `clone-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; @@ -64,52 +67,53 @@ export const clone = async (message: DiscordenoMessage, guildMode: boolean, argS const details = query[0]; if (!details) { - message - .send({ - embeds: [ - { - color: failColor, - title: `\`${aliasName}\` does not exist as a${guildMode ? ' guild alias' : 'n alias on your account'}.`, - description: `Did you mean to run \`${config.prefix}ra ${guildMode ? '' : 'guild '}clone ${aliasName}\`?`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:73', message, e)); + utils.sendOrInteract(msgOrInt, 'clone.ts:71', { + embeds: [ + { + color: failColor, + title: `\`${aliasName}\` does not exist as a${guildMode ? ' guild alias' : 'n alias on your account'}.`, + description: `Did you mean to run \`${config.prefix}ra ${guildMode ? '' : 'guild '}clone ${aliasName}\`?`, + }, + ], + }); } const targetQuery: QueryShape[] = await dbClient .query( `SELECT aliasName, yVarCnt, rollStr FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [0n, message.authorId, aliasName] : [message.guildId, 0n, aliasName], + guildMode ? [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName] : [BigInt(msgOrInt.guildId), 0n, aliasName], ) .catch((e0) => { utils.commonLoggers.dbError('clone.ts:82', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `clone-q1-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:85', message, e)); + utils.sendOrInteract( + msgOrInt, + 'clone.ts:90', + generateAliasError( + 'DB Query Failed.', + `clone-q1-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; if (targetQuery.length) { - message - .send({ - embeds: [ - { - color: failColor, - title: `\`${aliasName}\` already exists as an alias ${guildMode ? 'on your account' : 'in this guild'}.`, - description: `Please delete or rename the ${guildMode ? 'personal' : 'guild'} alias \`${aliasName}\` and try again.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:101', message, e)); + utils.sendOrInteract(msgOrInt, 'clone.ts:102', { + embeds: [ + { + color: failColor, + title: `\`${aliasName}\` already exists as an alias ${guildMode ? 'on your account' : 'in this guild'}.`, + description: `Please delete or rename the ${guildMode ? 'personal' : 'guild'} alias \`${aliasName}\` and try again.`, + }, + ], + }); return; } await dbClient .execute(`INSERT INTO aliases(guildid,userid,aliasName,rollStr,yVarCnt,premium) values(?,?,?,?,?,?)`, [ - guildMode ? 0n : message.guildId, - guildMode ? message.authorId : 0n, + guildMode ? 0n : BigInt(msgOrInt.guildId), + guildMode ? utils.getAuthorIdFromMessageOrInteraction(msgOrInt) : 0n, aliasName, details.rollStr, details.yVarCnt, @@ -117,22 +121,25 @@ export const clone = async (message: DiscordenoMessage, guildMode: boolean, argS ]) .catch((e0) => { utils.commonLoggers.dbError('clone.ts:110', 'query', e0); - message - .send(generateAliasError('DB Insert Failed.', `clone-q2-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:113', message, e)); + utils.sendOrInteract( + msgOrInt, + 'clone.ts:126', + generateAliasError( + 'DB Insert Failed.', + `clone-q2-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; - message - .send({ - embeds: [ - { - color: successColor, - title: `Successfully copied the ${guildMode ? 'guild' : 'personal'} alias \`${aliasName}\`!`, - description: `\`${aliasName}\` is now available as an alias ${guildMode ? 'on your account' : 'in this guild'}.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('clone.ts:132', message, e)); + utils.sendOrInteract(msgOrInt, 'clone.ts:137', { + embeds: [ + { + color: successColor, + title: `Successfully copied the ${guildMode ? 'guild' : 'personal'} alias \`${aliasName}\`!`, + description: `\`${aliasName}\` is now available as an alias ${guildMode ? 'on your account' : 'in this guild'}.`, + }, + ], + }); }; diff --git a/src/commands/aliasCmd/list.ts b/src/commands/aliasCmd/list.ts index 9a971ce..964201a 100644 --- a/src/commands/aliasCmd/list.ts +++ b/src/commands/aliasCmd/list.ts @@ -5,6 +5,8 @@ import dbClient from 'db/client.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { successColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; interface QueryShape { @@ -12,38 +14,38 @@ interface QueryShape { yVarCnt: number; } -export const list = async (message: DiscordenoMessage, guildMode: boolean) => { +export const list = async (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean) => { let errorOut = false; const query: QueryShape[] = await dbClient .query( `SELECT aliasName, yVarCnt FROM aliases WHERE guildid = ? AND userid = ? ORDER BY createdAt ASC`, - guildMode ? [message.guildId, 0n] : [0n, message.authorId], + guildMode ? [BigInt(msgOrInt.guildId), 0n] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt)], ) .catch((e0) => { utils.commonLoggers.dbError('list.ts:10', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `list-q0-${guildMode ? 't' : 'f'}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('list.ts:11', message, e)); + utils.sendOrInteract( + msgOrInt, + 'list.ts:26', + generateAliasError( + 'DB Query Failed.', + `list-q0-${guildMode ? 't' : 'f'}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; - message - .send({ - embeds: [ - { - color: successColor, - title: `Found ${query.length} alias${query.length === 1 ? '' : 'es'} for ${guildMode ? 'this guild' : 'your account'}:`, - description: query.length - ? `Format shown is \`alias-name\` followed by the number of yVars required for the alias in parenthesis, if there are any required. + utils.sendOrInteract(msgOrInt, 'list.ts:33', { + embeds: [ + { + color: successColor, + title: `Found ${query.length} alias${query.length === 1 ? '' : 'es'} for ${guildMode ? 'this guild' : 'your account'}:`, + description: query.length + ? `Format shown is \`alias-name\` followed by the number of yVars required for the alias in parenthesis, if there are any required. ${query.map((a) => `\`${a.aliasName}\`${a.yVarCnt ? ` (${a.yVarCnt})` : ''}`).join(', ')}` - : '', - }, - ], - }) - .catch((e0) => { - utils.commonLoggers.messageSendError('list.ts:39', message, e0); - message.send(generateAliasError('Message Send Failed.', `list-m0-${guildMode ? 't' : 'f'}-${guildMode ? message.guildId : message.authorId}`)); - }); + : '', + }, + ], + }); }; diff --git a/src/commands/aliasCmd/rename.ts b/src/commands/aliasCmd/rename.ts index 117cd10..892000b 100644 --- a/src/commands/aliasCmd/rename.ts +++ b/src/commands/aliasCmd/rename.ts @@ -7,24 +7,24 @@ import dbClient from 'db/client.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { failColor, successColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; interface QueryShape { aliasName: string; } -export const rename = async (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => { - if (guildMode && !(await hasGuildPermissions(message.guildId, message.authorId, ['ADMINISTRATOR']))) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: Only Guild Owners and Admins can rename a guild aliases`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('rename.ts:25', message, e)); +export const rename = async (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => { + if (guildMode && !(await hasGuildPermissions(BigInt(msgOrInt.guildId), utils.getAuthorIdFromMessageOrInteraction(msgOrInt), ['ADMINISTRATOR']))) { + utils.sendOrInteract(msgOrInt, 'rename.ts:20', { + embeds: [ + { + color: failColor, + title: `Error: Only Guild Owners and Admins can rename a guild aliases`, + }, + ], + }); return; } @@ -33,16 +33,14 @@ export const rename = async (message: DiscordenoMessage, guildMode: boolean, arg const newAliasName = (argSpaces.shift() || '').trim().toLowerCase(); if (!oldAliasName || !newAliasName) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: Please specify both an alias to rename, and the new name to set it to.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('rename.ts:32', message, e)); + utils.sendOrInteract(msgOrInt, 'rename.ts:37', { + embeds: [ + { + color: failColor, + title: `Error: Please specify both an alias to rename, and the new name to set it to.`, + }, + ], + }); return; } @@ -51,59 +49,65 @@ export const rename = async (message: DiscordenoMessage, guildMode: boolean, arg const queryOld: QueryShape[] = await dbClient .query( `SELECT aliasName FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [message.guildId, 0n, oldAliasName] : [0n, message.authorId, oldAliasName], + guildMode ? [BigInt(msgOrInt.guildId), 0n, oldAliasName] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), oldAliasName], ) .catch((e0) => { utils.commonLoggers.dbError('rename.ts:44', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `rename-q0-${guildMode ? 't' : 'f'}-${oldAliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('rename.ts:47', message, e)); + utils.sendOrInteract( + msgOrInt, + 'rename.ts:58', + generateAliasError( + 'DB Query Failed.', + `rename-q0-${guildMode ? 't' : 'f'}-${oldAliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; if (!queryOld.length) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: \`${oldAliasName}\` does not exist as a ${guildMode ? 'guild' : 'personal'} alias.`, - description: `If you are trying to update an existing alias, but forgot the name, please run the following command to view all your ${guildMode ? 'guild ' : ''}aliases: + utils.sendOrInteract(msgOrInt, 'rename.ts:70', { + embeds: [ + { + color: failColor, + title: `Error: \`${oldAliasName}\` does not exist as a ${guildMode ? 'guild' : 'personal'} alias.`, + description: `If you are trying to update an existing alias, but forgot the name, please run the following command to view all your ${guildMode ? 'guild ' : ''}aliases: \`${config.prefix}ra ${guildMode ? 'guild ' : ''}list\``, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:63', message, e)); + }, + ], + }); return; } const queryNew: QueryShape[] = await dbClient .query( `SELECT aliasName FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [message.guildId, 0n, newAliasName] : [0n, message.authorId, newAliasName], + guildMode ? [BigInt(msgOrInt.guildId), 0n, newAliasName] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), newAliasName], ) .catch((e0) => { utils.commonLoggers.dbError('rename.ts:44', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `rename-q1-${guildMode ? 't' : 'f'}-${newAliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('rename.ts:47', message, e)); + utils.sendOrInteract( + msgOrInt, + 'rename.ts:91', + generateAliasError( + 'DB Query Failed.', + `rename-q1-${guildMode ? 't' : 'f'}-${newAliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; if (queryNew.length) { - message - .send({ - embeds: [ - { - color: failColor, - title: `Error: \`${newAliasName}\` already exists as a ${guildMode ? 'guild' : 'personal'} alias.`, - description: 'Please choose a different name for this alias.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('add.ts:63', message, e)); + utils.sendOrInteract(msgOrInt, 'rename.ts:103', { + embeds: [ + { + color: failColor, + title: `Error: \`${newAliasName}\` already exists as a ${guildMode ? 'guild' : 'personal'} alias.`, + description: 'Please choose a different name for this alias.', + }, + ], + }); return; } @@ -111,32 +115,30 @@ export const rename = async (message: DiscordenoMessage, guildMode: boolean, arg await dbClient .execute('UPDATE aliases SET aliasName = ? WHERE guildid = ? AND userid = ? AND aliasName = ?', [ newAliasName, - guildMode ? message.guildId : 0n, - guildMode ? 0n : message.authorId, + guildMode ? BigInt(msgOrInt.guildId) : 0n, + guildMode ? 0n : utils.getAuthorIdFromMessageOrInteraction(msgOrInt), oldAliasName, ]) .catch((e0) => { utils.commonLoggers.dbError('rename.ts:169', 'update', e0); - message - .send( - generateAliasError( - 'DB Update Failed.', - `rename-q2-${guildMode ? 't' : 'f'}-${oldAliasName}-${newAliasName}-${guildMode ? message.guildId : message.authorId}`, - ), - ) - .catch((e: Error) => utils.commonLoggers.messageSendError('rename.ts:170', message, e)); + utils.sendOrInteract( + msgOrInt, + 'rename.ts:126', + generateAliasError( + 'DB Update Failed.', + `rename-q2-${guildMode ? 't' : 'f'}-${oldAliasName}-${newAliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); - message - .send({ - embeds: [ - { - color: successColor, - title: `Successfully renamed the ${guildMode ? 'guild' : 'personal'} alias \`${oldAliasName}\` to \`${newAliasName}\`!`, - description: `\`${newAliasName}\` is now available as an alias ${guildMode ? 'in this guild' : 'on your account'}.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('rename.ts:132', message, e)); + utils.sendOrInteract(msgOrInt, 'rename.ts:136', { + embeds: [ + { + color: successColor, + title: `Successfully renamed the ${guildMode ? 'guild' : 'personal'} alias \`${oldAliasName}\` to \`${newAliasName}\`!`, + description: `\`${newAliasName}\` is now available as an alias ${guildMode ? 'in this guild' : 'on your account'}.`, + }, + ], + }); }; diff --git a/src/commands/aliasCmd/reservedWords.ts b/src/commands/aliasCmd/reservedWords.ts index 445548f..c0da9aa 100644 --- a/src/commands/aliasCmd/reservedWords.ts +++ b/src/commands/aliasCmd/reservedWords.ts @@ -14,6 +14,7 @@ export const ReservedWords = Object.freeze([ 'view', 'delete', 'remove', + 'delete-one', 'delete-all', 'remove-all', 'run', diff --git a/src/commands/aliasCmd/run.ts b/src/commands/aliasCmd/run.ts index 17500d3..7eda98a 100644 --- a/src/commands/aliasCmd/run.ts +++ b/src/commands/aliasCmd/run.ts @@ -1,4 +1,5 @@ -import { DiscordenoMessage } from '@discordeno'; +import { DiscordenoMessage, hasOwnProperty } from '@discordeno'; +import { log, LogTypes as LT } from '@Log4Deno'; import config from '~config'; @@ -6,7 +7,8 @@ import { getModifiers } from 'artigen/dice/getModifiers.ts'; import { sendRollRequest } from 'artigen/managers/queueManager.ts'; -import { generateRollError, rollingEmbed } from 'artigen/utils/embeds.ts'; +import { rollingEmbed } from 'artigen/utils/embeds.ts'; +import { argSpacesSplitRegex } from 'artigen/utils/escape.ts'; import dbClient from 'db/client.ts'; import { queries } from 'db/common.ts'; @@ -14,6 +16,8 @@ import { queries } from 'db/common.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { failColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; interface QueryShape { @@ -22,7 +26,7 @@ interface QueryShape { rollStr: string; } -export const run = async (message: DiscordenoMessage, guildMode: boolean, command: string, argSpaces: string[]) => { +export const run = async (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, command: string, argSpaces: string[]) => { let errorOut = false; const aliasName = (command === 'run' || command === 'execute' ? argSpaces.shift() || '' : command)?.trim().toLowerCase(); const yVars = new Map(); @@ -37,13 +41,18 @@ export const run = async (message: DiscordenoMessage, guildMode: boolean, comman let query: QueryShape[] = await dbClient .query( `SELECT aliasName, yVarCnt, rollStr FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [message.guildId, 0n, aliasName] : [0n, message.authorId, aliasName], + guildMode ? [BigInt(msgOrInt.guildId), 0n, aliasName] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName], ) .catch((e0) => { utils.commonLoggers.dbError('run.ts:30', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `run-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('run.ts:33', message, e)); + utils.sendOrInteract( + msgOrInt, + 'run.ts:47', + generateAliasError( + 'DB Query Failed.', + `run-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; @@ -51,12 +60,17 @@ export const run = async (message: DiscordenoMessage, guildMode: boolean, comman if (!guildMode && !query.length) { // Didn't find an alias for the user, maybe their doing an implicit guild mode? query = await dbClient - .query(`SELECT aliasName, yVarCnt, rollStr FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, [message.guildId, 0n, aliasName]) + .query(`SELECT aliasName, yVarCnt, rollStr FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, [BigInt(msgOrInt.guildId), 0n, aliasName]) .catch((e0) => { utils.commonLoggers.dbError('run.ts:43', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `run-q1-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('run.ts:46', message, e)); + utils.sendOrInteract( + msgOrInt, + 'run.ts:64', + generateAliasError( + 'DB Query Failed.', + `run-q1-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; @@ -64,43 +78,45 @@ export const run = async (message: DiscordenoMessage, guildMode: boolean, comman const details = query.shift(); if (!details) { - message - .send({ - embeds: [ - { - color: failColor, - title: `No alias named \`${aliasName}\` found${guildMode ? ' ' : ' on your account or '}in this guild`, - description: `Please run \`${config.prefix}ra ${guildMode ? 'guild ' : ''}list\` to view the available aliases.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('run.ts:63', message, e)); + utils.sendOrInteract(msgOrInt, 'run.ts:78', { + embeds: [ + { + color: failColor, + title: `No alias named \`${aliasName}\` found${guildMode ? ' ' : ' on your account or '}in this guild`, + description: `Please run \`${config.prefix}ra ${guildMode ? 'guild ' : ''}list\` to view the available aliases.`, + }, + ], + }); return; } if (yVars.size < details.yVarCnt) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Not enough yVars provided', - description: `The alias \`${aliasName}\` requires \`${details.yVarCnt}\` yVars, but only \`${yVars.size}\` were provided. The roll string for this alias is: + utils.sendOrInteract(msgOrInt, 'run.ts:92', { + embeds: [ + { + color: failColor, + title: 'Not enough yVars provided', + description: `The alias \`${aliasName}\` requires \`${details.yVarCnt}\` yVars, but only \`${yVars.size}\` were provided. The roll string for this alias is: \`${details.rollStr}\``.slice(0, 3_000), - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('run.ts:81', message, e)); + }, + ], + }); return; } - const m = await message.reply(rollingEmbed); + const m = await utils.sendOrInteract(msgOrInt, 'run.ts:115', rollingEmbed, true); + if (!m) { + log(LT.ERROR, `My message didn't send! ${msgOrInt}`); + return; + } - const rollStrArgSpaces = details.rollStr.split(/([ \n]+)/g); + const rollStrArgSpaces = details.rollStr.split(argSpacesSplitRegex).filter((x) => x); const [modifiers, remainingArgs] = getModifiers(rollStrArgSpaces); if (!modifiers.valid) { - m.edit(generateRollError('Modifiers invalid:', modifiers.error.name, modifiers.error.message)).catch((e) => utils.commonLoggers.messageEditError('run.ts:96', m, e)); + // m.edit(generateRollError('Modifiers invalid:', modifiers.error.name, modifiers.error.message)).catch((e) => + // utils.commonLoggers.messageEditError('run.ts:96', m, e) + // ); return; } @@ -113,7 +129,11 @@ export const run = async (message: DiscordenoMessage, guildMode: boolean, comman apiRoll: false, ddRoll: true, testRoll: false, - dd: { myResponse: m, originalMessage: message }, + dd: { + myResponse: m, + originalMessage: hasOwnProperty(msgOrInt, 'token') ? m : msgOrInt, + authorId: utils.getAuthorIdFromMessageOrInteraction(msgOrInt), + }, rollCmd: remainingArgs.join(''), modifiers, originalCommand: details.rollStr, diff --git a/src/commands/aliasCmd/view.ts b/src/commands/aliasCmd/view.ts index b434edd..bd97594 100644 --- a/src/commands/aliasCmd/view.ts +++ b/src/commands/aliasCmd/view.ts @@ -7,6 +7,8 @@ import dbClient from 'db/client.ts'; import { generateAliasError } from 'embeds/alias.ts'; import { failColor, successColor } from 'embeds/colors.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; interface QueryShape { @@ -15,25 +17,23 @@ interface QueryShape { rollStr: string; } -export const view = async (message: DiscordenoMessage, guildMode: boolean, argSpaces: string[]) => { +export const view = async (msgOrInt: DiscordenoMessage | SlashCommandInteractionWithGuildId, guildMode: boolean, argSpaces: string[]) => { const aliasName = argSpaces.shift(); if (!aliasName) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'No alias provided.', - description: `Please run this command again with an alias to search for, for example + utils.sendOrInteract(msgOrInt, 'view.ts:24', { + embeds: [ + { + color: failColor, + title: 'No alias provided.', + description: `Please run this command again with an alias to search for, for example If you need to see all aliases for ${guildMode ? 'this guild' : 'your account'}, please run \`${config.prefix}ra ${guildMode ? 'guild ' : ''}list\` to see all of ${ - guildMode ? "this guild's" : 'your' - } current aliases.`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('view.ts:35', message, e)); + guildMode ? "this guild's" : 'your' + } current aliases.`, + }, + ], + }); return; } @@ -41,13 +41,18 @@ If you need to see all aliases for ${guildMode ? 'this guild' : 'your account'}, const query: QueryShape[] = await dbClient .query( `SELECT aliasName, yVarCnt, rollStr FROM aliases WHERE guildid = ? AND userid = ? AND aliasName = ?`, - guildMode ? [message.guildId, 0n, aliasName.toLowerCase()] : [0n, message.authorId, aliasName.toLowerCase()], + guildMode ? [BigInt(msgOrInt.guildId), 0n, aliasName.toLowerCase()] : [0n, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), aliasName.toLowerCase()], ) .catch((e0) => { utils.commonLoggers.dbError('view.ts:46', 'query', e0); - message - .send(generateAliasError('DB Query Failed.', `view-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`)) - .catch((e: Error) => utils.commonLoggers.messageSendError('view.ts:49', message, e)); + utils.sendOrInteract( + msgOrInt, + 'view.ts:50', + generateAliasError( + 'DB Query Failed.', + `view-q0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? BigInt(msgOrInt.guildId) : utils.getAuthorIdFromMessageOrInteraction(msgOrInt)}`, + ), + ); errorOut = true; }); if (errorOut) return; @@ -55,34 +60,25 @@ If you need to see all aliases for ${guildMode ? 'this guild' : 'your account'}, const details = query[0]; if (details) { - message - .send({ - embeds: [ - { - color: successColor, - title: `Found the alias \`${aliasName}\` for ${guildMode ? 'this guild' : 'your account'}:`, - description: `Y Var Count: \`${details.yVarCnt}\` Alias Name: \`${details.aliasName}\` + utils.sendOrInteract(msgOrInt, 'view.ts:63', { + embeds: [ + { + color: successColor, + title: `Found the alias \`${aliasName}\` for ${guildMode ? 'this guild' : 'your account'}:`, + description: `Y Var Count: \`${details.yVarCnt}\` Alias Name: \`${details.aliasName}\` ${details.rollStr}`, - }, - ], - }) - .catch((e0) => { - utils.commonLoggers.messageSendError('view.ts:69', message, e0); - message.send( - generateAliasError('Message Send Failed.', `view-m0-${guildMode ? 't' : 'f'}-${aliasName}-${guildMode ? message.guildId : message.authorId}`), - ); - }); + }, + ], + }); } else { - message - .send({ - embeds: [ - { - color: failColor, - title: `\`${aliasName}\` does not exist as a${guildMode ? ' guild alias' : 'n alias on your account'}.`, - description: `Did you mean to run \`${config.prefix}ra ${guildMode ? '' : 'guild '}view ${aliasName}\`?`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('view.ts:85', message, e)); + utils.sendOrInteract(msgOrInt, 'view.ts:74', { + embeds: [ + { + color: failColor, + title: `\`${aliasName}\` does not exist as a${guildMode ? ' guild alias' : 'n alias on your account'}.`, + description: `Did you mean to run \`${config.prefix}ra ${guildMode ? '' : 'guild '}view ${aliasName}\`?`, + }, + ], + }); } }; diff --git a/src/commands/heatmap.ts b/src/commands/heatmap.ts index 5fa9ef5..d3694cc 100644 --- a/src/commands/heatmap.ts +++ b/src/commands/heatmap.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; import config from '~config'; @@ -10,42 +10,43 @@ import { failColor, infoColor2 } from 'embeds/colors.ts'; import intervals from 'utils/intervals.ts'; import utils from 'utils/utils.ts'; -export const heatmap = (message: DiscordenoMessage) => { +export const heatmapSC: CreateGlobalApplicationCommand = { + name: 'heatmap', + description: 'Shows a heatmap of when the roll command is run the most.', +}; + +export const heatmap = (msgOrInt: DiscordenoMessage | Interaction) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('heatmap')).catch((e) => utils.commonLoggers.dbError('heatmap.ts:14', 'call sproc INC_CNT on', e)); if (config.api.enable) { - message - .send({ - embeds: [ - { - title: 'Roll Heatmap', - description: `Over time, this image will show a nice pattern of when rolls are requested the most. + utils.sendOrInteract(msgOrInt, 'heatmap.ts:23', { + embeds: [ + { + title: 'Roll Heatmap', + description: `Over time, this image will show a nice pattern of when rolls are requested the most. Least Rolls: ${intervals.getMinRollCnt()} Most Rolls: ${intervals.getMaxRollCnt()}`, - footer: { - text: 'Data is shown in US Eastern Time. | This heatmap uses data starting 6/26/2022.', - }, - color: infoColor2, - image: { - url: `${config.api.publicDomain}api/heatmap.png?now=${new Date().getTime()}`, - }, + footer: { + text: 'Data is shown in US Eastern Time. | This heatmap uses data starting 6/26/2022.', }, - ], - }) - .catch((e) => utils.commonLoggers.messageSendError('heatmap.ts:21', message, e)); + color: infoColor2, + image: { + url: `${config.api.publicDomain}api/heatmap.png?now=${new Date().getTime()}`, + }, + }, + ], + }); } else { - message - .send({ - embeds: [ - { - title: 'Roll Heatmap Disabled', - description: "This command requires the bot's API to be enabled. If you are the host of this bot, check your `config.ts` file to enable it.", - color: failColor, - }, - ], - }) - .catch((e) => utils.commonLoggers.messageSendError('heatmap.ts:21', message, e)); + utils.sendOrInteract(msgOrInt, 'heatmap.ts:42', { + embeds: [ + { + title: 'Roll Heatmap Disabled', + description: "This command requires the bot's API to be enabled. If you are the host of this bot, check your `config.ts` file to enable it.", + color: failColor, + }, + ], + }); } }; diff --git a/src/commands/help.ts b/src/commands/help.ts index b238fb0..7257bbe 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,4 +1,6 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; + +import config from '~config'; import { generateHelpMessage } from 'commands/helpLibrary/generateHelpMessage.ts'; @@ -7,8 +9,13 @@ import { queries } from 'db/common.ts'; import utils from 'utils/utils.ts'; -export const help = (message: DiscordenoMessage) => { +export const helpSC: CreateGlobalApplicationCommand = { + name: 'help', + description: `Opens ${config.name}'s Help Library.`, +}; + +export const help = (msgOrInt: DiscordenoMessage | Interaction) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('help')).catch((e) => utils.commonLoggers.dbError('help.ts:15', 'call sproc INC_CNT on', e)); - message.send(generateHelpMessage()).catch((e: Error) => utils.commonLoggers.messageSendError('help.ts:16', message, e)); + utils.sendOrInteract(msgOrInt, 'help.ts:20', generateHelpMessage()); }; diff --git a/src/commands/info.ts b/src/commands/info.ts index 8663a5b..73ea28b 100644 --- a/src/commands/info.ts +++ b/src/commands/info.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; import config from '~config'; @@ -9,22 +9,25 @@ import { infoColor2 } from 'embeds/colors.ts'; import utils from 'utils/utils.ts'; -export const info = (message: DiscordenoMessage) => { +export const infoSC: CreateGlobalApplicationCommand = { + name: 'info', + description: 'Outputs some information about the bot and its developer.', +}; + +export const info = (msgOrInt: DiscordenoMessage | Interaction) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('info')).catch((e) => utils.commonLoggers.dbError('info.ts:12', 'call sproc INC_CNT on', e)); - message - .send({ - embeds: [ - { - color: infoColor2, - title: `${config.name}, a Discord bot that specializing in rolling dice and calculating math`, - description: `${config.name} is developed by Ean AKA Burn_E99. + utils.sendOrInteract(msgOrInt, 'info.ts:21', { + embeds: [ + { + color: infoColor2, + title: `${config.name}, a Discord bot that specializing in rolling dice and calculating math`, + description: `${config.name} is developed by Ean AKA Burn_E99. Additional information can be found on my website [here](${config.links.homePage}). Want to check out my source code? Check it out [here](${config.links.sourceCode}). Need help with this bot? Join my support server [here](${config.links.supportServer}).`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('info.ts:23', message, e)); + }, + ], + }); }; diff --git a/src/commands/privacy.ts b/src/commands/privacy.ts index 4bba656..7d84ed9 100644 --- a/src/commands/privacy.ts +++ b/src/commands/privacy.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; import config from '~config'; @@ -9,31 +9,34 @@ import { infoColor1 } from 'embeds/colors.ts'; import utils from 'utils/utils.ts'; -export const privacy = (message: DiscordenoMessage) => { +export const privacySC: CreateGlobalApplicationCommand = { + name: 'privacy', + description: 'Shows a summary of the Privacy Policy and Terms of Service, along with links to them.', +}; + +export const privacy = (msgOrInt: DiscordenoMessage | Interaction) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('privacy')).catch((e) => utils.commonLoggers.dbError('privacy.ts:15', 'call sproc INC_CNT on', e)); - message - .send({ - embeds: [ - { - color: infoColor1, - title: 'Privacy Policy', - fields: [ - { - name: `${config.name} does not track or collect user information via Discord.`, - value: - `The only user submitted information that is stored is submitted via the \`${config.prefix}report\` command. This information is only stored for a short period of time in a location that only the Developer of ${config.name} can see. + utils.sendOrInteract(msgOrInt, 'privacy.ts:21', { + embeds: [ + { + color: infoColor1, + title: 'Privacy Policy', + fields: [ + { + name: `${config.name} does not track or collect user information via Discord.`, + value: + `The only user submitted information that is stored is submitted via the \`${config.prefix}report\` command. This information is only stored for a short period of time in a location that only the Developer of ${config.name} can see. For more details, please check out the Privacy Policy on the GitHub [here](${config.links.privacyPolicy}). Terms of Service can also be found on GitHub [here](${config.links.termsOfService}). Want me to ignore you? Simply run \`${config.prefix}opt-out\` and ${config.name} will no longer read your messages or respond to you.`, - }, - ], - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('privacy.ts:33', message, e)); + }, + ], + }, + ], + }); }; diff --git a/src/commands/report.ts b/src/commands/report.ts index 18af181..7c05c67 100644 --- a/src/commands/report.ts +++ b/src/commands/report.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage, sendMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordApplicationCommandOptionTypes, DiscordenoMessage, Interaction, sendMessage } from '@discordeno'; import config from '~config'; @@ -8,9 +8,22 @@ import { queries } from 'db/common.ts'; import { failColor, infoColor2, successColor } from 'embeds/colors.ts'; import utils from 'utils/utils.ts'; -export const report = (message: DiscordenoMessage, args: string[]) => { +export const reportSC: CreateGlobalApplicationCommand = { + name: 'report', + description: 'Report an issue or send a feature request to the developer.', + options: [ + { + type: DiscordApplicationCommandOptionTypes.String, + name: 'report-text', + description: 'The issue or feature request.', + required: true, + }, + ], +}; + +export const report = (msgOrInt: DiscordenoMessage | Interaction, args: string[]) => { // Light telemetry to see how many times a command is being run - dbClient.execute(queries.callIncCnt('report')).catch((e) => utils.commonLoggers.dbError('report.ts:17', 'call sproc INC_CNT on', e)); + dbClient.execute(queries.callIncCnt('report')).catch((e) => utils.commonLoggers.dbError('report.ts:25', 'call sproc INC_CNT on', e)); if (args.join(' ')) { sendMessage(config.reportChannel, { @@ -21,29 +34,25 @@ export const report = (message: DiscordenoMessage, args: string[]) => { description: args.join(' ') || 'No message', }, ], - }).catch((e: Error) => utils.commonLoggers.messageSendError('report.ts:22', message, e)); - message - .send({ - embeds: [ - { - color: successColor, - title: 'Failed command has been reported to my developer.', - description: `For more in depth support, and information about planned maintenance, please join the support server [here](${config.links.supportServer}).`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('report.ts:29', message, e)); + }).catch((e: Error) => utils.commonLoggers.messageSendError('report.ts:36', msgOrInt, e)); + utils.sendOrInteract(msgOrInt, 'report.ts:37', { + embeds: [ + { + color: successColor, + title: 'Failed command has been reported to my developer.', + description: `For more in depth support, and information about planned maintenance, please join the support server [here](${config.links.supportServer}).`, + }, + ], + }); } else { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Please provide a short description of what failed', - description: 'Providing a short description helps my developer quickly diagnose what went wrong.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('report.ts:37', message, e)); + utils.sendOrInteract(msgOrInt, 'report.ts:48', { + embeds: [ + { + color: failColor, + title: 'Please provide a short description of what failed', + description: 'Providing a short description helps my developer quickly diagnose what went wrong.', + }, + ], + }); } }; diff --git a/src/commands/rip.ts b/src/commands/rip.ts index e0d69a0..227350a 100644 --- a/src/commands/rip.ts +++ b/src/commands/rip.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; import config from '~config'; @@ -9,20 +9,23 @@ import { infoColor2 } from 'embeds/colors.ts'; import utils from 'utils/utils.ts'; -export const rip = (message: DiscordenoMessage) => { +export const ripSC: CreateGlobalApplicationCommand = { + name: 'rest-in-peace', + description: 'A short message I wanted to include.', +}; + +export const rip = (msgOrInt: DiscordenoMessage | Interaction) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('rip')).catch((e) => utils.commonLoggers.dbError('rip.ts:14', 'call sproc INC_CNT on', e)); - message - .send({ - embeds: [ - { - color: infoColor2, - title: `${config.name} was built in memory of my Grandmother, Babka`, - description: 'With much love, Ean', - footer: { text: 'December 21, 2020' }, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('rip.ts:26', message, e)); + utils.sendOrInteract(msgOrInt, 'rip.ts:21', { + embeds: [ + { + color: infoColor2, + title: `${config.name} was built in memory of my Grandmother, Babka`, + description: 'With much love, Ean', + footer: { text: 'December 21, 2020' }, + }, + ], + }); }; diff --git a/src/commands/roll.ts b/src/commands/roll.ts index ddbbb3d..624adef 100644 --- a/src/commands/roll.ts +++ b/src/commands/roll.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordApplicationCommandOptionTypes, DiscordenoMessage, hasOwnProperty, Interaction } from '@discordeno'; import { log, LogTypes as LT } from '@Log4Deno'; import config from '~config'; @@ -14,7 +14,20 @@ import { queries } from 'db/common.ts'; import utils from 'utils/utils.ts'; -export const roll = async (message: DiscordenoMessage, args: string[], command: string) => { +export const rollSC: CreateGlobalApplicationCommand = { + name: 'roll', + description: 'Rolls dice and does math! For help, see the "Dice/Roll/Math Command" section in the /help library.', + options: [ + { + type: DiscordApplicationCommandOptionTypes.String, + name: 'roll-string', + description: 'The full roll string to execute.', + required: true, + }, + ], +}; + +export const roll = async (msgOrInt: DiscordenoMessage | Interaction, args: string[], command: string) => { // Light telemetry to see how many times a command is being run const currDateTime = new Date(); dbClient.execute(queries.callIncCnt('roll')).catch((e) => utils.commonLoggers.dbError('roll.ts:20', 'call sproc INC_CNT on', e)); @@ -31,7 +44,10 @@ export const roll = async (message: DiscordenoMessage, args: string[], command: originalCommand = `${config.prefix}${originalCommand.trim()}`; } - const m = await message.reply(rollingEmbed); + const m = await utils.sendOrInteract(msgOrInt, 'roll.ts:47', rollingEmbed, true); + if (!m) { + throw new Error("My message didn't send!"); + } // Get modifiers from command const [modifiers, remainingArgs] = getModifiers(args); @@ -41,7 +57,7 @@ export const roll = async (message: DiscordenoMessage, args: string[], command: m.edit(generateRollError('Modifiers invalid:', modifiers.error.name, modifiers.error.message)).catch((e) => utils.commonLoggers.messageEditError('roll.ts:50', m, e)); } - let rollCmd = message.content.startsWith(`${config.prefix}r`) ? remainingArgs.join('') : `${command}${remainingArgs.join('')}`; + let rollCmd = (hasOwnProperty(msgOrInt, 'token') ? args.join('') : msgOrInt.content).startsWith(`${config.prefix}r`) ? remainingArgs.join('') : `${command}${remainingArgs.join('')}`; // Try to ensure the roll is wrapped if (!rollCmd.includes(config.postfix)) { @@ -55,12 +71,16 @@ export const roll = async (message: DiscordenoMessage, args: string[], command: apiRoll: false, ddRoll: true, testRoll: false, - dd: { myResponse: m, originalMessage: message }, + dd: { + authorId: utils.getAuthorIdFromMessageOrInteraction(msgOrInt), + myResponse: m, + originalMessage: hasOwnProperty(msgOrInt, 'token') ? m : msgOrInt, + }, rollCmd, modifiers, originalCommand, }); } catch (e) { - log(LT.ERROR, `Unhandled Error: ${JSON.stringify(e)}`); + log(LT.ERROR, `Unhandled Roll Error: ${JSON.stringify(e)} | msgOrInt: ${JSON.stringify(msgOrInt)} | args: ${JSON.stringify(args)} | command: ${command}`); } }; diff --git a/src/commands/stats.ts b/src/commands/stats.ts index 0edf78e..c8678b5 100644 --- a/src/commands/stats.ts +++ b/src/commands/stats.ts @@ -1,4 +1,4 @@ -import { cache, cacheHandlers, DiscordenoMessage } from '@discordeno'; +import { cache, cacheHandlers, CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; import config from '~config'; @@ -10,12 +10,17 @@ import { compilingStats } from 'embeds/common.ts'; import utils from 'utils/utils.ts'; -export const stats = async (message: DiscordenoMessage) => { +export const statsSC: CreateGlobalApplicationCommand = { + name: 'stats', + description: 'Shows general statistics on how much the bot is being used.', +}; + +export const stats = async (msgOrInt: DiscordenoMessage | Interaction) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('stats')).catch((e) => utils.commonLoggers.dbError('stats.ts:14', 'call sproc INC_CNT on', e)); try { - const m = await message.send(compilingStats); + const m = await utils.sendOrInteract(msgOrInt, 'stats.ts:23', compilingStats, true); const startTime = new Date().getTime(); // Calculate how many times commands have been run @@ -36,7 +41,7 @@ export const stats = async (message: DiscordenoMessage) => { const endTime = new Date().getTime(); - m.edit({ + m?.edit({ embeds: [ { color: infoColor2, @@ -74,8 +79,8 @@ export const stats = async (message: DiscordenoMessage) => { }, }, ], - }).catch((e: Error) => utils.commonLoggers.messageEditError('stats.ts:38', m, e)); + }).catch((e: Error) => utils.commonLoggers.messageEditError('stats.ts:82', m, e)); } catch (e) { - utils.commonLoggers.messageSendError('stats.ts:41', message, e as Error); + utils.commonLoggers.messageSendError('stats.ts:84', msgOrInt, e as Error); } }; diff --git a/src/commands/toggleInline.ts b/src/commands/toggleInline.ts index e5f72f4..126a952 100644 --- a/src/commands/toggleInline.ts +++ b/src/commands/toggleInline.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage, hasGuildPermissions } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordApplicationCommandOptionTypes, DiscordenoMessage, hasGuildPermissions, Interaction } from '@discordeno'; import config from '~config'; @@ -11,73 +11,100 @@ import { failColor, infoColor1, successColor } from 'embeds/colors.ts'; import utils from 'utils/utils.ts'; -export const toggleInline = async (message: DiscordenoMessage, args: string[]) => { +export const toggleInlineSC: CreateGlobalApplicationCommand = { + name: 'toggle-inline-rolls', + description: 'Enable or disable inline rolling for this guild.', + options: [ + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'enable', + description: 'Enables/Allows inline rolling in this guild.', + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'disable', + description: 'Disables/Blocks inline rolling in this guild.', + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'status', + description: 'Gets the current status of inline rolling for this guild.', + }, + { + type: DiscordApplicationCommandOptionTypes.SubCommand, + name: 'help', + description: 'Opens the help library to the Toggle Inline help page.', + }, + ], +}; + +export const toggleInline = async (msgOrInt: DiscordenoMessage | Interaction, args: string[]) => { // Light telemetry to see how many times a command is being run dbClient.execute(queries.callIncCnt('inline')).catch((e) => utils.commonLoggers.dbError('toggleInline.ts:16', 'call sproc INC_CNT on', e)); // Local apiArg in lowercase const apiArg = (args[0] || '').toLowerCase(); + const guildId = BigInt(msgOrInt.guildId ?? '0'); + // Alert users who DM the bot that this command is for guilds only - if (message.guildId === 0n) { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Toggle Inline commands are only available in guilds.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('toggleInline.ts:30', message, e)); + if (guildId === 0n) { + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:45', { + embeds: [ + { + color: failColor, + title: 'Toggle Inline commands are only available in guilds.', + }, + ], + }); return; } let errorOut = false; - const guildQuery = await dbClient.query(`SELECT guildid FROM allow_inline WHERE guildid = ?`, [message.guildId]).catch((e0) => { + const guildQuery = await dbClient.query(`SELECT guildid FROM allow_inline WHERE guildid = ?`, [guildId]).catch((e0) => { utils.commonLoggers.dbError('toggleInline.ts:36', 'query', e0); - message - .send({ - embeds: [ - { - color: failColor, - title: 'Failed to check Inline roll status for this guild.', - description: 'If this issue persists, please report this to the developers.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('toggleInline.ts:47', message, e)); + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:59', { + embeds: [ + { + color: failColor, + title: 'Failed to check Inline roll status for this guild.', + description: 'If this issue persists, please report this to the developers.', + }, + ], + }); errorOut = true; }); if (errorOut) return; - if (await hasGuildPermissions(message.guildId, message.authorId, ['ADMINISTRATOR'])) { + if (await hasGuildPermissions(guildId, utils.getAuthorIdFromMessageOrInteraction(msgOrInt), ['ADMINISTRATOR'])) { let enable = false; switch (apiArg) { case 'allow': case 'enable': enable = true; - await dbClient.execute('INSERT INTO allow_inline(guildid) values(?)', [message.guildId]).catch((e) => { - utils.commonLoggers.dbError('toggleInline.ts:58', 'insert into allow_inline', e); - errorOut = true; - }); - if (!errorOut) { - inlineList.push(message.guildId); + if (!inlineList.includes(guildId)) { + await dbClient.execute('INSERT INTO allow_inline(guildid) values(?)', [guildId]).catch((e) => { + utils.commonLoggers.dbError('toggleInline.ts:58', 'insert into allow_inline', e); + errorOut = true; + }); + if (!errorOut) { + inlineList.push(guildId); + } } break; case 'block': case 'disable': case 'delete': - await dbClient.execute('DELETE FROM allow_inline WHERE guildid = ?', [message.guildId]).catch((e) => { + await dbClient.execute('DELETE FROM allow_inline WHERE guildid = ?', [guildId]).catch((e) => { utils.commonLoggers.dbError('toggleInline.ts:65', 'delete from allow_inline', e); errorOut = true; }); - if (!errorOut && inlineList.indexOf(message.guildId) !== -1) { - inlineList.splice(inlineList.indexOf(message.guildId), 1); + if (!errorOut && inlineList.includes(guildId)) { + inlineList.splice(inlineList.indexOf(guildId), 1); } break; case 'status': - message.send({ + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:98', { embeds: [ { color: infoColor1, @@ -90,11 +117,11 @@ export const toggleInline = async (message: DiscordenoMessage, args: string[]) = case 'h': case 'help': default: - message.send(generateHelpMessage('inline')).catch((e: Error) => utils.commonLoggers.messageSendError('apiHelp.ts:67', message, e)); + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:113', generateHelpMessage('inline')); return; } if (errorOut) { - message.send({ + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:117', { embeds: [ { color: failColor, @@ -105,7 +132,7 @@ export const toggleInline = async (message: DiscordenoMessage, args: string[]) = }); return; } - message.send({ + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:128', { embeds: [ { color: successColor, @@ -114,15 +141,13 @@ export const toggleInline = async (message: DiscordenoMessage, args: string[]) = ], }); } else { - message - .send({ - embeds: [ - { - color: failColor, - title: 'Toggle Inline commands are powerful and can only be used by guild Owners and Admins.', - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('toggleInline.ts:77', message, e)); + utils.sendOrInteract(msgOrInt, 'toggleInline.ts:137', { + embeds: [ + { + color: failColor, + title: 'Toggle Inline commands are powerful and can only be used by guild Owners and Admins.', + }, + ], + }); } }; diff --git a/src/commands/version.ts b/src/commands/version.ts index cfe9858..72ee14f 100644 --- a/src/commands/version.ts +++ b/src/commands/version.ts @@ -1,4 +1,4 @@ -import { DiscordenoMessage } from '@discordeno'; +import { CreateGlobalApplicationCommand, DiscordenoMessage, Interaction } from '@discordeno'; import config from '~config'; @@ -9,18 +9,21 @@ import { infoColor1 } from 'embeds/colors.ts'; import utils from 'utils/utils.ts'; -export const version = (message: DiscordenoMessage) => { - // Light telemetry to see how many times a command is being run - dbClient.execute(queries.callIncCnt('version')).catch((e) => utils.commonLoggers.dbError('version.ts:15', 'call sproc INC_CNT on', e)); - - message - .send({ - embeds: [ - { - color: infoColor1, - title: `My current version is ${config.version}`, - }, - ], - }) - .catch((e: Error) => utils.commonLoggers.messageSendError('version.ts:24', message, e)); +export const versionSC: CreateGlobalApplicationCommand = { + name: 'version', + description: `Gets ${config.name}'s current version`, +}; + +export const version = (msgOrInt: DiscordenoMessage | Interaction) => { + // Light telemetry to see how many times a command is being run + dbClient.execute(queries.callIncCnt('version')).catch((e) => utils.commonLoggers.dbError('version.ts:14', 'call sproc INC_CNT on', e)); + + utils.sendOrInteract(msgOrInt, 'version.ts:16', { + embeds: [ + { + color: infoColor1, + title: `My current version is ${config.version}`, + }, + ], + }); }; diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 3af3ada..d87bcf2 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,4 +1,7 @@ import { + ApplicationCommandInteractionDataOptionString, + ApplicationCommandInteractionDataOptionSubCommand, + ApplicationCommandInteractionDataOptionSubCommandGroup, DiscordenoMessage, DiscordMessageComponentTypes, editMessage, @@ -15,6 +18,9 @@ import { log, LogTypes as LT } from '@Log4Deno'; import { repeatRollCustomId } from 'artigen/managers/handler/workerComplete.ts'; import { toggleWebView, webViewCustomId } from 'artigen/utils/embeds.ts'; +import { argSpacesSplitRegex } from 'artigen/utils/escape.ts'; + +import { commands, slashCommandDetails } from 'commands/_index.ts'; import { generateHelpMessage, helpCustomId } from 'commands/helpLibrary/generateHelpMessage.ts'; @@ -22,6 +28,8 @@ import { failColor } from 'embeds/colors.ts'; import { messageCreateHandler } from 'events/messageCreate.ts'; +import { SlashCommandInteractionWithGuildId } from 'src/mod.d.ts'; + import utils from 'utils/utils.ts'; export const InteractionValueSeparator = '\u205a'; @@ -76,33 +84,127 @@ export const interactionCreateHandler = async (interaction: Interaction) => { const ownerId = interaction.data.customId.split(InteractionValueSeparator)[1] ?? 'missingOwnerId'; const userInteractingId = interaction.member?.user.id ?? interaction.user?.id ?? 'missingUserId'; if (ownerId === userInteractingId) { - ackInteraction(interaction); const botMsg: DiscordenoMessage = await structures.createDiscordenoMessage(interaction.message); - const rollMsg: DiscordenoMessage = await getMessage( - BigInt(botMsg.messageReference?.channelId ?? '0'), - BigInt(botMsg.messageReference?.messageId ?? '0'), - ); - messageCreateHandler(rollMsg); - } else { - sendInteractionResponse(interaction.id, interaction.token, { - type: InteractionResponseTypes.ChannelMessageWithSource, - data: { - flags: MessageFlags.Empheral, - embeds: [ - { - color: failColor, - title: 'Not Allowed!', - description: 'Only the original user that requested this roll can repeat it.', - }, - ], - }, - }).catch((e) => utils.commonLoggers.messageSendError('interactionCreate.ts:96', interaction, e)); + if (botMsg && botMsg.messageReference) { + const rollMsg: DiscordenoMessage = await getMessage( + BigInt(botMsg.messageReference.channelId ?? '0'), + BigInt(botMsg.messageReference.messageId ?? '0'), + ); + if (!rollMsg.isBot) { + ackInteraction(interaction); + messageCreateHandler(rollMsg); + return; + } + } + + if (botMsg && botMsg.embeds.length) { + const rollEmbed = botMsg.embeds[0].description ?? ''; + const rollStrStartIdx = rollEmbed.indexOf('`') + 1; + const rollStr = rollEmbed.substring(rollStrStartIdx, rollEmbed.indexOf('`', rollStrStartIdx)); + commands.roll(interaction, rollStr.split(argSpacesSplitRegex), ''); + return; + } } + + sendInteractionResponse(interaction.id, interaction.token, { + type: InteractionResponseTypes.ChannelMessageWithSource, + data: { + flags: MessageFlags.Empheral, + embeds: [ + { + color: failColor, + title: 'Not Allowed!', + description: 'Only the original user that requested this roll can repeat it.', + }, + ], + }, + }).catch((e) => utils.commonLoggers.messageSendError('interactionCreate.ts:96', interaction, e)); return; } log(LT.WARN, `UNHANDLED COMPONENT!!! data: ${JSON.stringify(interaction.data)} | Full Interaction: ${JSON.stringify(interaction)}`); } else if (interaction.type === InteractionTypes.ApplicationCommand && interaction.data) { + switch (interaction.data.name) { + case slashCommandDetails.aliasSC.name: { + // Per the config defined in aliasCmd.ts, there should always be 3 layers to the nesting, with the third's options being the values for the command + // ex: alias => personal/guild => command => [...options] + // Joining them back into one array with spaces between each to match the way the text command works, and since 'alias' will have been shifted out of the array, we start the array with a single spacer + const argSpaces: string[] = [' ']; + const guildOrPersonalOpt = (interaction.data.options as ApplicationCommandInteractionDataOptionSubCommandGroup[])?.shift(); + if (!guildOrPersonalOpt) break; + if (guildOrPersonalOpt.name === 'guild') { + argSpaces.push('guild', ' '); + } + const commandOpt = (guildOrPersonalOpt.options as ApplicationCommandInteractionDataOptionSubCommand[])?.shift(); + if (!commandOpt) break; + argSpaces.push(commandOpt.name); + if (commandOpt.options?.length) { + argSpaces.push(' '); + for (const opt of commandOpt.options) { + argSpaces.push(...opt.value.toString().trim().split(argSpacesSplitRegex)); + argSpaces.push(' '); + } + } + const safeInteraction: SlashCommandInteractionWithGuildId = { + guildId: '0', + ...interaction, + }; + commands.alias(safeInteraction, argSpaces); + return; + } + case slashCommandDetails.heatmapSC.name: + commands.heatmap(interaction); + return; + case slashCommandDetails.helpSC.name: + commands.help(interaction); + return; + case slashCommandDetails.infoSC.name: + commands.info(interaction); + return; + case slashCommandDetails.privacySC.name: + commands.privacy(interaction); + return; + case slashCommandDetails.reportSC.name: { + const option = (interaction.data.options as ApplicationCommandInteractionDataOptionString[])?.shift(); + const text = option ? option.value : ''; + commands.report( + interaction, + text + .trim() + .split(' ') + .filter((x) => x), + ); + return; + } + case slashCommandDetails.ripSC.name: + commands.rip(interaction); + return; + case slashCommandDetails.rollSC.name: { + const option = (interaction.data.options as ApplicationCommandInteractionDataOptionString[])?.shift(); + const text = option ? option.value : ''; + commands.roll( + interaction, + text + .trim() + .split(argSpacesSplitRegex) + .filter((x) => x), + '', + ); + return; + } + case slashCommandDetails.statsSC.name: + commands.stats(interaction); + return; + case slashCommandDetails.toggleInlineSC.name: { + const option = (interaction.data.options as ApplicationCommandInteractionDataOptionSubCommand[])?.shift(); + const subCommand = option ? option.name : ''; + commands.toggleInline(interaction, [subCommand]); + return; + } + case slashCommandDetails.versionSC.name: + commands.version(interaction); + return; + } log(LT.WARN, `UNHANDLED APPLICATION COMMAND!!! data: ${JSON.stringify(interaction.data)} | Full Interaction: ${JSON.stringify(interaction)}`); } else { log(LT.WARN, `UNHANDLED INTERACTION!!! Missing data! ${JSON.stringify(interaction)} | Full Interaction: ${JSON.stringify(interaction)}`); diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 48edb1a..ee46d3e 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -3,9 +3,10 @@ import { log, LogTypes as LT } from '@Log4Deno'; import config from '~config'; -import commands from 'commands/_index.ts'; +import { commands } from 'commands/_index.ts'; import { ignoreList, inlineList } from 'db/common.ts'; +import { argSpacesSplitRegex } from 'artigen/utils/escape.ts'; export const messageCreateHandler = (message: DiscordenoMessage) => { // Ignore all other bots @@ -23,7 +24,14 @@ export const messageCreateHandler = (message: DiscordenoMessage) => { // Handle inline guilds if allowed if (inlineList.includes(message.guildId) && message.content.includes(config.prefix) && message.content.includes(config.prefix)) { - commands.roll(message, message.content.trim().split(/([ \n]+)/g), ''); + commands.roll( + message, + message.content + .trim() + .split(argSpacesSplitRegex) + .filter((x) => x), + '', + ); } // return as we are done handling this message return; @@ -40,7 +48,8 @@ export const messageCreateHandler = (message: DiscordenoMessage) => { const argSpaces = message.content .slice(sliceLength) .trim() - .split(/([ \n]+)/g); + .split(argSpacesSplitRegex) + .filter((x) => x); const command = args.shift()?.toLowerCase(); argSpaces.shift(); diff --git a/src/events/ready.ts b/src/events/ready.ts index b9d2914..6c62245 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -8,6 +8,7 @@ import { successColor } from 'embeds/colors.ts'; import intervals from 'utils/intervals.ts'; import utils from 'utils/utils.ts'; +import { announceSlashCommands } from 'commands/_index.ts'; export const readyHandler = () => { log(LT.INFO, `${config.name} Logged in!`); @@ -66,6 +67,7 @@ export const readyHandler = () => { LOCALMODE ? log(LT.INFO, 'updateListStatistics not running') : intervals.updateListStatistics(botId, cache.guilds.size + cache.dispatchedGuildIds.size); intervals.updateHourlyRates(); intervals.updateHeatmapPng(); + announceSlashCommands(); editBotStatus({ activities: [ { diff --git a/src/mod.d.ts b/src/mod.d.ts new file mode 100644 index 0000000..83ae528 --- /dev/null +++ b/src/mod.d.ts @@ -0,0 +1,5 @@ +import { SlashCommandInteraction } from '@discordeno'; + +export interface SlashCommandInteractionWithGuildId extends SlashCommandInteraction { + guildId: string; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 3089e02..6524982 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -4,7 +4,7 @@ * December 21, 2020 */ import { log, LogTypes as LT } from '@Log4Deno'; -import { DiscordenoMessage, Interaction } from '@discordeno'; +import { CreateMessage, DiscordenoMessage, getOriginalInteractionResponse, hasOwnProperty, Interaction, InteractionResponseTypes, sendInteractionResponse } from '@discordeno'; const genericLogger = (level: LT, message: string) => log(level, message); const messageGetError = (location: string, channelId: bigint | string, messageId: bigint | string, err: Error) => @@ -17,6 +17,35 @@ const messageDeleteError = (location: string, message: DiscordenoMessage | strin genericLogger(LT.ERROR, `${location} | Failed to delete message: ${JSON.stringify(message)} | Error: ${err.name} - ${err.message}`); const dbError = (location: string, type: string, err: Error) => genericLogger(LT.ERROR, `${location} | Failed to ${type} database | Error: ${err.name} - ${err.message}`); +const sendOrInteract = async ( + msgOrInt: DiscordenoMessage | Interaction, + callLocation: string, + payload: CreateMessage, + tryGetOriginal = false, +): Promise => { + let newMsg; + if (hasOwnProperty(msgOrInt, 'token')) { + const interaction = msgOrInt as Interaction; + await sendInteractionResponse(interaction.id, interaction.token, { + type: InteractionResponseTypes.ChannelMessageWithSource, + data: payload, + }).catch((e: Error) => messageSendError(callLocation, interaction, e)); + if (tryGetOriginal) newMsg = await getOriginalInteractionResponse(interaction.token); + } else { + newMsg = await msgOrInt.reply(payload).catch((e: Error) => messageSendError(callLocation, msgOrInt, e)); + } + return newMsg; +}; + +const getAuthorIdFromMessageOrInteraction = (msgOrInt: DiscordenoMessage | Interaction): bigint => { + if (hasOwnProperty(msgOrInt, 'token')) { + const interaction = msgOrInt as Interaction; + return BigInt(interaction.member?.user.id ?? interaction.user?.id ?? '0'); + } else { + return msgOrInt.authorId; + } +}; + export default { commonLoggers: { dbError, @@ -25,4 +54,6 @@ export default { messageGetError, messageSendError, }, + getAuthorIdFromMessageOrInteraction, + sendOrInteract, };