From 43228fc51b89e506014ae3a4d7062029a8d79f7a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 24 Jan 2026 18:15:23 +0000 Subject: [PATCH] [autofix.ci] apply automated fixes --- .../src/utils/notifications/build-error.ts | 736 ++++++++-------- .../src/utils/notifications/build-success.ts | 764 ++++++++--------- .../utils/notifications/database-backup.ts | 792 +++++++++--------- .../src/utils/notifications/docker-cleanup.ts | 496 +++++------ .../utils/notifications/dokploy-restart.ts | 474 +++++------ 5 files changed, 1631 insertions(+), 1631 deletions(-) diff --git a/packages/server/src/utils/notifications/build-error.ts b/packages/server/src/utils/notifications/build-error.ts index 021ccd05a..603de64a5 100644 --- a/packages/server/src/utils/notifications/build-error.ts +++ b/packages/server/src/utils/notifications/build-error.ts @@ -1,12 +1,12 @@ -import { db } from "@dokploy/server/db"; -import { notifications } from "@dokploy/server/db/schema"; -import BuildFailedEmail from "@dokploy/server/emails/emails/build-failed"; -import { renderAsync } from "@react-email/components"; -import { format } from "date-fns"; -import { and, eq } from "drizzle-orm"; -import { - sendCustomNotification, - sendDiscordNotification, +import { db } from "@dokploy/server/db"; +import { notifications } from "@dokploy/server/db/schema"; +import BuildFailedEmail from "@dokploy/server/emails/emails/build-failed"; +import { renderAsync } from "@react-email/components"; +import { format } from "date-fns"; +import { and, eq } from "drizzle-orm"; +import { + sendCustomNotification, + sendDiscordNotification, sendEmailNotification, sendGotifyNotification, sendLarkNotification, @@ -16,46 +16,46 @@ import { sendSlackNotification, sendTelegramNotification, } from "./utils"; - -interface Props { - projectName: string; - applicationName: string; - applicationType: string; - errorMessage: string; - buildLink: string; - organizationId: string; -} - -export const sendBuildErrorNotifications = async ({ - projectName, - applicationName, - applicationType, - errorMessage, - buildLink, - organizationId, -}: Props) => { - const date = new Date(); - const unixDate = ~~(Number(date) / 1000); - const notificationList = await db.query.notifications.findMany({ - where: and( - eq(notifications.appBuildError, true), - eq(notifications.organizationId, organizationId), - ), - with: { - email: true, - discord: true, - telegram: true, - slack: true, - resend: true, - gotify: true, - ntfy: true, - custom: true, - lark: true, - pushover: true, - }, - }); - - for (const notification of notificationList) { + +interface Props { + projectName: string; + applicationName: string; + applicationType: string; + errorMessage: string; + buildLink: string; + organizationId: string; +} + +export const sendBuildErrorNotifications = async ({ + projectName, + applicationName, + applicationType, + errorMessage, + buildLink, + organizationId, +}: Props) => { + const date = new Date(); + const unixDate = ~~(Number(date) / 1000); + const notificationList = await db.query.notifications.findMany({ + where: and( + eq(notifications.appBuildError, true), + eq(notifications.organizationId, organizationId), + ), + with: { + email: true, + discord: true, + telegram: true, + slack: true, + resend: true, + gotify: true, + ntfy: true, + custom: true, + lark: true, + pushover: true, + }, + }); + + for (const notification of notificationList) { const { email, resend, @@ -68,322 +68,322 @@ export const sendBuildErrorNotifications = async ({ lark, pushover, } = notification; - try { - if (email || resend) { - const template = await renderAsync( - BuildFailedEmail({ - projectName, - applicationName, - applicationType, - errorMessage: errorMessage, - buildLink, - date: date.toLocaleString(), - }), - ).catch(); - - if (email) { - await sendEmailNotification( - email, - "Build failed for dokploy", - template, - ); - } - - if (resend) { - await sendResendNotification( - resend, - "Build failed for dokploy", - template, - ); - } - } - - 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, - }, - { - 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 (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, - }, - ], - ]; - - 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 (custom) { - await sendCustomNotification(custom, { - title: "Build Error", - message: "Build failed with errors", - projectName, - applicationName, - applicationType, - errorMessage, - buildLink, - timestamp: date.toISOString(), - date: date.toLocaleString(), - status: "error", - type: "build", - }); - } - - 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, - }, - ], - }, - { - tag: "button", - text: { - tag: "plain_text", - content: "View Build Details", - }, - type: "danger", - width: "default", - size: "medium", - behaviors: [ - { - type: "open_url", - default_url: buildLink, - pc_url: "", - ios_url: "", - android_url: "", - }, - ], - margin: "0px 0px 0px 0px", - }, - ], - }, - }, - }); - } - - if (pushover) { - await sendPushoverNotification( - pushover, - "Build Failed", - `Project: ${projectName}\nApplication: ${applicationName}\nType: ${applicationType}\nDate: ${date.toLocaleString()}\nError: ${errorMessage}`, - ); - } - } catch (error) { - console.log(error); - } - } -}; + try { + if (email || resend) { + const template = await renderAsync( + BuildFailedEmail({ + projectName, + applicationName, + applicationType, + errorMessage: errorMessage, + buildLink, + date: date.toLocaleString(), + }), + ).catch(); + + if (email) { + await sendEmailNotification( + email, + "Build failed for dokploy", + template, + ); + } + + if (resend) { + await sendResendNotification( + resend, + "Build failed for dokploy", + template, + ); + } + } + + 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, + }, + { + 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 (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, + }, + ], + ]; + + 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 (custom) { + await sendCustomNotification(custom, { + title: "Build Error", + message: "Build failed with errors", + projectName, + applicationName, + applicationType, + errorMessage, + buildLink, + timestamp: date.toISOString(), + date: date.toLocaleString(), + status: "error", + type: "build", + }); + } + + 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, + }, + ], + }, + { + tag: "button", + text: { + tag: "plain_text", + content: "View Build Details", + }, + type: "danger", + width: "default", + size: "medium", + behaviors: [ + { + type: "open_url", + default_url: buildLink, + pc_url: "", + ios_url: "", + android_url: "", + }, + ], + margin: "0px 0px 0px 0px", + }, + ], + }, + }, + }); + } + + if (pushover) { + await sendPushoverNotification( + pushover, + "Build Failed", + `Project: ${projectName}\nApplication: ${applicationName}\nType: ${applicationType}\nDate: ${date.toLocaleString()}\nError: ${errorMessage}`, + ); + } + } 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 e5a735b4d..09101b9c3 100644 --- a/packages/server/src/utils/notifications/build-success.ts +++ b/packages/server/src/utils/notifications/build-success.ts @@ -1,13 +1,13 @@ -import { db } from "@dokploy/server/db"; -import { notifications } from "@dokploy/server/db/schema"; -import BuildSuccessEmail from "@dokploy/server/emails/emails/build-success"; -import type { Domain } from "@dokploy/server/services/domain"; -import { renderAsync } from "@react-email/components"; -import { format } from "date-fns"; -import { and, eq } from "drizzle-orm"; -import { - sendCustomNotification, - sendDiscordNotification, +import { db } from "@dokploy/server/db"; +import { notifications } from "@dokploy/server/db/schema"; +import BuildSuccessEmail from "@dokploy/server/emails/emails/build-success"; +import type { Domain } from "@dokploy/server/services/domain"; +import { renderAsync } from "@react-email/components"; +import { format } from "date-fns"; +import { and, eq } from "drizzle-orm"; +import { + sendCustomNotification, + sendDiscordNotification, sendEmailNotification, sendGotifyNotification, sendLarkNotification, @@ -17,48 +17,48 @@ import { sendSlackNotification, sendTelegramNotification, } from "./utils"; - -interface Props { - projectName: string; - applicationName: string; - applicationType: string; - buildLink: string; - organizationId: string; - domains: Domain[]; - environmentName: string; -} - -export const sendBuildSuccessNotifications = async ({ - projectName, - applicationName, - applicationType, - buildLink, - organizationId, - domains, - environmentName, -}: Props) => { - const date = new Date(); - const unixDate = ~~(Number(date) / 1000); - const notificationList = await db.query.notifications.findMany({ - where: and( - eq(notifications.appDeploy, true), - eq(notifications.organizationId, organizationId), - ), - with: { - email: true, - discord: true, - telegram: true, - slack: true, - resend: true, - gotify: true, - ntfy: true, - custom: true, - lark: true, - pushover: true, - }, - }); - - for (const notification of notificationList) { + +interface Props { + projectName: string; + applicationName: string; + applicationType: string; + buildLink: string; + organizationId: string; + domains: Domain[]; + environmentName: string; +} + +export const sendBuildSuccessNotifications = async ({ + projectName, + applicationName, + applicationType, + buildLink, + organizationId, + domains, + environmentName, +}: Props) => { + const date = new Date(); + const unixDate = ~~(Number(date) / 1000); + const notificationList = await db.query.notifications.findMany({ + where: and( + eq(notifications.appDeploy, true), + eq(notifications.organizationId, organizationId), + ), + with: { + email: true, + discord: true, + telegram: true, + slack: true, + resend: true, + gotify: true, + ntfy: true, + custom: true, + lark: true, + pushover: true, + }, + }); + + for (const notification of notificationList) { const { email, resend, @@ -71,333 +71,333 @@ export const sendBuildSuccessNotifications = async ({ lark, pushover, } = notification; - try { - if (email || resend) { - const template = await renderAsync( - BuildSuccessEmail({ - projectName, - applicationName, - applicationType, - buildLink, - date: date.toLocaleString(), - environmentName, - }), - ).catch(); - - if (email) { - await sendEmailNotification( - email, - "Build success for dokploy", - template, - ); - } - - if (resend) { - await sendResendNotification( - resend, - "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), - ); - - 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 (custom) { - await sendCustomNotification(custom, { - title: "Build Success", - message: "Build completed successfully", - projectName, - applicationName, - applicationType, - buildLink, - timestamp: date.toISOString(), - date: date.toLocaleString(), - domains: domains.map((domain) => domain.host).join(", "), - status: "success", - type: "build", - }); - } - - 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, - }, - ], - }, - { - tag: "button", - text: { - tag: "plain_text", - content: "View Build Details", - }, - type: "primary", - width: "default", - size: "medium", - behaviors: [ - { - type: "open_url", - default_url: buildLink, - pc_url: "", - ios_url: "", - android_url: "", - }, - ], - margin: "0px 0px 0px 0px", - }, - ], - }, - }, - }); - } - - if (pushover) { - await sendPushoverNotification( - pushover, - "Build Success", - `Project: ${projectName}\nApplication: ${applicationName}\nEnvironment: ${environmentName}\nType: ${applicationType}\nDate: ${date.toLocaleString()}`, - ); - } - } catch (error) { - console.log(error); - } - } -}; + try { + if (email || resend) { + const template = await renderAsync( + BuildSuccessEmail({ + projectName, + applicationName, + applicationType, + buildLink, + date: date.toLocaleString(), + environmentName, + }), + ).catch(); + + if (email) { + await sendEmailNotification( + email, + "Build success for dokploy", + template, + ); + } + + if (resend) { + await sendResendNotification( + resend, + "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), + ); + + 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 (custom) { + await sendCustomNotification(custom, { + title: "Build Success", + message: "Build completed successfully", + projectName, + applicationName, + applicationType, + buildLink, + timestamp: date.toISOString(), + date: date.toLocaleString(), + domains: domains.map((domain) => domain.host).join(", "), + status: "success", + type: "build", + }); + } + + 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, + }, + ], + }, + { + tag: "button", + text: { + tag: "plain_text", + content: "View Build Details", + }, + type: "primary", + width: "default", + size: "medium", + behaviors: [ + { + type: "open_url", + default_url: buildLink, + pc_url: "", + ios_url: "", + android_url: "", + }, + ], + margin: "0px 0px 0px 0px", + }, + ], + }, + }, + }); + } + + if (pushover) { + await sendPushoverNotification( + pushover, + "Build Success", + `Project: ${projectName}\nApplication: ${applicationName}\nEnvironment: ${environmentName}\nType: ${applicationType}\nDate: ${date.toLocaleString()}`, + ); + } + } 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 2c9e5b78e..40162f6bb 100644 --- a/packages/server/src/utils/notifications/database-backup.ts +++ b/packages/server/src/utils/notifications/database-backup.ts @@ -1,12 +1,12 @@ -import { db } from "@dokploy/server/db"; -import { notifications } from "@dokploy/server/db/schema"; -import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup"; -import { renderAsync } from "@react-email/components"; -import { format } from "date-fns"; -import { and, eq } from "drizzle-orm"; -import { - sendCustomNotification, - sendDiscordNotification, +import { db } from "@dokploy/server/db"; +import { notifications } from "@dokploy/server/db/schema"; +import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup"; +import { renderAsync } from "@react-email/components"; +import { format } from "date-fns"; +import { and, eq } from "drizzle-orm"; +import { + sendCustomNotification, + sendDiscordNotification, sendEmailNotification, sendGotifyNotification, sendLarkNotification, @@ -16,46 +16,46 @@ import { sendSlackNotification, sendTelegramNotification, } from "./utils"; - -export const sendDatabaseBackupNotifications = async ({ - projectName, - applicationName, - databaseType, - type, - errorMessage, - organizationId, - databaseName, -}: { - projectName: string; - applicationName: string; - databaseType: "postgres" | "mysql" | "mongodb" | "mariadb"; - type: "error" | "success"; - organizationId: string; - errorMessage?: string; - databaseName: string; -}) => { - const date = new Date(); - const unixDate = ~~(Number(date) / 1000); - const notificationList = await db.query.notifications.findMany({ - where: and( - eq(notifications.databaseBackup, true), - eq(notifications.organizationId, organizationId), - ), - with: { - email: true, - discord: true, - telegram: true, - slack: true, - resend: true, - gotify: true, - ntfy: true, - custom: true, - lark: true, - pushover: true, - }, - }); - - for (const notification of notificationList) { + +export const sendDatabaseBackupNotifications = async ({ + projectName, + applicationName, + databaseType, + type, + errorMessage, + organizationId, + databaseName, +}: { + projectName: string; + applicationName: string; + databaseType: "postgres" | "mysql" | "mongodb" | "mariadb"; + type: "error" | "success"; + organizationId: string; + errorMessage?: string; + databaseName: string; +}) => { + const date = new Date(); + const unixDate = ~~(Number(date) / 1000); + const notificationList = await db.query.notifications.findMany({ + where: and( + eq(notifications.databaseBackup, true), + eq(notifications.organizationId, organizationId), + ), + with: { + email: true, + discord: true, + telegram: true, + slack: true, + resend: true, + gotify: true, + ntfy: true, + custom: true, + lark: true, + pushover: true, + }, + }); + + for (const notification of notificationList) { const { email, resend, @@ -68,350 +68,350 @@ export const sendDatabaseBackupNotifications = async ({ lark, pushover, } = notification; - try { - if (email || resend) { - const template = await renderAsync( - DatabaseBackupEmail({ - projectName, - applicationName, - databaseType, - type, - errorMessage, - date: date.toLocaleString(), - }), - ).catch(); - - if (email) { - await sendEmailNotification( - email, - "Database backup for dokploy", - template, - ); - } - - if (resend) { - await sendResendNotification( - resend, - "Database backup for dokploy", - template, - ); - } - } - - 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", - }, - }); - } - - 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}`) : ""}`, - ); - } - - 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; - - 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 : ""}`; - - 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 (custom) { - await sendCustomNotification(custom, { - title: `Database Backup ${type === "success" ? "Successful" : "Failed"}`, - message: - type === "success" - ? "Database backup completed successfully" - : "Database backup failed", - projectName, - applicationName, - databaseType, - databaseName, - type, - errorMessage: errorMessage || "", - timestamp: date.toISOString(), - date: date.toLocaleString(), - status: type, - }); - } - - 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", - }, - }, - }, - }, - 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, - }, - ], - }, - ...(type === "error" && truncatedErrorMessage - ? [ - { - tag: "markdown", - content: `**Error Message:**\n\`\`\`\n${truncatedErrorMessage}\n\`\`\``, - text_align: "left", - text_size: "normal_v2", - }, - ] - : []), - ], - }, - }, - }); - } - - if (pushover) { - await sendPushoverNotification( - pushover, - `Database Backup ${type === "success" ? "Successful" : "Failed"}`, - `Project: ${projectName}\nApplication: ${applicationName}\nDatabase: ${databaseType}\nDatabase Name: ${databaseName}\nDate: ${date.toLocaleString()}${type === "error" && errorMessage ? `\nError: ${errorMessage}` : ""}`, - ); - } - } catch (error) { - console.log(error); - } - } -}; + try { + if (email || resend) { + const template = await renderAsync( + DatabaseBackupEmail({ + projectName, + applicationName, + databaseType, + type, + errorMessage, + date: date.toLocaleString(), + }), + ).catch(); + + if (email) { + await sendEmailNotification( + email, + "Database backup for dokploy", + template, + ); + } + + if (resend) { + await sendResendNotification( + resend, + "Database backup for dokploy", + template, + ); + } + } + + 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", + }, + }); + } + + 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}`) : ""}`, + ); + } + + 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; + + 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 : ""}`; + + 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 (custom) { + await sendCustomNotification(custom, { + title: `Database Backup ${type === "success" ? "Successful" : "Failed"}`, + message: + type === "success" + ? "Database backup completed successfully" + : "Database backup failed", + projectName, + applicationName, + databaseType, + databaseName, + type, + errorMessage: errorMessage || "", + timestamp: date.toISOString(), + date: date.toLocaleString(), + status: type, + }); + } + + 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", + }, + }, + }, + }, + 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, + }, + ], + }, + ...(type === "error" && truncatedErrorMessage + ? [ + { + tag: "markdown", + content: `**Error Message:**\n\`\`\`\n${truncatedErrorMessage}\n\`\`\``, + text_align: "left", + text_size: "normal_v2", + }, + ] + : []), + ], + }, + }, + }); + } + + if (pushover) { + await sendPushoverNotification( + pushover, + `Database Backup ${type === "success" ? "Successful" : "Failed"}`, + `Project: ${projectName}\nApplication: ${applicationName}\nDatabase: ${databaseType}\nDatabase Name: ${databaseName}\nDate: ${date.toLocaleString()}${type === "error" && errorMessage ? `\nError: ${errorMessage}` : ""}`, + ); + } + } 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 0646a2b64..e22d47ffb 100644 --- a/packages/server/src/utils/notifications/docker-cleanup.ts +++ b/packages/server/src/utils/notifications/docker-cleanup.ts @@ -1,12 +1,12 @@ -import { db } from "@dokploy/server/db"; -import { notifications } from "@dokploy/server/db/schema"; -import DockerCleanupEmail from "@dokploy/server/emails/emails/docker-cleanup"; -import { renderAsync } from "@react-email/components"; -import { format } from "date-fns"; -import { and, eq } from "drizzle-orm"; -import { - sendCustomNotification, - sendDiscordNotification, +import { db } from "@dokploy/server/db"; +import { notifications } from "@dokploy/server/db/schema"; +import DockerCleanupEmail from "@dokploy/server/emails/emails/docker-cleanup"; +import { renderAsync } from "@react-email/components"; +import { format } from "date-fns"; +import { and, eq } from "drizzle-orm"; +import { + sendCustomNotification, + sendDiscordNotification, sendEmailNotification, sendGotifyNotification, sendLarkNotification, @@ -16,33 +16,33 @@ import { sendSlackNotification, sendTelegramNotification, } from "./utils"; - -export const sendDockerCleanupNotifications = async ( - organizationId: string, - message = "Docker cleanup for dokploy", -) => { - const date = new Date(); - const unixDate = ~~(Number(date) / 1000); - const notificationList = await db.query.notifications.findMany({ - where: and( - eq(notifications.dockerCleanup, true), - eq(notifications.organizationId, organizationId), - ), - with: { - email: true, - discord: true, - telegram: true, - slack: true, - resend: true, - gotify: true, - ntfy: true, - custom: true, - lark: true, - pushover: true, - }, - }); - - for (const notification of notificationList) { + +export const sendDockerCleanupNotifications = async ( + organizationId: string, + message = "Docker cleanup for dokploy", +) => { + const date = new Date(); + const unixDate = ~~(Number(date) / 1000); + const notificationList = await db.query.notifications.findMany({ + where: and( + eq(notifications.dockerCleanup, true), + eq(notifications.organizationId, organizationId), + ), + with: { + email: true, + discord: true, + telegram: true, + slack: true, + resend: true, + gotify: true, + ntfy: true, + custom: true, + lark: true, + pushover: true, + }, + }); + + for (const notification of notificationList) { const { email, resend, @@ -55,215 +55,215 @@ export const sendDockerCleanupNotifications = async ( lark, pushover, } = notification; - try { - if (email || resend) { - const template = await renderAsync( - DockerCleanupEmail({ message, date: date.toLocaleString() }), - ).catch(); - - if (email) { - await sendEmailNotification( - email, - "Docker cleanup for dokploy", - template, - ); - } - - if (resend) { - await sendResendNotification( - resend, - "Docker cleanup for dokploy", - template, - ); - } - } - - 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, - }, - { - 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 (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 (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 (custom) { - await sendCustomNotification(custom, { - title: "Docker Cleanup", - message: "Docker cleanup completed successfully", - cleanupMessage: message, - timestamp: date.toISOString(), - date: date.toLocaleString(), - status: "success", - type: "docker-cleanup", - }); - } - - 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, - }, - ], - }, - ], - }, - }, - }); - } - - if (pushover) { - await sendPushoverNotification( - pushover, - "Docker Cleanup", - `Date: ${date.toLocaleString()}\nMessage: ${message}`, - ); - } - } catch (error) { - console.log(error); - } - } -}; + try { + if (email || resend) { + const template = await renderAsync( + DockerCleanupEmail({ message, date: date.toLocaleString() }), + ).catch(); + + if (email) { + await sendEmailNotification( + email, + "Docker cleanup for dokploy", + template, + ); + } + + if (resend) { + await sendResendNotification( + resend, + "Docker cleanup for dokploy", + template, + ); + } + } + + 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, + }, + { + 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 (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 (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 (custom) { + await sendCustomNotification(custom, { + title: "Docker Cleanup", + message: "Docker cleanup completed successfully", + cleanupMessage: message, + timestamp: date.toISOString(), + date: date.toLocaleString(), + status: "success", + type: "docker-cleanup", + }); + } + + 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, + }, + ], + }, + ], + }, + }, + }); + } + + if (pushover) { + await sendPushoverNotification( + pushover, + "Docker Cleanup", + `Date: ${date.toLocaleString()}\nMessage: ${message}`, + ); + } + } 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 6526fb222..75188988c 100644 --- a/packages/server/src/utils/notifications/dokploy-restart.ts +++ b/packages/server/src/utils/notifications/dokploy-restart.ts @@ -1,12 +1,12 @@ -import { db } from "@dokploy/server/db"; -import { notifications } from "@dokploy/server/db/schema"; -import DokployRestartEmail from "@dokploy/server/emails/emails/dokploy-restart"; -import { renderAsync } from "@react-email/components"; -import { format } from "date-fns"; -import { eq } from "drizzle-orm"; -import { - sendCustomNotification, - sendDiscordNotification, +import { db } from "@dokploy/server/db"; +import { notifications } from "@dokploy/server/db/schema"; +import DokployRestartEmail from "@dokploy/server/emails/emails/dokploy-restart"; +import { renderAsync } from "@react-email/components"; +import { format } from "date-fns"; +import { eq } from "drizzle-orm"; +import { + sendCustomNotification, + sendDiscordNotification, sendEmailNotification, sendGotifyNotification, sendLarkNotification, @@ -16,27 +16,27 @@ import { sendSlackNotification, sendTelegramNotification, } from "./utils"; - -export const sendDokployRestartNotifications = async () => { - const date = new Date(); - const unixDate = ~~(Number(date) / 1000); - const notificationList = await db.query.notifications.findMany({ - where: eq(notifications.dokployRestart, true), - with: { - email: true, - discord: true, - telegram: true, - slack: true, - resend: true, - gotify: true, - ntfy: true, - custom: true, - lark: true, - pushover: true, - }, - }); - - for (const notification of notificationList) { + +export const sendDokployRestartNotifications = async () => { + const date = new Date(); + const unixDate = ~~(Number(date) / 1000); + const notificationList = await db.query.notifications.findMany({ + where: eq(notifications.dokployRestart, true), + with: { + email: true, + discord: true, + telegram: true, + slack: true, + resend: true, + gotify: true, + ntfy: true, + custom: true, + lark: true, + pushover: true, + }, + }); + + for (const notification of notificationList) { const { email, resend, @@ -49,210 +49,210 @@ export const sendDokployRestartNotifications = async () => { lark, pushover, } = notification; - - try { - if (email || resend) { - const template = await renderAsync( - DokployRestartEmail({ date: date.toLocaleString() }), - ).catch(); - - if (email) { - await sendEmailNotification( - email, - "Dokploy Server Restarted", - template, - ); - } - - if (resend) { - await sendResendNotification( - resend, - "Dokploy Server Restarted", - template, - ); - } - } - - if (discord) { - const decorate = (decoration: string, text: string) => - `${discord.decoration ? decoration : ""} ${text}`.trim(); - - await sendDiscordNotification(discord, { - title: decorate(">", "`✅` Dokploy Server Restarted"), - color: 0x57f287, - fields: [ - { - name: decorate("`📅`", "Date"), - value: ``, - inline: true, - }, - { - name: decorate("`⌚`", "Time"), - value: ``, - inline: true, - }, - { - name: decorate("`❓`", "Type"), - value: "Successful", - inline: true, - }, - ], - timestamp: date.toISOString(), - footer: { - text: "Dokploy Restart Notification", - }, - }); - } - - if (gotify) { - const decorate = (decoration: string, text: string) => - `${gotify.decoration ? decoration : ""} ${text}\n`; - await sendGotifyNotification( - gotify, - decorate("✅", "Dokploy Server Restarted"), - `${decorate("🕒", `Date: ${date.toLocaleString()}`)}`, - ); - } - - if (ntfy) { - await sendNtfyNotification( - ntfy, - "Dokploy Server Restarted", - "white_check_mark", - "", - `🕒Date: ${date.toLocaleString()}`, - ); - } - - if (telegram) { - await sendTelegramNotification( - telegram, - `✅ Dokploy Server Restarted\n\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: *Dokploy Server Restarted*", - fields: [ - { - title: "Time", - value: date.toLocaleString(), - short: true, - }, - ], - }, - ], - }); - } - - if (custom) { - try { - await sendCustomNotification(custom, { - title: "Dokploy Server Restarted", - message: "Dokploy server has been restarted successfully", - timestamp: date.toISOString(), - date: date.toLocaleString(), - status: "success", - type: "dokploy-restart", - }); - } catch (error) { - console.log(error); - } - } - - 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: "✅ Dokploy Server Restarted", - }, - 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", - }, - ], - vertical_align: "top", - weight: 1, - }, - { - tag: "column", - width: "weighted", - elements: [ - { - tag: "markdown", - content: `**Restart Time:**\n${format( - date, - "PP pp", - )}`, - text_align: "left", - text_size: "normal_v2", - }, - ], - vertical_align: "top", - weight: 1, - }, - ], - }, - ], - }, - }, - }); - } - - if (pushover) { - await sendPushoverNotification( - pushover, - "Dokploy Server Restarted", - `Date: ${date.toLocaleString()}`, - ); - } - } catch (error) { - console.log(error); - } - } -}; + + try { + if (email || resend) { + const template = await renderAsync( + DokployRestartEmail({ date: date.toLocaleString() }), + ).catch(); + + if (email) { + await sendEmailNotification( + email, + "Dokploy Server Restarted", + template, + ); + } + + if (resend) { + await sendResendNotification( + resend, + "Dokploy Server Restarted", + template, + ); + } + } + + if (discord) { + const decorate = (decoration: string, text: string) => + `${discord.decoration ? decoration : ""} ${text}`.trim(); + + await sendDiscordNotification(discord, { + title: decorate(">", "`✅` Dokploy Server Restarted"), + color: 0x57f287, + fields: [ + { + name: decorate("`📅`", "Date"), + value: ``, + inline: true, + }, + { + name: decorate("`⌚`", "Time"), + value: ``, + inline: true, + }, + { + name: decorate("`❓`", "Type"), + value: "Successful", + inline: true, + }, + ], + timestamp: date.toISOString(), + footer: { + text: "Dokploy Restart Notification", + }, + }); + } + + if (gotify) { + const decorate = (decoration: string, text: string) => + `${gotify.decoration ? decoration : ""} ${text}\n`; + await sendGotifyNotification( + gotify, + decorate("✅", "Dokploy Server Restarted"), + `${decorate("🕒", `Date: ${date.toLocaleString()}`)}`, + ); + } + + if (ntfy) { + await sendNtfyNotification( + ntfy, + "Dokploy Server Restarted", + "white_check_mark", + "", + `🕒Date: ${date.toLocaleString()}`, + ); + } + + if (telegram) { + await sendTelegramNotification( + telegram, + `✅ Dokploy Server Restarted\n\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: *Dokploy Server Restarted*", + fields: [ + { + title: "Time", + value: date.toLocaleString(), + short: true, + }, + ], + }, + ], + }); + } + + if (custom) { + try { + await sendCustomNotification(custom, { + title: "Dokploy Server Restarted", + message: "Dokploy server has been restarted successfully", + timestamp: date.toISOString(), + date: date.toLocaleString(), + status: "success", + type: "dokploy-restart", + }); + } catch (error) { + console.log(error); + } + } + + 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: "✅ Dokploy Server Restarted", + }, + 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", + }, + ], + vertical_align: "top", + weight: 1, + }, + { + tag: "column", + width: "weighted", + elements: [ + { + tag: "markdown", + content: `**Restart Time:**\n${format( + date, + "PP pp", + )}`, + text_align: "left", + text_size: "normal_v2", + }, + ], + vertical_align: "top", + weight: 1, + }, + ], + }, + ], + }, + }, + }); + } + + if (pushover) { + await sendPushoverNotification( + pushover, + "Dokploy Server Restarted", + `Date: ${date.toLocaleString()}`, + ); + } + } catch (error) { + console.log(error); + } + } +};