From bacadccaa93be444ff607204e4df1754ec902e98 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 26 Nov 2025 02:39:01 -0500 Subject: [PATCH] refactor: improve error handling in notification components - Enhanced error messages in HandleNotifications and notificationRouter to provide more specific feedback. - Updated email and Discord notification functions to throw detailed errors on failure. - Ensured consistent error handling across notification utilities for better debugging. --- .../notifications/handle-notifications.tsx | 6 +- .../server/api/routers/notification.ts | 6 +- .../src/utils/notifications/build-error.ts | 524 ++++++++-------- .../src/utils/notifications/build-success.ts | 547 ++++++++--------- .../utils/notifications/database-backup.ts | 571 +++++++++--------- .../src/utils/notifications/docker-cleanup.ts | 329 +++++----- .../utils/notifications/dokploy-restart.ts | 69 +-- .../server/src/utils/notifications/utils.ts | 43 +- 8 files changed, 1061 insertions(+), 1034 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index e5fee3a9d..337cdfd2b 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -1261,8 +1261,10 @@ export const HandleNotifications = ({ notificationId }: Props) => { }); } toast.success("Connection Success"); - } catch { - toast.error("Error testing the provider"); + } catch (error) { + toast.error( + `Error testing the provider ${error instanceof Error ? error.message : "Unknown error"}`, + ); } }} > diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index 56748dc98..c483b813e 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -111,7 +111,7 @@ export const notificationRouter = createTRPCRouter({ } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", - message: "Error testing the notification", + message: `${error instanceof Error ? error.message : "Unknown error"}`, cause: error, }); } @@ -228,7 +228,7 @@ export const notificationRouter = createTRPCRouter({ } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", - message: "Error testing the notification", + message: `${error instanceof Error ? error.message : "Unknown error"}`, cause: error, }); } @@ -285,7 +285,7 @@ export const notificationRouter = createTRPCRouter({ } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", - message: "Error testing the notification", + message: `${error instanceof Error ? error.message : "Unknown error"}`, cause: error, }); } diff --git a/packages/server/src/utils/notifications/build-error.ts b/packages/server/src/utils/notifications/build-error.ts index 67c568b72..3ee983031 100644 --- a/packages/server/src/utils/notifications/build-error.ts +++ b/packages/server/src/utils/notifications/build-error.ts @@ -7,8 +7,8 @@ import { and, eq } from "drizzle-orm"; import { sendDiscordNotification, sendEmailNotification, - sendLarkNotification, sendGotifyNotification, + sendLarkNotification, sendNtfyNotification, sendSlackNotification, sendTelegramNotification, @@ -52,279 +52,287 @@ export const sendBuildErrorNotifications = async ({ for (const notification of notificationList) { const { email, discord, telegram, slack, gotify, ntfy, lark } = notification; - if (email) { - const template = await renderAsync( - BuildFailedEmail({ - projectName, - applicationName, - applicationType, - errorMessage: errorMessage, - buildLink, - date: date.toLocaleString(), - }), - ).catch(); - await sendEmailNotification(email, "Build failed for dokploy", template); - } + try { + if (email) { + const template = await renderAsync( + BuildFailedEmail({ + projectName, + applicationName, + applicationType, + errorMessage: errorMessage, + buildLink, + date: date.toLocaleString(), + }), + ).catch(); + await sendEmailNotification( + email, + "Build failed for dokploy", + template, + ); + } - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); - const limitCharacter = 800; - const truncatedErrorMessage = errorMessage.substring(0, limitCharacter); - await sendDiscordNotification(discord, { - title: decorate(">", "`⚠️` Build Failed"), - color: 0xed4245, - fields: [ - { - name: decorate("`🛠️`", "Project"), - value: projectName, - inline: true, + const limitCharacter = 800; + const truncatedErrorMessage = errorMessage.substring(0, limitCharacter); + await sendDiscordNotification(discord, { + title: decorate(">", "`⚠️` Build Failed"), + color: 0xed4245, + fields: [ + { + name: decorate("`🛠️`", "Project"), + value: projectName, + inline: true, + }, + { + name: decorate("`⚙️`", "Application"), + value: applicationName, + inline: true, + }, + { + name: decorate("`❔`", "Type"), + value: applicationType, + inline: true, + }, + { + name: decorate("`📅`", "Date"), + value: ``, + inline: true, + }, + { + name: decorate("`⌚`", "Time"), + value: ``, + inline: true, + }, + { + name: decorate("`❓`", "Type"), + value: "Failed", + inline: true, + }, + { + name: decorate("`⚠️`", "Error Message"), + value: `\`\`\`${truncatedErrorMessage}\`\`\``, + }, + { + name: decorate("`🧷`", "Build Link"), + value: `[Click here to access build link](${buildLink})`, + }, + ], + timestamp: date.toISOString(), + footer: { + text: "Dokploy Build Notification", }, - { - name: decorate("`⚙️`", "Application"), - value: applicationName, - inline: true, - }, - { - name: decorate("`❔`", "Type"), - value: applicationType, - inline: true, - }, - { - name: decorate("`📅`", "Date"), - value: ``, - inline: true, - }, - { - name: decorate("`⌚`", "Time"), - value: ``, - inline: true, - }, - { - name: decorate("`❓`", "Type"), - value: "Failed", - inline: true, - }, - { - name: decorate("`⚠️`", "Error Message"), - value: `\`\`\`${truncatedErrorMessage}\`\`\``, - }, - { - name: decorate("`🧷`", "Build Link"), - value: `[Click here to access build link](${buildLink})`, - }, - ], - timestamp: date.toISOString(), - footer: { - text: "Dokploy Build Notification", - }, - }); - } + }); + } - if (gotify) { - const decorate = (decoration: string, text: string) => - `${gotify.decoration ? decoration : ""} ${text}\n`; - await sendGotifyNotification( - gotify, - decorate("⚠️", "Build Failed"), - `${decorate("🛠️", `Project: ${projectName}`)}` + - `${decorate("⚙️", `Application: ${applicationName}`)}` + - `${decorate("❔", `Type: ${applicationType}`)}` + - `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + - `${decorate("⚠️", `Error:\n${errorMessage}`)}` + - `${decorate("🔗", `Build details:\n${buildLink}`)}`, - ); - } + if (gotify) { + const decorate = (decoration: string, text: string) => + `${gotify.decoration ? decoration : ""} ${text}\n`; + await sendGotifyNotification( + gotify, + decorate("⚠️", "Build Failed"), + `${decorate("🛠️", `Project: ${projectName}`)}` + + `${decorate("⚙️", `Application: ${applicationName}`)}` + + `${decorate("❔", `Type: ${applicationType}`)}` + + `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + + `${decorate("⚠️", `Error:\n${errorMessage}`)}` + + `${decorate("🔗", `Build details:\n${buildLink}`)}`, + ); + } - if (ntfy) { - await sendNtfyNotification( - ntfy, - "Build Failed", - "warning", - `view, Build details, ${buildLink}, clear=true;`, - `🛠️Project: ${projectName}\n` + - `⚙️Application: ${applicationName}\n` + - `❔Type: ${applicationType}\n` + - `🕒Date: ${date.toLocaleString()}\n` + - `⚠️Error:\n${errorMessage}`, - ); - } + if (ntfy) { + await sendNtfyNotification( + ntfy, + "Build Failed", + "warning", + `view, Build details, ${buildLink}, clear=true;`, + `🛠️Project: ${projectName}\n` + + `⚙️Application: ${applicationName}\n` + + `❔Type: ${applicationType}\n` + + `🕒Date: ${date.toLocaleString()}\n` + + `⚠️Error:\n${errorMessage}`, + ); + } - if (telegram) { - const inlineButton = [ - [ - { - text: "Deployment Logs", - url: buildLink, - }, - ], - ]; + if (telegram) { + const inlineButton = [ + [ + { + text: "Deployment Logs", + url: buildLink, + }, + ], + ]; - await sendTelegramNotification( - telegram, - `⚠️ Build Failed\n\nProject: ${projectName}\nApplication: ${applicationName}\nType: ${applicationType}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}\n\nError:\n
${errorMessage}
`, - inlineButton, - ); - } + await sendTelegramNotification( + telegram, + `⚠️ Build Failed\n\nProject: ${projectName}\nApplication: ${applicationName}\nType: ${applicationType}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}\n\nError:\n
${errorMessage}
`, + inlineButton, + ); + } - if (slack) { - const { channel } = slack; - await sendSlackNotification(slack, { - channel: channel, - attachments: [ - { - color: "#FF0000", - pretext: ":warning: *Build Failed*", - fields: [ - { - title: "Project", - value: projectName, - short: true, - }, - { - title: "Application", - value: applicationName, - short: true, - }, - { - title: "Type", - value: applicationType, - short: true, - }, - { - title: "Time", - value: date.toLocaleString(), - short: true, - }, - { - title: "Error", - value: `\`\`\`${errorMessage}\`\`\``, - short: false, - }, - ], - actions: [ - { - type: "button", - text: "View Build Details", - url: buildLink, - }, - ], - }, - ], - }); - } + if (slack) { + const { channel } = slack; + await sendSlackNotification(slack, { + channel: channel, + attachments: [ + { + color: "#FF0000", + pretext: ":warning: *Build Failed*", + fields: [ + { + title: "Project", + value: projectName, + short: true, + }, + { + title: "Application", + value: applicationName, + short: true, + }, + { + title: "Type", + value: applicationType, + short: true, + }, + { + title: "Time", + value: date.toLocaleString(), + short: true, + }, + { + title: "Error", + value: `\`\`\`${errorMessage}\`\`\``, + short: false, + }, + ], + actions: [ + { + type: "button", + text: "View Build Details", + url: buildLink, + }, + ], + }, + ], + }); + } - if (lark) { - const limitCharacter = 800; - const truncatedErrorMessage = errorMessage.substring(0, limitCharacter); - await sendLarkNotification(lark, { - msg_type: "interactive", - card: { - schema: "2.0", - config: { - update_multi: true, - style: { - text_size: { - normal_v2: { - default: "normal", - pc: "normal", - mobile: "heading", + if (lark) { + const limitCharacter = 800; + const truncatedErrorMessage = errorMessage.substring(0, limitCharacter); + await sendLarkNotification(lark, { + msg_type: "interactive", + card: { + schema: "2.0", + config: { + update_multi: true, + style: { + text_size: { + normal_v2: { + default: "normal", + pc: "normal", + mobile: "heading", + }, }, }, }, - }, - header: { - title: { - tag: "plain_text", - content: "⚠️ Build Failed", - }, - subtitle: { - tag: "plain_text", - content: "", - }, - template: "red", - padding: "12px 12px 12px 12px", - }, - body: { - direction: "vertical", - padding: "12px 12px 12px 12px", - elements: [ - { - tag: "column_set", - columns: [ - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Project:**\n${projectName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Type:**\n${applicationType}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Error Message:**\n\`\`\`\n${truncatedErrorMessage}\n\`\`\``, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Application:**\n${applicationName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Date:**\n${format(date, "PP pp")}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - ], + header: { + title: { + tag: "plain_text", + content: "⚠️ Build Failed", }, - { - tag: "button", - text: { - tag: "plain_text", - content: "View Build Details", + subtitle: { + tag: "plain_text", + content: "", + }, + template: "red", + padding: "12px 12px 12px 12px", + }, + body: { + direction: "vertical", + padding: "12px 12px 12px 12px", + elements: [ + { + tag: "column_set", + columns: [ + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Project:**\n${projectName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Type:**\n${applicationType}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Error Message:**\n\`\`\`\n${truncatedErrorMessage}\n\`\`\``, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Application:**\n${applicationName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Date:**\n${format(date, "PP pp")}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + ], }, - type: "danger", - width: "default", - size: "medium", - behaviors: [ - { - type: "open_url", - default_url: buildLink, - pc_url: "", - ios_url: "", - android_url: "", + { + tag: "button", + text: { + tag: "plain_text", + content: "View Build Details", }, - ], - margin: "0px 0px 0px 0px", - }, - ], + type: "danger", + width: "default", + size: "medium", + behaviors: [ + { + type: "open_url", + default_url: buildLink, + pc_url: "", + ios_url: "", + android_url: "", + }, + ], + margin: "0px 0px 0px 0px", + }, + ], + }, }, - }, - }); + }); + } + } catch (error) { + console.log(error); } } }; diff --git a/packages/server/src/utils/notifications/build-success.ts b/packages/server/src/utils/notifications/build-success.ts index 5b5d6f518..232eb76c2 100644 --- a/packages/server/src/utils/notifications/build-success.ts +++ b/packages/server/src/utils/notifications/build-success.ts @@ -8,8 +8,8 @@ import { and, eq } from "drizzle-orm"; import { sendDiscordNotification, sendEmailNotification, - sendLarkNotification, sendGotifyNotification, + sendLarkNotification, sendNtfyNotification, sendSlackNotification, sendTelegramNotification, @@ -55,288 +55,295 @@ export const sendBuildSuccessNotifications = async ({ for (const notification of notificationList) { const { email, discord, telegram, slack, gotify, ntfy, lark } = notification; - - if (email) { - const template = await renderAsync( - BuildSuccessEmail({ - projectName, - applicationName, - applicationType, - buildLink, - date: date.toLocaleString(), - environmentName, - }), - ).catch(); - await sendEmailNotification(email, "Build success for dokploy", template); - } - - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); - - await sendDiscordNotification(discord, { - title: decorate(">", "`✅` Build Successes"), - color: 0x57f287, - fields: [ - { - name: decorate("`🛠️`", "Project"), - value: projectName, - inline: true, - }, - { - name: decorate("`⚙️`", "Application"), - value: applicationName, - inline: true, - }, - { - name: decorate("`🌍`", "Environment"), - value: environmentName, - inline: true, - }, - { - name: decorate("`❔`", "Type"), - value: applicationType, - inline: true, - }, - { - name: decorate("`📅`", "Date"), - value: ``, - inline: true, - }, - { - name: decorate("`⌚`", "Time"), - value: ``, - inline: true, - }, - { - name: decorate("`❓`", "Type"), - value: "Successful", - inline: true, - }, - { - name: decorate("`🧷`", "Build Link"), - value: `[Click here to access build link](${buildLink})`, - }, - ], - timestamp: date.toISOString(), - footer: { - text: "Dokploy Build Notification", - }, - }); - } - - if (gotify) { - const decorate = (decoration: string, text: string) => - `${gotify.decoration ? decoration : ""} ${text}\n`; - await sendGotifyNotification( - gotify, - decorate("✅", "Build Success"), - `${decorate("🛠️", `Project: ${projectName}`)}` + - `${decorate("⚙️", `Application: ${applicationName}`)}` + - `${decorate("🌍", `Environment: ${environmentName}`)}` + - `${decorate("❔", `Type: ${applicationType}`)}` + - `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + - `${decorate("🔗", `Build details:\n${buildLink}`)}`, - ); - } - - if (ntfy) { - await sendNtfyNotification( - ntfy, - "Build Success", - "white_check_mark", - `view, Build details, ${buildLink}, clear=true;`, - `🛠Project: ${projectName}\n` + - `⚙️Application: ${applicationName}\n` + - `🌍Environment: ${environmentName}\n` + - `❔Type: ${applicationType}\n` + - `🕒Date: ${date.toLocaleString()}`, - ); - } - - if (telegram) { - const chunkArray = (array: T[], chunkSize: number): T[][] => - Array.from({ length: Math.ceil(array.length / chunkSize) }, (_, i) => - array.slice(i * chunkSize, i * chunkSize + chunkSize), + try { + if (email) { + const template = await renderAsync( + BuildSuccessEmail({ + projectName, + applicationName, + applicationType, + buildLink, + date: date.toLocaleString(), + environmentName, + }), + ).catch(); + await sendEmailNotification( + email, + "Build success for dokploy", + template, ); + } - const inlineButton = [ - [ - { - text: "Deployment Logs", - url: buildLink, + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); + + await sendDiscordNotification(discord, { + title: decorate(">", "`✅` Build Successes"), + color: 0x57f287, + fields: [ + { + name: decorate("`🛠️`", "Project"), + value: projectName, + inline: true, + }, + { + name: decorate("`⚙️`", "Application"), + value: applicationName, + inline: true, + }, + { + name: decorate("`🌍`", "Environment"), + value: environmentName, + inline: true, + }, + { + name: decorate("`❔`", "Type"), + value: applicationType, + inline: true, + }, + { + name: decorate("`📅`", "Date"), + value: ``, + inline: true, + }, + { + name: decorate("`⌚`", "Time"), + value: ``, + inline: true, + }, + { + name: decorate("`❓`", "Type"), + value: "Successful", + inline: true, + }, + { + name: decorate("`🧷`", "Build Link"), + value: `[Click here to access build link](${buildLink})`, + }, + ], + timestamp: date.toISOString(), + footer: { + text: "Dokploy Build Notification", }, - ], - ...chunkArray(domains, 2).map((chunk) => - chunk.map((data) => ({ - text: data.host, - url: `${data.https ? "https" : "http"}://${data.host}`, - })), - ), - ]; + }); + } - await sendTelegramNotification( - telegram, - `✅ Build Success\n\nProject: ${projectName}\nApplication: ${applicationName}\nEnvironment: ${environmentName}\nType: ${applicationType}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}`, - inlineButton, - ); - } + if (gotify) { + const decorate = (decoration: string, text: string) => + `${gotify.decoration ? decoration : ""} ${text}\n`; + await sendGotifyNotification( + gotify, + decorate("✅", "Build Success"), + `${decorate("🛠️", `Project: ${projectName}`)}` + + `${decorate("⚙️", `Application: ${applicationName}`)}` + + `${decorate("🌍", `Environment: ${environmentName}`)}` + + `${decorate("❔", `Type: ${applicationType}`)}` + + `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + + `${decorate("🔗", `Build details:\n${buildLink}`)}`, + ); + } - if (slack) { - const { channel } = slack; - await sendSlackNotification(slack, { - channel: channel, - attachments: [ - { - color: "#00FF00", - pretext: ":white_check_mark: *Build Success*", - fields: [ - { - title: "Project", - value: projectName, - short: true, - }, - { - title: "Application", - value: applicationName, - short: true, - }, - { - title: "Environment", - value: environmentName, - short: true, - }, - { - title: "Type", - value: applicationType, - short: true, - }, - { - title: "Time", - value: date.toLocaleString(), - short: true, - }, - ], - actions: [ - { - type: "button", - text: "View Build Details", - url: buildLink, - }, - ], - }, - ], - }); - } + if (ntfy) { + await sendNtfyNotification( + ntfy, + "Build Success", + "white_check_mark", + `view, Build details, ${buildLink}, clear=true;`, + `🛠Project: ${projectName}\n` + + `⚙️Application: ${applicationName}\n` + + `🌍Environment: ${environmentName}\n` + + `❔Type: ${applicationType}\n` + + `🕒Date: ${date.toLocaleString()}`, + ); + } - if (lark) { - await sendLarkNotification(lark, { - msg_type: "interactive", - card: { - schema: "2.0", - config: { - update_multi: true, - style: { - text_size: { - normal_v2: { - default: "normal", - pc: "normal", - mobile: "heading", + if (telegram) { + const chunkArray = (array: T[], chunkSize: number): T[][] => + Array.from({ length: Math.ceil(array.length / chunkSize) }, (_, i) => + array.slice(i * chunkSize, i * chunkSize + chunkSize), + ); + + const inlineButton = [ + [ + { + text: "Deployment Logs", + url: buildLink, + }, + ], + ...chunkArray(domains, 2).map((chunk) => + chunk.map((data) => ({ + text: data.host, + url: `${data.https ? "https" : "http"}://${data.host}`, + })), + ), + ]; + + await sendTelegramNotification( + telegram, + `✅ Build Success\n\nProject: ${projectName}\nApplication: ${applicationName}\nEnvironment: ${environmentName}\nType: ${applicationType}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}`, + inlineButton, + ); + } + + if (slack) { + const { channel } = slack; + await sendSlackNotification(slack, { + channel: channel, + attachments: [ + { + color: "#00FF00", + pretext: ":white_check_mark: *Build Success*", + fields: [ + { + title: "Project", + value: projectName, + short: true, + }, + { + title: "Application", + value: applicationName, + short: true, + }, + { + title: "Environment", + value: environmentName, + short: true, + }, + { + title: "Type", + value: applicationType, + short: true, + }, + { + title: "Time", + value: date.toLocaleString(), + short: true, + }, + ], + actions: [ + { + type: "button", + text: "View Build Details", + url: buildLink, + }, + ], + }, + ], + }); + } + + if (lark) { + await sendLarkNotification(lark, { + msg_type: "interactive", + card: { + schema: "2.0", + config: { + update_multi: true, + style: { + text_size: { + normal_v2: { + default: "normal", + pc: "normal", + mobile: "heading", + }, }, }, }, - }, - header: { - title: { - tag: "plain_text", - content: "✅ Build Success", - }, - subtitle: { - tag: "plain_text", - content: "", - }, - template: "green", - padding: "12px 12px 12px 12px", - }, - body: { - direction: "vertical", - padding: "12px 12px 12px 12px", - elements: [ - { - tag: "column_set", - columns: [ - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Project:**\n${projectName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Environment:**\n${environmentName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Type:**\n${applicationType}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Application:**\n${applicationName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Date:**\n${format(date, "PP pp")}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - ], + header: { + title: { + tag: "plain_text", + content: "✅ Build Success", }, - { - tag: "button", - text: { - tag: "plain_text", - content: "View Build Details", + subtitle: { + tag: "plain_text", + content: "", + }, + template: "green", + padding: "12px 12px 12px 12px", + }, + body: { + direction: "vertical", + padding: "12px 12px 12px 12px", + elements: [ + { + tag: "column_set", + columns: [ + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Project:**\n${projectName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Environment:**\n${environmentName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Type:**\n${applicationType}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Application:**\n${applicationName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Date:**\n${format(date, "PP pp")}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + ], }, - type: "primary", - width: "default", - size: "medium", - behaviors: [ - { - type: "open_url", - default_url: buildLink, - pc_url: "", - ios_url: "", - android_url: "", + { + tag: "button", + text: { + tag: "plain_text", + content: "View Build Details", }, - ], - margin: "0px 0px 0px 0px", - }, - ], + type: "primary", + width: "default", + size: "medium", + behaviors: [ + { + type: "open_url", + default_url: buildLink, + pc_url: "", + ios_url: "", + android_url: "", + }, + ], + margin: "0px 0px 0px 0px", + }, + ], + }, }, - }, - }); + }); + } + } catch (error) { + console.log(error); } } }; diff --git a/packages/server/src/utils/notifications/database-backup.ts b/packages/server/src/utils/notifications/database-backup.ts index c5cb68dbc..02141e3ae 100644 --- a/packages/server/src/utils/notifications/database-backup.ts +++ b/packages/server/src/utils/notifications/database-backup.ts @@ -7,8 +7,8 @@ import { and, eq } from "drizzle-orm"; import { sendDiscordNotification, sendEmailNotification, - sendLarkNotification, sendGotifyNotification, + sendLarkNotification, sendNtfyNotification, sendSlackNotification, sendTelegramNotification, @@ -52,309 +52,312 @@ export const sendDatabaseBackupNotifications = async ({ for (const notification of notificationList) { const { email, discord, telegram, slack, gotify, ntfy, lark } = notification; + try { + if (email) { + const template = await renderAsync( + DatabaseBackupEmail({ + projectName, + applicationName, + databaseType, + type, + errorMessage, + date: date.toLocaleString(), + }), + ).catch(); + await sendEmailNotification( + email, + "Database backup for dokploy", + template, + ); + } - if (email) { - const template = await renderAsync( - DatabaseBackupEmail({ - projectName, - applicationName, - databaseType, - type, - errorMessage, - date: date.toLocaleString(), - }), - ).catch(); - await sendEmailNotification( - email, - "Database backup for dokploy", - template, - ); - } + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); + await sendDiscordNotification(discord, { + title: + type === "success" + ? decorate(">", "`✅` Database Backup Successful") + : decorate(">", "`❌` Database Backup Failed"), + color: type === "success" ? 0x57f287 : 0xed4245, + fields: [ + { + name: decorate("`🛠️`", "Project"), + value: projectName, + inline: true, + }, + { + name: decorate("`⚙️`", "Application"), + value: applicationName, + inline: true, + }, + { + name: decorate("`❔`", "Database"), + value: databaseType, + inline: true, + }, + { + name: decorate("`📂`", "Database Name"), + value: databaseName, + inline: true, + }, + { + name: decorate("`📅`", "Date"), + value: ``, + inline: true, + }, + { + name: decorate("`⌚`", "Time"), + value: ``, + inline: true, + }, + { + name: decorate("`❓`", "Type"), + value: type + .replace("error", "Failed") + .replace("success", "Successful"), + inline: true, + }, + ...(type === "error" && errorMessage + ? [ + { + name: decorate("`⚠️`", "Error Message"), + value: `\`\`\`${errorMessage}\`\`\``, + }, + ] + : []), + ], + timestamp: date.toISOString(), + footer: { + text: "Dokploy Database Backup Notification", + }, + }); + } - await sendDiscordNotification(discord, { - title: - type === "success" - ? decorate(">", "`✅` Database Backup Successful") - : decorate(">", "`❌` Database Backup Failed"), - color: type === "success" ? 0x57f287 : 0xed4245, - fields: [ - { - name: decorate("`🛠️`", "Project"), - value: projectName, - inline: true, - }, - { - name: decorate("`⚙️`", "Application"), - value: applicationName, - inline: true, - }, - { - name: decorate("`❔`", "Database"), - value: databaseType, - inline: true, - }, - { - name: decorate("`📂`", "Database Name"), - value: databaseName, - inline: true, - }, - { - name: decorate("`📅`", "Date"), - value: ``, - inline: true, - }, - { - name: decorate("`⌚`", "Time"), - value: ``, - inline: true, - }, - { - name: decorate("`❓`", "Type"), - value: type - .replace("error", "Failed") - .replace("success", "Successful"), - inline: true, - }, - ...(type === "error" && errorMessage - ? [ - { - name: decorate("`⚠️`", "Error Message"), - value: `\`\`\`${errorMessage}\`\`\``, - }, - ] - : []), - ], - timestamp: date.toISOString(), - footer: { - text: "Dokploy Database Backup Notification", - }, - }); - } + if (gotify) { + const decorate = (decoration: string, text: string) => + `${gotify.decoration ? decoration : ""} ${text}\n`; - if (gotify) { - const decorate = (decoration: string, text: string) => - `${gotify.decoration ? decoration : ""} ${text}\n`; + await sendGotifyNotification( + gotify, + decorate( + type === "success" ? "✅" : "❌", + `Database Backup ${type === "success" ? "Successful" : "Failed"}`, + ), + `${decorate("🛠️", `Project: ${projectName}`)}` + + `${decorate("⚙️", `Application: ${applicationName}`)}` + + `${decorate("❔", `Type: ${databaseType}`)}` + + `${decorate("📂", `Database Name: ${databaseName}`)}` + + `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + + `${type === "error" && errorMessage ? decorate("❌", `Error:\n${errorMessage}`) : ""}`, + ); + } - await sendGotifyNotification( - gotify, - decorate( - type === "success" ? "✅" : "❌", + if (ntfy) { + await sendNtfyNotification( + ntfy, `Database Backup ${type === "success" ? "Successful" : "Failed"}`, - ), - `${decorate("🛠️", `Project: ${projectName}`)}` + - `${decorate("⚙️", `Application: ${applicationName}`)}` + - `${decorate("❔", `Type: ${databaseType}`)}` + - `${decorate("📂", `Database Name: ${databaseName}`)}` + - `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + - `${type === "error" && errorMessage ? decorate("❌", `Error:\n${errorMessage}`) : ""}`, - ); - } + `${type === "success" ? "white_check_mark" : "x"}`, + "", + `🛠Project: ${projectName}\n` + + `⚙️Application: ${applicationName}\n` + + `❔Type: ${databaseType}\n` + + `📂Database Name: ${databaseName}` + + `🕒Date: ${date.toLocaleString()}\n` + + `${type === "error" && errorMessage ? `❌Error:\n${errorMessage}` : ""}`, + ); + } - if (ntfy) { - await sendNtfyNotification( - ntfy, - `Database Backup ${type === "success" ? "Successful" : "Failed"}`, - `${type === "success" ? "white_check_mark" : "x"}`, - "", - `🛠Project: ${projectName}\n` + - `⚙️Application: ${applicationName}\n` + - `❔Type: ${databaseType}\n` + - `📂Database Name: ${databaseName}` + - `🕒Date: ${date.toLocaleString()}\n` + - `${type === "error" && errorMessage ? `❌Error:\n${errorMessage}` : ""}`, - ); - } + if (telegram) { + const isError = type === "error" && errorMessage; - if (telegram) { - const isError = type === "error" && errorMessage; + const statusEmoji = type === "success" ? "✅" : "❌"; + const typeStatus = type === "success" ? "Successful" : "Failed"; + const errorMsg = isError + ? `\n\nError:\n
${errorMessage}
` + : ""; - const statusEmoji = type === "success" ? "✅" : "❌"; - const typeStatus = type === "success" ? "Successful" : "Failed"; - const errorMsg = isError - ? `\n\nError:\n
${errorMessage}
` - : ""; + const messageText = `${statusEmoji} Database Backup ${typeStatus}\n\nProject: ${projectName}\nApplication: ${applicationName}\nType: ${databaseType}\nDatabase Name: ${databaseName}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}${isError ? errorMsg : ""}`; - const messageText = `${statusEmoji} Database Backup ${typeStatus}\n\nProject: ${projectName}\nApplication: ${applicationName}\nType: ${databaseType}\nDatabase Name: ${databaseName}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}${isError ? errorMsg : ""}`; + await sendTelegramNotification(telegram, messageText); + } - await sendTelegramNotification(telegram, messageText); - } + if (slack) { + const { channel } = slack; + await sendSlackNotification(slack, { + channel: channel, + attachments: [ + { + color: type === "success" ? "#00FF00" : "#FF0000", + pretext: + type === "success" + ? ":white_check_mark: *Database Backup Successful*" + : ":x: *Database Backup Failed*", + fields: [ + ...(type === "error" && errorMessage + ? [ + { + title: "Error Message", + value: errorMessage, + short: false, + }, + ] + : []), + { + title: "Project", + value: projectName, + short: true, + }, + { + title: "Application", + value: applicationName, + short: true, + }, + { + title: "Type", + value: databaseType, + short: true, + }, + { + title: "Database Name", + value: databaseName, + }, + { + title: "Time", + value: date.toLocaleString(), + short: true, + }, + { + title: "Type", + value: type, + }, + { + title: "Status", + value: type === "success" ? "Successful" : "Failed", + }, + ], + }, + ], + }); + } - if (slack) { - const { channel } = slack; - await sendSlackNotification(slack, { - channel: channel, - attachments: [ - { - color: type === "success" ? "#00FF00" : "#FF0000", - pretext: - type === "success" - ? ":white_check_mark: *Database Backup Successful*" - : ":x: *Database Backup Failed*", - fields: [ - ...(type === "error" && errorMessage - ? [ - { - title: "Error Message", - value: errorMessage, - short: false, - }, - ] - : []), - { - title: "Project", - value: projectName, - short: true, - }, - { - title: "Application", - value: applicationName, - short: true, - }, - { - title: "Type", - value: databaseType, - short: true, - }, - { - title: "Database Name", - value: databaseName, - }, - { - title: "Time", - value: date.toLocaleString(), - short: true, - }, - { - title: "Type", - value: type, - }, - { - title: "Status", - value: type === "success" ? "Successful" : "Failed", - }, - ], - }, - ], - }); - } + if (lark) { + const limitCharacter = 800; + const truncatedErrorMessage = + errorMessage && errorMessage.length > limitCharacter + ? errorMessage.substring(0, limitCharacter) + : errorMessage; - if (lark) { - const limitCharacter = 800; - const truncatedErrorMessage = - errorMessage && errorMessage.length > limitCharacter - ? errorMessage.substring(0, limitCharacter) - : errorMessage; - - await sendLarkNotification(lark, { - msg_type: "interactive", - card: { - schema: "2.0", - config: { - update_multi: true, - style: { - text_size: { - normal_v2: { - default: "normal", - pc: "normal", - mobile: "heading", + await sendLarkNotification(lark, { + msg_type: "interactive", + card: { + schema: "2.0", + config: { + update_multi: true, + style: { + text_size: { + normal_v2: { + default: "normal", + pc: "normal", + mobile: "heading", + }, }, }, }, - }, - header: { - title: { - tag: "plain_text", - content: - type === "success" - ? "✅ Database Backup Successful" - : "❌ Database Backup Failed", - }, - subtitle: { - tag: "plain_text", - content: "", - }, - template: type === "success" ? "green" : "red", - padding: "12px 12px 12px 12px", - }, - body: { - direction: "vertical", - padding: "12px 12px 12px 12px", - elements: [ - { - tag: "column_set", - columns: [ - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Project:**\n${projectName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Database Type:**\n${databaseType}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Status:**\n${type === "success" ? "Successful" : "Failed"}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Application:**\n${applicationName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Database Name:**\n${databaseName}`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Date:**\n${format(date, "PP pp")}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - ], + header: { + title: { + tag: "plain_text", + content: + type === "success" + ? "✅ Database Backup Successful" + : "❌ Database Backup Failed", }, - ...(type === "error" && truncatedErrorMessage - ? [ + subtitle: { + tag: "plain_text", + content: "", + }, + template: type === "success" ? "green" : "red", + padding: "12px 12px 12px 12px", + }, + body: { + direction: "vertical", + padding: "12px 12px 12px 12px", + elements: [ + { + tag: "column_set", + columns: [ { - tag: "markdown", - content: `**Error Message:**\n\`\`\`\n${truncatedErrorMessage}\n\`\`\``, - text_align: "left", - text_size: "normal_v2", + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Project:**\n${projectName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Database Type:**\n${databaseType}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Status:**\n${type === "success" ? "Successful" : "Failed"}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, }, - ] - : []), - ], + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Application:**\n${applicationName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Database Name:**\n${databaseName}`, + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Date:**\n${format(date, "PP pp")}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + ], + }, + ...(type === "error" && truncatedErrorMessage + ? [ + { + tag: "markdown", + content: `**Error Message:**\n\`\`\`\n${truncatedErrorMessage}\n\`\`\``, + text_align: "left", + text_size: "normal_v2", + }, + ] + : []), + ], + }, }, - }, - }); + }); + } + } catch (error) { + console.log(error); } } }; diff --git a/packages/server/src/utils/notifications/docker-cleanup.ts b/packages/server/src/utils/notifications/docker-cleanup.ts index 062da9d49..f7947c8a0 100644 --- a/packages/server/src/utils/notifications/docker-cleanup.ts +++ b/packages/server/src/utils/notifications/docker-cleanup.ts @@ -7,8 +7,8 @@ import { and, eq } from "drizzle-orm"; import { sendDiscordNotification, sendEmailNotification, - sendLarkNotification, sendGotifyNotification, + sendLarkNotification, sendNtfyNotification, sendSlackNotification, sendTelegramNotification, @@ -39,182 +39,185 @@ export const sendDockerCleanupNotifications = async ( for (const notification of notificationList) { const { email, discord, telegram, slack, gotify, ntfy, lark } = notification; + try { + if (email) { + const template = await renderAsync( + DockerCleanupEmail({ message, date: date.toLocaleString() }), + ).catch(); - if (email) { - const template = await renderAsync( - DockerCleanupEmail({ message, date: date.toLocaleString() }), - ).catch(); + await sendEmailNotification( + email, + "Docker cleanup for dokploy", + template, + ); + } - await sendEmailNotification( - email, - "Docker cleanup for dokploy", - template, - ); - } + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); - - await sendDiscordNotification(discord, { - title: decorate(">", "`✅` Docker Cleanup"), - color: 0x57f287, - fields: [ - { - name: decorate("`📅`", "Date"), - value: ``, - inline: true, + await sendDiscordNotification(discord, { + title: decorate(">", "`✅` Docker Cleanup"), + color: 0x57f287, + fields: [ + { + name: decorate("`📅`", "Date"), + value: ``, + inline: true, + }, + { + name: decorate("`⌚`", "Time"), + value: ``, + inline: true, + }, + { + name: decorate("`❓`", "Type"), + value: "Successful", + inline: true, + }, + { + name: decorate("`📜`", "Message"), + value: `\`\`\`${message}\`\`\``, + }, + ], + timestamp: date.toISOString(), + footer: { + text: "Dokploy Docker Cleanup Notification", }, - { - name: decorate("`⌚`", "Time"), - value: ``, - inline: true, - }, - { - name: decorate("`❓`", "Type"), - value: "Successful", - inline: true, - }, - { - name: decorate("`📜`", "Message"), - value: `\`\`\`${message}\`\`\``, - }, - ], - timestamp: date.toISOString(), - footer: { - text: "Dokploy Docker Cleanup Notification", - }, - }); - } + }); + } - if (gotify) { - const decorate = (decoration: string, text: string) => - `${gotify.decoration ? decoration : ""} ${text}\n`; - await sendGotifyNotification( - gotify, - decorate("✅", "Docker Cleanup"), - `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + - `${decorate("📜", `Message:\n${message}`)}`, - ); - } + if (gotify) { + const decorate = (decoration: string, text: string) => + `${gotify.decoration ? decoration : ""} ${text}\n`; + await sendGotifyNotification( + gotify, + decorate("✅", "Docker Cleanup"), + `${decorate("🕒", `Date: ${date.toLocaleString()}`)}` + + `${decorate("📜", `Message:\n${message}`)}`, + ); + } - if (ntfy) { - await sendNtfyNotification( - ntfy, - "Docker Cleanup", - "white_check_mark", - "", - `🕒Date: ${date.toLocaleString()}\n` + `📜Message:\n${message}`, - ); - } + if (ntfy) { + await sendNtfyNotification( + ntfy, + "Docker Cleanup", + "white_check_mark", + "", + `🕒Date: ${date.toLocaleString()}\n` + `📜Message:\n${message}`, + ); + } - if (telegram) { - await sendTelegramNotification( - telegram, - `✅ Docker Cleanup\n\nMessage: ${message}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}`, - ); - } + if (telegram) { + await sendTelegramNotification( + telegram, + `✅ Docker Cleanup\n\nMessage: ${message}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}`, + ); + } - if (slack) { - const { channel } = slack; - await sendSlackNotification(slack, { - channel: channel, - attachments: [ - { - color: "#00FF00", - pretext: ":white_check_mark: *Docker Cleanup*", - fields: [ - { - title: "Message", - value: message, - }, - { - title: "Time", - value: date.toLocaleString(), - short: true, - }, - ], - }, - ], - }); - } + if (slack) { + const { channel } = slack; + await sendSlackNotification(slack, { + channel: channel, + attachments: [ + { + color: "#00FF00", + pretext: ":white_check_mark: *Docker Cleanup*", + fields: [ + { + title: "Message", + value: message, + }, + { + title: "Time", + value: date.toLocaleString(), + short: true, + }, + ], + }, + ], + }); + } - if (lark) { - await sendLarkNotification(lark, { - msg_type: "interactive", - card: { - schema: "2.0", - config: { - update_multi: true, - style: { - text_size: { - normal_v2: { - default: "normal", - pc: "normal", - mobile: "heading", + if (lark) { + await sendLarkNotification(lark, { + msg_type: "interactive", + card: { + schema: "2.0", + config: { + update_multi: true, + style: { + text_size: { + normal_v2: { + default: "normal", + pc: "normal", + mobile: "heading", + }, }, }, }, - }, - header: { - title: { - tag: "plain_text", - content: "✅ Docker Cleanup", - }, - subtitle: { - tag: "plain_text", - content: "", - }, - template: "green", - padding: "12px 12px 12px 12px", - }, - body: { - direction: "vertical", - padding: "12px 12px 12px 12px", - elements: [ - { - tag: "column_set", - columns: [ - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Status:**\nSuccessful`, - text_align: "left", - text_size: "normal_v2", - }, - { - tag: "markdown", - content: `**Cleanup Details:**\n${message}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Date:**\n${format(date, "PP pp")}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - ], + header: { + title: { + tag: "plain_text", + content: "✅ Docker Cleanup", }, - ], + subtitle: { + tag: "plain_text", + content: "", + }, + template: "green", + padding: "12px 12px 12px 12px", + }, + body: { + direction: "vertical", + padding: "12px 12px 12px 12px", + elements: [ + { + tag: "column_set", + columns: [ + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: "**Status:**\nSuccessful", + text_align: "left", + text_size: "normal_v2", + }, + { + tag: "markdown", + content: `**Cleanup Details:**\n${message}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Date:**\n${format(date, "PP pp")}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + ], + }, + ], + }, }, - }, - }); + }); + } + } catch (error) { + console.log(error); } } }; diff --git a/packages/server/src/utils/notifications/dokploy-restart.ts b/packages/server/src/utils/notifications/dokploy-restart.ts index 2582c92d1..093e14010 100644 --- a/packages/server/src/utils/notifications/dokploy-restart.ts +++ b/packages/server/src/utils/notifications/dokploy-restart.ts @@ -7,8 +7,8 @@ import { eq } from "drizzle-orm"; import { sendDiscordNotification, sendEmailNotification, - sendLarkNotification, sendGotifyNotification, + sendLarkNotification, sendNtfyNotification, sendSlackNotification, sendTelegramNotification, @@ -34,18 +34,23 @@ export const sendDokployRestartNotifications = async () => { const { email, discord, telegram, slack, gotify, ntfy, lark } = notification; - if (email) { - const template = await renderAsync( - DokployRestartEmail({ date: date.toLocaleString() }), - ).catch(); - await sendEmailNotification(email, "Dokploy Server Restarted", template); - } + try { + if (email) { + const template = await renderAsync( + DokployRestartEmail({ date: date.toLocaleString() }), + ).catch(); - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); + await sendEmailNotification( + email, + "Dokploy Server Restarted", + template, + ); + } + + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); - try { await sendDiscordNotification(discord, { title: decorate(">", "`✅` Dokploy Server Restarted"), color: 0x57f287, @@ -71,27 +76,19 @@ export const sendDokployRestartNotifications = async () => { text: "Dokploy Restart Notification", }, }); - } catch (error) { - console.log(error); } - } - if (gotify) { - const decorate = (decoration: string, text: string) => - `${gotify.decoration ? decoration : ""} ${text}\n`; - try { + if (gotify) { + const decorate = (decoration: string, text: string) => + `${gotify.decoration ? decoration : ""} ${text}\n`; await sendGotifyNotification( gotify, decorate("✅", "Dokploy Server Restarted"), `${decorate("🕒", `Date: ${date.toLocaleString()}`)}`, ); - } catch (error) { - console.log(error); } - } - if (ntfy) { - try { + if (ntfy) { await sendNtfyNotification( ntfy, "Dokploy Server Restarted", @@ -99,25 +96,17 @@ export const sendDokployRestartNotifications = async () => { "", `🕒Date: ${date.toLocaleString()}`, ); - } catch (error) { - console.log(error); } - } - if (telegram) { - try { + if (telegram) { await sendTelegramNotification( telegram, `✅ Dokploy Server Restarted\n\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}`, ); - } catch (error) { - console.log(error); } - } - if (slack) { - const { channel } = slack; - try { + if (slack) { + const { channel } = slack; await sendSlackNotification(slack, { channel: channel, attachments: [ @@ -134,13 +123,9 @@ export const sendDokployRestartNotifications = async () => { }, ], }); - } catch (error) { - console.log(error); } - } - if (lark) { - try { + if (lark) { await sendLarkNotification(lark, { msg_type: "interactive", card: { @@ -182,7 +167,7 @@ export const sendDokployRestartNotifications = async () => { elements: [ { tag: "markdown", - content: `**Status:**\nSuccessful`, + content: "**Status:**\nSuccessful", text_align: "left", text_size: "normal_v2", }, @@ -210,9 +195,9 @@ export const sendDokployRestartNotifications = async () => { }, }, }); - } catch (error) { - console.log(error); } + } catch (error) { + console.log(error); } } }; diff --git a/packages/server/src/utils/notifications/utils.ts b/packages/server/src/utils/notifications/utils.ts index a56a70918..539376ac5 100644 --- a/packages/server/src/utils/notifications/utils.ts +++ b/packages/server/src/utils/notifications/utils.ts @@ -1,8 +1,8 @@ import type { discord, email, - lark, gotify, + lark, ntfy, slack, telegram, @@ -38,6 +38,9 @@ export const sendEmailNotification = async ( }); } catch (err) { console.log(err); + throw new Error( + `Failed to send email notification ${err instanceof Error ? err.message : "Unknown error"}`, + ); } }; @@ -45,15 +48,23 @@ export const sendDiscordNotification = async ( connection: typeof discord.$inferInsert, embed: any, ) => { - // try { - await fetch(connection.webhookUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ embeds: [embed] }), - }); - // } catch (err) { - // console.log(err); - // } + try { + const response = await fetch(connection.webhookUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ embeds: [embed] }), + }); + if (!response.ok) { + throw new Error( + `Failed to send discord notification ${response.statusText}`, + ); + } + } catch (err) { + console.log("error", err); + throw new Error( + `Failed to send discord notification ${err instanceof Error ? err.message : "Unknown error"}`, + ); + } }; export const sendTelegramNotification = async ( @@ -90,13 +101,21 @@ export const sendSlackNotification = async ( message: any, ) => { try { - await fetch(connection.webhookUrl, { + const response = await fetch(connection.webhookUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(message), }); + if (!response.ok) { + throw new Error( + `Failed to send slack notification ${response.statusText}`, + ); + } } catch (err) { - console.log(err); + console.log("error", err); + throw new Error( + `Failed to send slack notification ${err instanceof Error ? err.message : "Unknown error"}`, + ); } };