From e8b95a2f3149fab08ed3c927f771d8ee4fad9d04 Mon Sep 17 00:00:00 2001 From: Isaac Date: Sun, 25 Jun 2023 13:41:07 +0100 Subject: [PATCH] feat: improve error handling --- package.json | 5 +-- pnpm-lock.yaml | 38 ++++++++++++--------- src/buttons/edit.js | 2 +- src/lib/logging.js | 6 ++++ src/lib/tickets/manager.js | 3 +- src/listeners/autocomplete/error.js | 22 +++++++++++++ src/listeners/buttons/error.js | 5 +-- src/listeners/commands/error.js | 5 +-- src/listeners/menus/error.js | 51 +++++++++++++++++++++++++++++ src/listeners/modals/error.js | 51 +++++++++++++++++++++++++++++ 10 files changed, 165 insertions(+), 23 deletions(-) create mode 100644 src/listeners/autocomplete/error.js create mode 100644 src/listeners/menus/error.js create mode 100644 src/listeners/modals/error.js diff --git a/package.json b/package.json index 92cca4f..012a789 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@fastify/cookie": "^6.0.0", "@fastify/jwt": "^5.0.1", "@fastify/oauth2": "^5.1.0", - "@prisma/client": "^4.14.1", + "@prisma/client": "^4.16.1", "boxen": "^7.1.0", "cryptr": "^6.2.0", "discord.js": "^14.11.0", @@ -68,8 +68,9 @@ "node-dir": "^0.1.17", "node-emoji": "^1.11.0", "object-diffy": "^1.0.4", - "prisma": "^4.14.1", + "prisma": "^4.16.1", "semver": "^7.5.1", + "short-unique-id": "^4.4.4", "spacetime": "^7.4.4", "terminal-link": "^2.1.1", "yaml": "^1.10.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 512738a..489fb51 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,8 +23,8 @@ dependencies: specifier: ^5.1.0 version: 5.1.0 '@prisma/client': - specifier: ^4.14.1 - version: 4.15.0(prisma@4.15.0) + specifier: ^4.16.1 + version: 4.16.1(prisma@4.16.1) boxen: specifier: ^7.1.0 version: 7.1.0 @@ -71,11 +71,14 @@ dependencies: specifier: ^1.0.4 version: 1.0.4 prisma: - specifier: ^4.14.1 - version: 4.15.0 + specifier: ^4.16.1 + version: 4.16.1 semver: specifier: ^7.5.1 version: 7.5.1 + short-unique-id: + specifier: ^4.4.4 + version: 4.4.4 spacetime: specifier: ^7.4.4 version: 7.4.4 @@ -653,8 +656,8 @@ packages: fastq: 1.15.0 dev: true - /@prisma/client@4.15.0(prisma@4.15.0): - resolution: {integrity: sha512-xnROvyABcGiwqRNdrObHVZkD9EjkJYHOmVdlKy1yGgI+XOzvMzJ4tRg3dz1pUlsyhKxXGCnjIQjWW+2ur+YXuw==} + /@prisma/client@4.16.1(prisma@4.16.1): + resolution: {integrity: sha512-CoDHu7Bt+NuDo40ijoeHP79EHtECsPBTy3yte5Yo3op8TqXt/kV0OT5OrsWewKvQGKFMHhYQ+ePed3zzjYdGAw==} engines: {node: '>=14.17'} requiresBuild: true peerDependencies: @@ -663,16 +666,16 @@ packages: prisma: optional: true dependencies: - '@prisma/engines-version': 4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944 - prisma: 4.15.0 + '@prisma/engines-version': 4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c + prisma: 4.16.1 dev: false - /@prisma/engines-version@4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944: - resolution: {integrity: sha512-sVOig4tjGxxlYaFcXgE71f/rtFhzyYrfyfNFUsxCIEJyVKU9rdOWIlIwQ2NQ7PntvGnn+x0XuFo4OC1jvPJKzg==} + /@prisma/engines-version@4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c: + resolution: {integrity: sha512-tMWAF/qF00fbUH1HB4Yjmz6bjh7fzkb7Y3NRoUfMlHu6V+O45MGvqwYxqwBjn1BIUXkl3r04W351D4qdJjrgvA==} dev: false - /@prisma/engines@4.15.0: - resolution: {integrity: sha512-FTaOCGs0LL0OW68juZlGxFtYviZa4xdQj/rQEdat2txw0s3Vu/saAPKjNVXfIgUsGXmQ72HPgNr6935/P8FNAA==} + /@prisma/engines@4.16.1: + resolution: {integrity: sha512-gpZG0kGGxfemgvK/LghHdBIz+crHkZjzszja94xp4oytpsXrgt/Ice82MvPsWMleVIniKuARrowtsIsim0PFJQ==} requiresBuild: true dev: false @@ -3069,13 +3072,13 @@ packages: dev: true optional: true - /prisma@4.15.0: - resolution: {integrity: sha512-iKZZpobPl48gTcSZVawLMQ3lEy6BnXwtoMj7hluoGFYu2kQ6F9LBuBrUyF95zRVnNo8/3KzLXJXJ5TEnLSJFiA==} + /prisma@4.16.1: + resolution: {integrity: sha512-C2Xm7yxHxjFjjscBEW4tmoraPHH/Vyu/A0XABdbaFtoiOZARsxvOM7rwc2iZ0qVxbh0bGBGBWZUSXO/52/nHBQ==} engines: {node: '>=14.17'} hasBin: true requiresBuild: true dependencies: - '@prisma/engines': 4.15.0 + '@prisma/engines': 4.16.1 dev: false /process-nextick-args@2.0.1: @@ -3390,6 +3393,11 @@ packages: engines: {node: '>=8'} dev: true + /short-unique-id@4.4.4: + resolution: {integrity: sha512-oLF1NCmtbiTWl2SqdXZQbo5KM1b7axdp0RgQLq8qCBBLoq+o3A5wmLrNM6bZIh54/a8BJ3l69kTXuxwZ+XCYuw==} + hasBin: true + dev: false + /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true diff --git a/src/buttons/edit.js b/src/buttons/edit.js index 96e1764..510bc10 100644 --- a/src/buttons/edit.js +++ b/src/buttons/edit.js @@ -108,4 +108,4 @@ module.exports = class EditButton extends Button { ); } } -}; \ No newline at end of file +}; diff --git a/src/lib/logging.js b/src/lib/logging.js index 5b24f86..52a078b 100644 --- a/src/lib/logging.js +++ b/src/lib/logging.js @@ -3,6 +3,11 @@ const { EmbedBuilder, } = require('discord.js'); const { diff: getDiff } = require('object-diffy'); +const ShortUniqueId = require('short-unique-id'); + +const uid = new ShortUniqueId(); + +const getSUID = () => uid.stamp(10); const uuidRegex = /[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}/g; @@ -235,6 +240,7 @@ async function logMessageEvent(client, { module.exports = { getLogChannel, + getSUID, logAdminEvent, logMessageEvent, logTicketEvent, diff --git a/src/lib/tickets/manager.js b/src/lib/tickets/manager.js index 0983379..e448891 100644 --- a/src/lib/tickets/manager.js +++ b/src/lib/tickets/manager.js @@ -28,6 +28,7 @@ const { decrypt, encrypt, } = new Cryptr(process.env.ENCRYPTION_KEY); +const { getSUID } = require('../logging'); /** * @typedef {import('@prisma/client').Category & @@ -682,7 +683,7 @@ module.exports = class TicketManager { userId: interaction.user.id, }); } catch (error) { - const ref = require('crypto').randomUUID(); + const ref = getSUID(); this.client.log.warn.tickets('An error occurred whilst creating ticket', channel.id); this.client.log.error.tickets(ref); this.client.log.error.tickets(error); diff --git a/src/listeners/autocomplete/error.js b/src/listeners/autocomplete/error.js new file mode 100644 index 0000000..c38aa0d --- /dev/null +++ b/src/listeners/autocomplete/error.js @@ -0,0 +1,22 @@ +const { Listener } = require('@eartharoid/dbf'); + +module.exports = class extends Listener { + constructor(client, options) { + super(client, { + ...options, + emitter: client.autocomplete, + event: 'error', + }); + } + + async run({ + completer, + error, + interaction, + }) { + this.client.log.error.autocomplete(`"${completer.id}" autocomplete execution error:`, { + error, + interaction, + }); + } +}; diff --git a/src/listeners/buttons/error.js b/src/listeners/buttons/error.js index d1f86d3..95f4ebf 100644 --- a/src/listeners/buttons/error.js +++ b/src/listeners/buttons/error.js @@ -3,6 +3,7 @@ const { EmbedBuilder, codeBlock, } = require('discord.js'); +const { getSUID } = require('../../lib/logging'); module.exports = class extends Listener { constructor(client, options) { @@ -18,7 +19,7 @@ module.exports = class extends Listener { error, interaction, }) { - const ref = require('crypto').randomUUID(); + const ref = getSUID(); this.client.log.error.buttons(ref); this.client.log.error.buttons(`"${button.id}" button execution error:`, error); let locale = null; @@ -39,7 +40,7 @@ module.exports = class extends Listener { .addFields([ { name: getMessage('misc.error.fields.identifier'), - value: codeBlock(ref), + value: codeBlock(' ' + ref + ' '), }, ]), ], diff --git a/src/listeners/commands/error.js b/src/listeners/commands/error.js index 3baccd9..79b6eab 100644 --- a/src/listeners/commands/error.js +++ b/src/listeners/commands/error.js @@ -3,6 +3,7 @@ const { EmbedBuilder, codeBlock, } = require('discord.js'); +const { getSUID } = require('../../lib/logging'); module.exports = class extends Listener { constructor(client, options) { @@ -18,7 +19,7 @@ module.exports = class extends Listener { error, interaction, }) { - const ref = require('crypto').randomUUID(); + const ref = getSUID(); this.client.log.error.commands(ref); this.client.log.error.commands(`"${command.name}" command execution error:`, error); let locale = null; @@ -39,7 +40,7 @@ module.exports = class extends Listener { .addFields([ { name: getMessage('misc.error.fields.identifier'), - value: codeBlock(ref), + value: codeBlock(' ' + ref + ' '), }, ]), ], diff --git a/src/listeners/menus/error.js b/src/listeners/menus/error.js new file mode 100644 index 0000000..586322c --- /dev/null +++ b/src/listeners/menus/error.js @@ -0,0 +1,51 @@ +const { Listener } = require('@eartharoid/dbf'); +const { + EmbedBuilder, + codeBlock, +} = require('discord.js'); +const { getSUID } = require('../../lib/logging'); + +module.exports = class extends Listener { + constructor(client, options) { + super(client, { + ...options, + emitter: client.menus, + event: 'error', + }); + } + + async run({ + menu, + error, + interaction, + }) { + const ref = getSUID(); + this.client.log.error.menus(ref); + this.client.log.error.menus(`"${menu.id}" menu execution error:`, error); + let locale = null; + if (interaction.guild) { + locale = (await this.client.prisma.guild.findUnique({ + select: { locale: true }, + where: { id: interaction.guild.id }, + })).locale; + } + const getMessage = this.client.i18n.getLocale(locale); + const data = { + components: [], + embeds: [ + new EmbedBuilder() + .setColor('Orange') + .setTitle(getMessage('misc.error.title')) + .setDescription(getMessage('misc.error.description')) + .addFields([ + { + name: getMessage('misc.error.fields.identifier'), + value: codeBlock(' ' + ref + ' '), + }, + ]), + ], + }; + + interaction.reply(data).catch(() => interaction.editReply(data)); + } +}; diff --git a/src/listeners/modals/error.js b/src/listeners/modals/error.js new file mode 100644 index 0000000..548a633 --- /dev/null +++ b/src/listeners/modals/error.js @@ -0,0 +1,51 @@ +const { Listener } = require('@eartharoid/dbf'); +const { + EmbedBuilder, + codeBlock, +} = require('discord.js'); +const { getSUID } = require('../../lib/logging'); + +module.exports = class extends Listener { + constructor(client, options) { + super(client, { + ...options, + emitter: client.modals, + event: 'error', + }); + } + + async run({ + modal, + error, + interaction, + }) { + const ref = getSUID(); + this.client.log.error.modals(ref); + this.client.log.error.modals(`"${modal.id}" modal execution error:`, error); + let locale = null; + if (interaction.guild) { + locale = (await this.client.prisma.guild.findUnique({ + select: { locale: true }, + where: { id: interaction.guild.id }, + })).locale; + } + const getMessage = this.client.i18n.getLocale(locale); + const data = { + components: [], + embeds: [ + new EmbedBuilder() + .setColor('Orange') + .setTitle(getMessage('misc.error.title')) + .setDescription(getMessage('misc.error.description')) + .addFields([ + { + name: getMessage('misc.error.fields.identifier'), + value: codeBlock(' ' + ref + ' '), + }, + ]), + ], + }; + + interaction.reply(data).catch(() => interaction.editReply(data)); + } +};