From 365e055005e437f85cc34823df666c9da61634bd Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 1 Apr 2026 08:26:24 -0600 Subject: [PATCH] feat(notifications): integrate dokployBackup into notification handling - Added dokployBackup parameter to various notification functions and schemas to support backup notifications. - Updated HandleNotifications component to include dokployBackup in notification payloads. - Enhanced notification utilities to accommodate new backup notification types across multiple channels. --- .../notifications/handle-notifications.tsx | 10 + packages/server/src/db/schema/notification.ts | 7 + packages/server/src/services/notification.ts | 10 + .../src/utils/notifications/dokploy-backup.ts | 606 ++++++++++-------- 4 files changed, 379 insertions(+), 254 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index 7f427ef07..37463fd62 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -421,6 +421,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, apiKey: notification.resend?.apiKey, @@ -469,6 +470,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, webhookUrl: notification.mattermost?.webhookUrl, @@ -498,6 +500,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, webhookUrl: notification.teams?.webhookUrl, @@ -511,6 +514,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, type: notification.notificationType, endpoint: notification.custom?.endpoint || "", headers: notification.custom?.headers @@ -532,6 +536,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: notification.appDeploy, dokployRestart: notification.dokployRestart, databaseBackup: notification.databaseBackup, + dokployBackup: notification.dokployBackup, volumeBackup: notification.volumeBackup, type: notification.notificationType, userKey: notification.pushover?.userKey, @@ -651,6 +656,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, apiKey: data.apiKey, fromAddress: data.fromAddress, @@ -701,6 +707,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, channel: data.channel || undefined, @@ -732,6 +739,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, webhookUrl: data.webhookUrl, name: data.name, @@ -758,6 +766,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, endpoint: data.endpoint, headers: headersRecord, @@ -777,6 +786,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { appDeploy: appDeploy, dokployRestart: dokployRestart, databaseBackup: databaseBackup, + dokployBackup: dokployBackup, volumeBackup: volumeBackup, userKey: data.userKey, apiToken: data.apiToken, diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 94398704b..3caf23d13 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -396,6 +396,7 @@ export const apiCreateResend = notificationsSchema .pick({ appBuildError: true, databaseBackup: true, + dokployBackup: true, volumeBackup: true, dokployRestart: true, name: true, @@ -493,6 +494,7 @@ export const apiCreateMattermost = notificationsSchema .pick({ appBuildError: true, databaseBackup: true, + dokployBackup: true, volumeBackup: true, dokployRestart: true, name: true, @@ -510,6 +512,7 @@ export const apiCreateMattermost = notificationsSchema webhookUrl: true, appBuildError: true, databaseBackup: true, + dokployBackup: true, volumeBackup: true, dokployRestart: true, appDeploy: true, @@ -542,6 +545,7 @@ export const apiCreateCustom = notificationsSchema .pick({ appBuildError: true, databaseBackup: true, + dokployBackup: true, volumeBackup: true, dokployRestart: true, name: true, @@ -596,6 +600,7 @@ export const apiCreateTeams = notificationsSchema .pick({ appBuildError: true, databaseBackup: true, + dokployBackup: true, volumeBackup: true, dokployRestart: true, name: true, @@ -622,6 +627,7 @@ export const apiCreatePushover = notificationsSchema .pick({ appBuildError: true, databaseBackup: true, + dokployBackup: true, volumeBackup: true, dokployRestart: true, name: true, @@ -656,6 +662,7 @@ export const apiUpdatePushover = z.object({ expire: z.number().min(1).max(10800).nullish(), appBuildError: z.boolean().optional(), databaseBackup: z.boolean().optional(), + dokployBackup: z.boolean().optional(), volumeBackup: z.boolean().optional(), dokployRestart: z.boolean().optional(), name: z.string().optional(), diff --git a/packages/server/src/services/notification.ts b/packages/server/src/services/notification.ts index b689d7194..2c8247f0c 100644 --- a/packages/server/src/services/notification.ts +++ b/packages/server/src/services/notification.ts @@ -460,6 +460,7 @@ export const createResendNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -492,6 +493,7 @@ export const updateResendNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -741,6 +743,7 @@ export const createCustomNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -773,6 +776,7 @@ export const updateCustomNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -958,6 +962,7 @@ export const createTeamsNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -990,6 +995,7 @@ export const updateTeamsNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -1065,6 +1071,7 @@ export const createMattermostNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -1097,6 +1104,7 @@ export const updateMattermostNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -1161,6 +1169,7 @@ export const createPushoverNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, @@ -1193,6 +1202,7 @@ export const updatePushoverNotification = async ( appDeploy: input.appDeploy, appBuildError: input.appBuildError, databaseBackup: input.databaseBackup, + dokployBackup: input.dokployBackup, volumeBackup: input.volumeBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, diff --git a/packages/server/src/utils/notifications/dokploy-backup.ts b/packages/server/src/utils/notifications/dokploy-backup.ts index 580dd1baa..26a88d657 100644 --- a/packages/server/src/utils/notifications/dokploy-backup.ts +++ b/packages/server/src/utils/notifications/dokploy-backup.ts @@ -5,12 +5,17 @@ import { renderAsync } from "@react-email/components"; import { format } from "date-fns"; import { eq } from "drizzle-orm"; import { + sendCustomNotification, sendDiscordNotification, sendEmailNotification, - sendLarkNotification, sendGotifyNotification, + sendLarkNotification, + sendMattermostNotification, sendNtfyNotification, + sendPushoverNotification, + sendResendNotification, sendSlackNotification, + sendTeamsNotification, sendTelegramNotification, } from "./utils"; @@ -32,287 +37,380 @@ export const sendDokployBackupNotifications = async ({ discord: true, telegram: true, slack: true, + resend: true, gotify: true, ntfy: true, + mattermost: true, + custom: true, lark: true, + pushover: true, + teams: true, }, }); for (const notification of notificationList) { - const { email, discord, telegram, slack, gotify, ntfy, lark } = - notification; + const { + email, + discord, + telegram, + slack, + resend, + gotify, + ntfy, + mattermost, + custom, + lark, + pushover, + teams, + } = notification; - if (email) { - const template = await renderAsync( - DokployBackupEmail({ - type, - errorMessage, - date: date.toLocaleString(), - backupSize, - }), - ).catch(); - await sendEmailNotification(email, "Dokploy instance backup", template); - } + try { + if (email || resend) { + const template = await renderAsync( + DokployBackupEmail({ + type, + errorMessage, + date: date.toLocaleString(), + backupSize, + }), + ).catch(); - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); + if (email) { + await sendEmailNotification( + email, + "Dokploy instance backup", + template, + ); + } - await sendDiscordNotification(discord, { - title: - type === "success" - ? decorate(">", "`โœ…` Dokploy Backup Successful") - : decorate(">", "`โŒ` Dokploy Backup Failed"), - color: type === "success" ? 0x57f287 : 0xed4245, - fields: [ - { - name: decorate("`๐Ÿ“ฆ`", "Backup Type"), - value: "Complete Dokploy Instance", - inline: true, + if (resend) { + await sendResendNotification( + resend, + "Dokploy instance backup", + template, + ); + } + } + + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); + + await sendDiscordNotification(discord, { + title: + type === "success" + ? decorate(">", "`โœ…` Dokploy Backup Successful") + : decorate(">", "`โŒ` Dokploy Backup Failed"), + color: type === "success" ? 0x57f287 : 0xed4245, + fields: [ + { + name: decorate("`๐Ÿ“ฆ`", "Backup Type"), + value: "Complete Dokploy Instance", + inline: true, + }, + ...(backupSize + ? [ + { + name: decorate("`๐Ÿ’พ`", "Backup Size"), + value: backupSize, + inline: true, + }, + ] + : []), + { + name: decorate("`๐Ÿ“…`", "Date"), + value: ``, + inline: true, + }, + { + name: decorate("`โŒš`", "Time"), + value: ``, + inline: true, + }, + { + name: decorate("`โ“`", "Status"), + 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 Instance Backup Notification", }, - ...(backupSize - ? [ - { - name: decorate("`๐Ÿ’พ`", "Backup Size"), - value: backupSize, - inline: true, - }, - ] - : []), - { - name: decorate("`๐Ÿ“…`", "Date"), - value: ``, - inline: true, - }, - { - name: decorate("`โŒš`", "Time"), - value: ``, - inline: true, - }, - { - name: decorate("`โ“`", "Status"), - 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 Instance 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" ? "โœ…" : "โŒ", + await sendGotifyNotification( + gotify, + decorate( + type === "success" ? "โœ…" : "โŒ", + `Dokploy Backup ${type === "success" ? "Successful" : "Failed"}`, + ), + `${decorate("๐Ÿ“ฆ", "Backup Type: Complete Dokploy Instance")}` + + `${backupSize ? decorate("๐Ÿ’พ", `Backup Size: ${backupSize}`) : ""}` + + `${decorate("๐Ÿ•’", `Date: ${date.toLocaleString()}`)}` + + `${type === "error" && errorMessage ? decorate("โŒ", `Error:\n${errorMessage}`) : ""}`, + ); + } + + if (ntfy) { + await sendNtfyNotification( + ntfy, `Dokploy Backup ${type === "success" ? "Successful" : "Failed"}`, - ), - `${decorate("๐Ÿ“ฆ", "Backup Type: Complete Dokploy Instance")}` + - `${backupSize ? decorate("๐Ÿ’พ", `Backup Size: ${backupSize}`) : ""}` + - `${decorate("๐Ÿ•’", `Date: ${date.toLocaleString()}`)}` + - `${type === "error" && errorMessage ? decorate("โŒ", `Error:\n${errorMessage}`) : ""}`, - ); - } + `${type === "success" ? "white_check_mark" : "x"}`, + "", + "๐Ÿ“ฆBackup Type: Complete Dokploy Instance\n" + + `${backupSize ? `๐Ÿ’พBackup Size: ${backupSize}\n` : ""}` + + `๐Ÿ•’Date: ${date.toLocaleString()}\n` + + `${type === "error" && errorMessage ? `โŒError:\n${errorMessage}` : ""}`, + ); + } - if (ntfy) { - await sendNtfyNotification( - ntfy, - `Dokploy Backup ${type === "success" ? "Successful" : "Failed"}`, - `${type === "success" ? "white_check_mark" : "x"}`, - "", - `๐Ÿ“ฆBackup Type: Complete Dokploy Instance\n` + - `${backupSize ? `๐Ÿ’พBackup Size: ${backupSize}\n` : ""}` + - `๐Ÿ•’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 sizeInfo = backupSize + ? `\nBackup Size: ${backupSize}` + : ""; - const statusEmoji = type === "success" ? "โœ…" : "โŒ"; - const typeStatus = type === "success" ? "Successful" : "Failed"; - const errorMsg = isError - ? `\n\nError:\n
${errorMessage}
` - : ""; - const sizeInfo = backupSize ? `\nBackup Size: ${backupSize}` : ""; + const messageText = `${statusEmoji} Dokploy Backup ${typeStatus}\n\nBackup Type: Complete Dokploy Instance${sizeInfo}\nDate: ${format(date, "PP")}\nTime: ${format(date, "pp")}${isError ? errorMsg : ""}`; - const messageText = `${statusEmoji} Dokploy Backup ${typeStatus}\n\nBackup Type: Complete Dokploy Instance${sizeInfo}\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: *Dokploy Backup Successful*" + : ":x: *Dokploy Backup Failed*", + fields: [ + ...(type === "error" && errorMessage + ? [ + { + title: "Error Message", + value: errorMessage, + short: false, + }, + ] + : []), + { + title: "Backup Type", + value: "Complete Dokploy Instance", + short: true, + }, + ...(backupSize + ? [ + { + title: "Backup Size", + value: backupSize, + short: true, + }, + ] + : []), + { + title: "Time", + value: date.toLocaleString(), + short: true, + }, + { + title: "Status", + value: type === "success" ? "Successful" : "Failed", + short: true, + }, + ], + }, + ], + }); + } - if (slack) { - const { channel } = slack; - await sendSlackNotification(slack, { - channel: channel, - attachments: [ - { - color: type === "success" ? "#00FF00" : "#FF0000", - pretext: - type === "success" - ? ":white_check_mark: *Dokploy Backup Successful*" - : ":x: *Dokploy Backup Failed*", - fields: [ - ...(type === "error" && errorMessage - ? [ - { - title: "Error Message", - value: errorMessage, - short: false, - }, - ] - : []), - { - title: "Backup Type", - value: "Complete Dokploy Instance", - short: true, - }, - ...(backupSize - ? [ - { - title: "Backup Size", - value: backupSize, - short: true, - }, - ] - : []), - { - title: "Time", - value: date.toLocaleString(), - short: true, - }, - { - title: "Status", - value: type === "success" ? "Successful" : "Failed", - short: true, - }, - ], - }, - ], - }); - } + 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" - ? "โœ… Dokploy Backup Successful" - : "โŒ Dokploy 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: `**Backup Type:**\nComplete Dokploy Instance`, - 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: [ - ...(backupSize - ? [ - { - tag: "markdown", - content: `**Backup Size:**\n${backupSize}`, - 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" + ? "โœ… Dokploy Backup Successful" + : "โŒ Dokploy 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: + "**Backup Type:**\nComplete Dokploy Instance", + 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: [ + ...(backupSize + ? [ + { + tag: "markdown", + content: `**Backup Size:**\n${backupSize}`, + 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", + }, + ] + : []), + ], + }, }, - }, - }); + }); + } + + if (mattermost) { + const statusEmoji = type === "success" ? ":white_check_mark:" : ":x:"; + const typeStatus = type === "success" ? "Successful" : "Failed"; + await sendMattermostNotification(mattermost, { + text: `${statusEmoji} **Dokploy Backup ${typeStatus}** + +**Backup Type:** Complete Dokploy Instance${backupSize ? `\n**Backup Size:** ${backupSize}` : ""} +**Date:** ${date.toLocaleString()} +**Status:** ${typeStatus}${type === "error" && errorMessage ? `\n\n**Error:**\n\`\`\`\n${errorMessage}\n\`\`\`` : ""}`, + channel: mattermost.channel, + username: mattermost.username || "Dokploy Bot", + }); + } + + if (custom) { + await sendCustomNotification(custom, { + title: `Dokploy Backup ${type === "success" ? "Successful" : "Failed"}`, + message: `Dokploy instance backup ${type === "success" ? "completed successfully" : "failed"}`, + backupType: "Complete Dokploy Instance", + ...(backupSize ? { backupSize } : {}), + ...(type === "error" && errorMessage ? { errorMessage } : {}), + timestamp: date.toISOString(), + date: date.toLocaleString(), + status: type, + type: "dokploy-backup", + }); + } + + if (pushover) { + await sendPushoverNotification( + pushover, + `Dokploy Backup ${type === "success" ? "Successful" : "Failed"}`, + `Backup Type: Complete Dokploy Instance${backupSize ? `\nBackup Size: ${backupSize}` : ""}\nDate: ${date.toLocaleString()}${type === "error" && errorMessage ? `\nError: ${errorMessage}` : ""}`, + ); + } + + if (teams) { + await sendTeamsNotification(teams, { + title: `${type === "success" ? "โœ…" : "โŒ"} Dokploy Backup ${type === "success" ? "Successful" : "Failed"}`, + facts: [ + { name: "Backup Type", value: "Complete Dokploy Instance" }, + ...(backupSize ? [{ name: "Backup Size", value: backupSize }] : []), + { name: "Date", value: format(date, "PP pp") }, + { + name: "Status", + value: type === "success" ? "Successful" : "Failed", + }, + ...(type === "error" && errorMessage + ? [{ name: "Error Message", value: errorMessage }] + : []), + ], + }); + } + } catch (error) { + console.error(error); } } };