diff --git a/src/commands/dev/sentry.js b/src/commands/dev/sentry.js index 0b9a350..d9e659e 100644 --- a/src/commands/dev/sentry.js +++ b/src/commands/dev/sentry.js @@ -8,6 +8,13 @@ module.exports = { name: "sentry", description: "Manage Sentry", options: [ + { + type: 1, + name: "capture-tokens", + description: "[DEVELOPER ONLY] Get a list of all the active capture tokens.", + options: [] + }, + { type: 1, name: "deregister", @@ -64,6 +71,33 @@ module.exports = { return; } + if(interaction.options.getSubcommand() === "capture-tokens") { + const data = await sentrySchema.find(); + + const tokens = []; + + for(const token of data) { + tokens.push(`- ${token._id}`); + } + + if(!tokens.length) { + const error = new Discord.EmbedBuilder() + .setColor(client.config_embeds.error) + .setDescription(`${emoji.error} There are no tokens!`) + + await interaction.editReply({ embeds: [error], ephemeral: true }); + return; + } + + const tokenInfo = new Discord.EmbedBuilder() + .setColor(client.config_embeds.default) + .setTitle("🔑 Tokens") + .setDescription(tokens.join("\n")) + + await interaction.editReply({ embeds: [tokenInfo] }); + return; + } + if(interaction.options.getSubcommand() === "deregister") { const token = interaction.options.getString("token"); @@ -139,7 +173,7 @@ module.exports = { .setStyle(Discord.ButtonStyle.Secondary) .setCustomId(`sentry-capture-${id}`) .setEmoji("ℹī¸") - .setLabel("Capture Details") + .setLabel("Details") ) await interaction.editReply({ embeds: [registered], components: [actions] }); diff --git a/src/sentry-api/assets/sentry-glyph-light-1000x917.png b/src/sentry-api/assets/sentry-glyph-light-1000x917.png deleted file mode 100644 index 8ba24b1..0000000 Binary files a/src/sentry-api/assets/sentry-glyph-light-1000x917.png and /dev/null differ diff --git a/src/sentry-api/assets/sentry-glyph-light-400x367.png b/src/sentry-api/assets/sentry-glyph-light-400x367.png new file mode 100644 index 0000000..b18c2e6 Binary files /dev/null and b/src/sentry-api/assets/sentry-glyph-light-400x367.png differ diff --git a/src/sentry-api/endpoints/post.js b/src/sentry-api/endpoints/post.js index 39ef142..69d6411 100644 --- a/src/sentry-api/endpoints/post.js +++ b/src/sentry-api/endpoints/post.js @@ -14,8 +14,9 @@ module.exports = async (req, res, client) => { const event = req.body; const embed = new Discord.EmbedBuilder() - .setThumbnail("attachment://sentry-glyph-light-1000x917.png") - .setFooter({ text: event.project_name }) + .setAuthor({ name: event.project_name, iconURL: "attachment://sentry-glyph-light-400x367.png", url: parser.getProjectLink(event) }) + + const logo = new Discord.AttachmentBuilder("src/sentry-api/assets/sentry-glyph-light-400x367.png", { name: "sentry-glyph-light-400x367.png" }); const projectName = parser.getProject(event); const eventTitle = parser.getTitle(event); @@ -29,9 +30,7 @@ module.exports = async (req, res, client) => { const link = parser.getLink(event); - if(link.startsWith("https://") || link.startsWith("http://")) { - embed.setURL(parser.getLink(event)); - } + if(link.startsWith("https://") || link.startsWith("http://")) embed.setURL(parser.getLink(event)); embed.setTimestamp(parser.getTime(event)); embed.setColor(getColor(parser.getLevel(event))); @@ -59,7 +58,7 @@ module.exports = async (req, res, client) => { if(location?.length > 0) { fields.push({ name: "Stack", - value: `\`\`\`${cap(location.join("\n"), 1000)}\n\`\`\``, + value: `\`\`\`${cap(location.join("\n"), 1000)}\n\`\`\`` }); } @@ -68,10 +67,8 @@ module.exports = async (req, res, client) => { if(user?.username) { fields.push({ name: "User", - value: cap( - `${user.username} ${user.id ? `(${user.id})` : ""}`, - 1024 - ), + value: cap(`${user.username} ${user.id ? `(${user.id})` : ""}`, 1024), + inline: true }); } @@ -80,10 +77,8 @@ module.exports = async (req, res, client) => { if(Object.keys(tags).length > 0) { fields.push({ name: "Tags", - value: cap( - tags.map(([key, value]) => `**${key}**: ${value}`).join("\n"), - 1024 - ), + value: cap(tags.map(([key, value]) => `**${key}**: ${value}`).join("\n"), 1024), + inline: true }); } @@ -93,6 +88,7 @@ module.exports = async (req, res, client) => { fields.push({ name: "Extras", value: cap(extras.join("\n"), 1024), + inline: true }); } @@ -102,6 +98,7 @@ module.exports = async (req, res, client) => { fields.push({ name: "Contexts", value: cap(contexts.join("\n"), 1024), + inline: true }); } @@ -111,6 +108,7 @@ module.exports = async (req, res, client) => { fields.push({ name: "Release", value: cap(release, 1024), + inline: true }); } @@ -139,9 +137,7 @@ module.exports = async (req, res, client) => { const channel = client.channels.cache.get(data.channel); - const image = new Discord.AttachmentBuilder("src/sentry-api/assets/sentry-glyph-light-1000x917.png") - - channel.send({ embeds: [embed], components: [actions], files: [image] }); + channel.send({ embeds: [embed], components: [actions], files: [logo] }); res.status(200).json({ "message": "The event has been received.", "code": "EVENT_RECEIVED" }); } diff --git a/src/util/sentry/parser.js b/src/util/sentry/parser.js index beafe90..35a2f18 100644 --- a/src/util/sentry/parser.js +++ b/src/util/sentry/parser.js @@ -1,21 +1,5 @@ // https://github.com/IanMitchell/sentrydiscord.dev/blob/867b889e15c6b101d619610d07b4663c6a73fe6a/lib/message.ts -module.exports.getEvent = function (issue) { - return issue?.event ?? issue?.data?.issue ?? issue; -} - -module.exports.getProject = function (issue) { - return issue?.project?.project_name ?? this.getEvent(issue)?.project?.name; -} - -module.exports.getPlatform = function (issue) { - return this.getEvent(issue)?.platform; -} - -module.exports.getLanguage = function (issue) { - return this.getEvent(issue)?.location?.split(".")?.slice(-1)?.[0] || ""; -} - module.exports.getContexts = function (issue) { const contexts = this.getEvent(issue)?.contexts ?? {}; @@ -26,6 +10,40 @@ module.exports.getContexts = function (issue) { return values ?? []; } +module.exports.getErrorCodeSnippet = function (issue) { + const stacktrace = this.getStacktrace(issue); + const location = stacktrace?.frames?.reverse()?.[0]; + + if(!location) return this.getEvent(issue)?.culprit ?? null; + + return ` ${location.pre_context?.join("\n ") ?? ""}\n>${ + location.context_line + }\n${location.post_context?.join("\n") ?? ""}`; +} + +module.exports.getErrorLocation = function (issue, maxLines = Infinity) { + const stacktrace = this.getStacktrace(issue); + const locations = stacktrace?.frames; + + let files = locations?.map( + (location) => + `${location?.filename}, ${location?.lineno ?? "?"}:${ + location?.colno ?? "?" + }` + ); + + if(maxLines < Infinity && files?.length > maxLines) { + files = files.slice(0, maxLines); + files.push("..."); + } + + return files; +} + +module.exports.getEvent = function (issue) { + return issue?.event ?? issue?.data?.issue ?? issue; +} + module.exports.getExtras = function (issue) { const extras = this.getEvent(issue)?.extra ?? {}; @@ -36,47 +54,47 @@ module.exports.getExtras = function (issue) { return values ?? []; } -module.exports.getLink = function (issue) { - return issue?.url ?? "https://sentry.io"; +module.exports.getFileLocation = function (issue) { + return this.getEvent(issue)?.location; } -module.exports.getTags = function (issue) { - return this.getEvent(issue)?.tags ?? []; +module.exports.getLanguage = function (issue) { + return this.getEvent(issue)?.location?.split(".")?.slice(-1)?.[0] || ""; } module.exports.getLevel = function (issue) { return this.getEvent(issue)?.level; } -module.exports.getType = function (issue) { - return this.getEvent(issue)?.type; +module.exports.getLink = function (issue) { + return issue?.url ?? "https://sentry.io"; } -module.exports.getTitle = function (issue) { - return this.getEvent(issue)?.title ?? "Sentry Event"; +module.exports.getMessage = function (issue) { + return issue?.message; } -module.exports.getTime = function (issue) { - const event = this.getEvent(issue); - - if(event?.timestamp) return new Date(event?.timestamp * 1000); - if(event?.lastSeen != null) return new Date(event?.lastSeen); +module.exports.getOrganisation = function (url) { + const regex = /https:\/\/([\w-]+)\.sentry\.io/; + const match = url.match(regex); - if(event?.firstSeen != null) return new Date(event?.firstSeen); + return match[1] ?? null; +} - return new Date(); +module.exports.getPlatform = function (issue) { + return this.getEvent(issue)?.platform; } -module.exports.getRelease = function (issue) { - return this.getEvent(issue)?.release; +module.exports.getProject = function (issue) { + return issue?.project?.project_name ?? this.getEvent(issue)?.project?.name; } -module.exports.getUser = function (issue) { - return this.getEvent(issue)?.user; +module.exports.getProjectLink = function (issue) { + return `https://${this.getOrganisation(this.getLink(issue))}.sentry.io/projects/${issue.project_slug}`; } -module.exports.getFileLocation = function (issue) { - return this.getEvent(issue)?.location; +module.exports.getRelease = function (issue) { + return this.getEvent(issue)?.release; } module.exports.getStacktrace = function (issue) { @@ -86,39 +104,29 @@ module.exports.getStacktrace = function (issue) { ); } -module.exports.getErrorLocation = function (issue, maxLines = Infinity) { - const stacktrace = this.getStacktrace(issue); - const locations = stacktrace?.frames; +module.exports.getTags = function (issue) { + return this.getEvent(issue)?.tags ?? []; +} - let files = locations?.map( - (location) => - `${location?.filename}, ${location?.lineno ?? "?"}:${ - location?.colno ?? "?" - }` - ); +module.exports.getTime = function (issue) { + const event = this.getEvent(issue); - if(maxLines < Infinity && files?.length > maxLines) { - files = files.slice(0, maxLines); - files.push("..."); - } + if(event?.timestamp) return new Date(event?.timestamp * 1000); + if(event?.lastSeen != null) return new Date(event?.lastSeen); - return files; -} + if(event?.firstSeen != null) return new Date(event?.firstSeen); -module.exports.getErrorCodeSnippet = function (issue) { - const stacktrace = this.getStacktrace(issue); - const location = stacktrace?.frames?.reverse()?.[0]; + return new Date(); +} - if (!location) { - const event = this.getEvent(issue); - return event?.culprit ?? null; - } +module.exports.getTitle = function (issue) { + return this.getEvent(issue)?.title ?? "Sentry Event"; +} - return ` ${location.pre_context?.join("\n ") ?? ""}\n>${ - location.context_line - }\n${location.post_context?.join("\n") ?? ""}`; +module.exports.getType = function (issue) { + return this.getEvent(issue)?.type; } -module.exports.getMessage = function (issue) { - return issue?.message; +module.exports.getUser = function (issue) { + return this.getEvent(issue)?.user; }