462 lines · 12.1 KB · TypeScript
RawDownload
import { db } from "@dokploy/server/db";import { notifications } from "@dokploy/server/db/schema";import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup";import { render } from "@react-email/components";import { format } from "date-fns";import { and, eq } from "drizzle-orm";import {	sendCustomNotification,	sendDiscordNotification,	sendEmailNotification,	sendGotifyNotification,	sendLarkNotification,	sendMattermostNotification,	sendNtfyNotification,	sendPushoverNotification,	sendResendNotification,	sendSlackNotification,	sendTeamsNotification,	sendTelegramNotification,} from "./utils"; export const sendDatabaseBackupNotifications = async ({	projectName,	applicationName,	databaseType,	type,	errorMessage,	organizationId,	databaseName,}: {	projectName: string;	applicationName: string;	databaseType: "postgres" | "mysql" | "mongodb" | "mariadb" | "libsql";	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,			mattermost: true,			custom: true,			lark: true,			pushover: true,			teams: true,		},	}); 	for (const notification of notificationList) {		const {			email,			resend,			discord,			telegram,			slack,			gotify,			ntfy,			mattermost,			custom,			lark,			pushover,			teams,		} = notification;		try {			if (email || resend) {				const template = await render(					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: `<t:${unixDate}:D>`,							inline: true,						},						{							name: decorate("`⌚`", "Time"),							value: `<t:${unixDate}:t>`,							inline: true,						},						{							name: decorate("`❓`", "Type"),							value: type								.replace("error", "Failed")								.replace("success", "Successful"),							inline: true,						},						...(type === "error" && errorMessage							? [									{										name: decorate("`⚠️`", "Error Message"),										value: `\`\`\`${errorMessage.length > 1010 ? `${errorMessage.substring(0, 1010)}...` : 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\n<b>Error:</b>\n<pre>${errorMessage}</pre>`					: ""; 				const messageText = `<b>${statusEmoji} Database Backup ${typeStatus}</b>\n\n<b>Project:</b> ${projectName}\n<b>Application:</b> ${applicationName}\n<b>Type:</b> ${databaseType}\n<b>Database Name:</b> ${databaseName}\n<b>Date:</b> ${format(date, "PP")}\n<b>Time:</b> ${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 (mattermost) {				const statusEmoji = type === "success" ? "✅" : "❌";				const typeStatus = type === "success" ? "Successful" : "Failed";				const errorMsg =					type === "error" && errorMessage						? `\n\n**Error:**\n\`\`\`\n${errorMessage}\n\`\`\``						: ""; 				await sendMattermostNotification(mattermost, {					text: `**${statusEmoji} Database Backup ${typeStatus}**\n\n**Project:** ${projectName}\n**Application:** ${applicationName}\n**Type:** ${databaseType}\n**Database Name:** ${databaseName}\n**Date:** ${format(date, "PP")}\n**Time:** ${format(date, "pp")}${errorMsg}`,					channel: mattermost.channel,					username: mattermost.username || "Dokploy",				});			} 			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}` : ""}`,				);			} 			if (teams) {				const facts = [					{ name: "Project", value: projectName },					{ name: "Application", value: applicationName },					{ name: "Database Type", value: databaseType },					{ name: "Database Name", value: databaseName },					{ name: "Date", value: format(date, "PP pp") },					{						name: "Status",						value: type === "success" ? "Successful" : "Failed",					},				];				if (type === "error" && errorMessage) {					facts.push({ name: "Error", value: errorMessage.substring(0, 500) });				}				await sendTeamsNotification(teams, {					title:						type === "success"							? "✅ Database Backup Successful"							: "❌ Database Backup Failed",					facts,				});			}		} catch (error) {			console.log(error);		}	}};