mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-04 13:35:22 +02:00
feat(volume-backup): add volume backup email notification template and integrate with notification system
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { db } from "@dokploy/server/db";
|
||||
import { notifications } from "@dokploy/server/db/schema";
|
||||
import { VolumeBackupEmail } from "@dokploy/server/emails/emails/volume-backup";
|
||||
import { renderAsync } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
@@ -60,25 +61,18 @@ export const sendVolumeBackupNotifications = async ({
|
||||
|
||||
if (email) {
|
||||
const subject = `Volume Backup ${type === "success" ? "Successful" : "Failed"} - ${applicationName}`;
|
||||
const htmlContent = `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2 style="color: ${type === "success" ? "#00AA00" : "#AA0000"};">
|
||||
${type === "success" ? "✅" : "❌"} Volume Backup ${type === "success" ? "Successful" : "Failed"}
|
||||
</h2>
|
||||
<div style="background-color: #f5f5f5; padding: 20px; border-radius: 5px; margin: 20px 0;">
|
||||
<p><strong>Project:</strong> ${projectName}</p>
|
||||
<p><strong>Application:</strong> ${applicationName}</p>
|
||||
<p><strong>Volume Name:</strong> ${volumeName}</p>
|
||||
<p><strong>Service Type:</strong> ${serviceType}</p>
|
||||
${backupSize ? `<p><strong>Backup Size:</strong> ${backupSize}</p>` : ""}
|
||||
<p><strong>Date:</strong> ${date.toLocaleString()}</p>
|
||||
${type === "error" && errorMessage ? `<p><strong>Error:</strong> <code>${errorMessage}</code></p>` : ""}
|
||||
</div>
|
||||
<p style="color: #666; font-size: 12px;">
|
||||
This notification was sent by Dokploy Volume Backup System.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
const htmlContent = await renderAsync(
|
||||
VolumeBackupEmail({
|
||||
projectName,
|
||||
applicationName,
|
||||
volumeName,
|
||||
serviceType,
|
||||
type,
|
||||
errorMessage,
|
||||
backupSize,
|
||||
date: date.toISOString(),
|
||||
}),
|
||||
);
|
||||
await sendEmailNotification(email, subject, htmlContent);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,51 @@ import { getS3Credentials, normalizeS3Path } from "../backups/utils";
|
||||
import { sendVolumeBackupNotifications } from "../notifications/volume-backup";
|
||||
import { backupVolume } from "./backup";
|
||||
|
||||
// Helper functions to extract project info from volume backup
|
||||
const getProjectName = (
|
||||
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
|
||||
): string => {
|
||||
const services = [
|
||||
volumeBackup.application,
|
||||
volumeBackup.compose,
|
||||
volumeBackup.postgres,
|
||||
volumeBackup.mysql,
|
||||
volumeBackup.mariadb,
|
||||
volumeBackup.mongo,
|
||||
volumeBackup.redis,
|
||||
];
|
||||
|
||||
for (const service of services) {
|
||||
if (service?.environment?.project?.name) {
|
||||
return service.environment.project.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown Project";
|
||||
};
|
||||
|
||||
const getOrganizationId = (
|
||||
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
|
||||
): string => {
|
||||
const services = [
|
||||
volumeBackup.application,
|
||||
volumeBackup.compose,
|
||||
volumeBackup.postgres,
|
||||
volumeBackup.mysql,
|
||||
volumeBackup.mariadb,
|
||||
volumeBackup.mongo,
|
||||
volumeBackup.redis,
|
||||
];
|
||||
|
||||
for (const service of services) {
|
||||
if (service?.environment?.project?.organizationId) {
|
||||
return service.environment.project.organizationId;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
export const scheduleVolumeBackup = async (volumeBackupId: string) => {
|
||||
const volumeBackup = await findVolumeBackupById(volumeBackupId);
|
||||
scheduleJob(volumeBackupId, volumeBackup.cronExpression, async () => {
|
||||
@@ -62,7 +107,8 @@ export const runVolumeBackup = async (volumeBackupId: string) => {
|
||||
title: "Volume Backup",
|
||||
description: "Volume Backup",
|
||||
});
|
||||
|
||||
const projectName = getProjectName(volumeBackup);
|
||||
const organizationId = getOrganizationId(volumeBackup);
|
||||
try {
|
||||
const command = await backupVolume(volumeBackup);
|
||||
|
||||
@@ -79,55 +125,20 @@ export const runVolumeBackup = async (volumeBackupId: string) => {
|
||||
|
||||
await updateDeploymentStatus(deployment.deploymentId, "done");
|
||||
|
||||
// Send success notification
|
||||
try {
|
||||
const projectName =
|
||||
volumeBackup.application?.environment?.project?.name ||
|
||||
volumeBackup.compose?.environment?.project?.name ||
|
||||
volumeBackup.postgres?.environment?.project?.name ||
|
||||
volumeBackup.mysql?.environment?.project?.name ||
|
||||
volumeBackup.mariadb?.environment?.project?.name ||
|
||||
volumeBackup.mongo?.environment?.project?.name ||
|
||||
volumeBackup.redis?.environment?.project?.name ||
|
||||
"Unknown Project";
|
||||
// Map service type to match notification function expectations
|
||||
const mappedServiceType =
|
||||
volumeBackup.serviceType === "mongo"
|
||||
? "mongodb"
|
||||
: volumeBackup.serviceType;
|
||||
|
||||
const organizationId =
|
||||
volumeBackup.application?.environment?.project?.organizationId ||
|
||||
volumeBackup.compose?.environment?.project?.organizationId ||
|
||||
volumeBackup.postgres?.environment?.project?.organizationId ||
|
||||
volumeBackup.mysql?.environment?.project?.organizationId ||
|
||||
volumeBackup.mariadb?.environment?.project?.organizationId ||
|
||||
volumeBackup.mongo?.environment?.project?.organizationId ||
|
||||
volumeBackup.redis?.environment?.project?.organizationId ||
|
||||
"";
|
||||
|
||||
// Map service type to match notification function expectations
|
||||
const mappedServiceType =
|
||||
volumeBackup.serviceType === "mongo"
|
||||
? "mongodb"
|
||||
: volumeBackup.serviceType;
|
||||
|
||||
await sendVolumeBackupNotifications({
|
||||
projectName,
|
||||
applicationName: volumeBackup.name,
|
||||
volumeName: volumeBackup.volumeName,
|
||||
serviceType: mappedServiceType as
|
||||
| "application"
|
||||
| "postgres"
|
||||
| "mysql"
|
||||
| "mongodb"
|
||||
| "mariadb"
|
||||
| "redis"
|
||||
| "compose",
|
||||
type: "success",
|
||||
organizationId,
|
||||
});
|
||||
} catch (notificationError) {
|
||||
console.error(
|
||||
"Failed to send volume backup success notification:",
|
||||
notificationError,
|
||||
);
|
||||
}
|
||||
await sendVolumeBackupNotifications({
|
||||
projectName,
|
||||
applicationName: volumeBackup.name,
|
||||
volumeName: volumeBackup.volumeName,
|
||||
serviceType: mappedServiceType,
|
||||
type: "success",
|
||||
organizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
const { VOLUME_BACKUPS_PATH } = paths(!!serverId);
|
||||
const volumeBackupPath = path.join(
|
||||
@@ -144,56 +155,19 @@ export const runVolumeBackup = async (volumeBackupId: string) => {
|
||||
await updateDeploymentStatus(deployment.deploymentId, "error");
|
||||
|
||||
// Send error notification
|
||||
try {
|
||||
const projectName =
|
||||
volumeBackup.application?.environment?.project?.name ||
|
||||
volumeBackup.compose?.environment?.project?.name ||
|
||||
volumeBackup.postgres?.environment?.project?.name ||
|
||||
volumeBackup.mysql?.environment?.project?.name ||
|
||||
volumeBackup.mariadb?.environment?.project?.name ||
|
||||
volumeBackup.mongo?.environment?.project?.name ||
|
||||
volumeBackup.redis?.environment?.project?.name ||
|
||||
"Unknown Project";
|
||||
const mappedServiceType =
|
||||
volumeBackup.serviceType === "mongo"
|
||||
? "mongodb"
|
||||
: volumeBackup.serviceType;
|
||||
|
||||
const organizationId =
|
||||
volumeBackup.application?.environment?.project?.organizationId ||
|
||||
volumeBackup.compose?.environment?.project?.organizationId ||
|
||||
volumeBackup.postgres?.environment?.project?.organizationId ||
|
||||
volumeBackup.mysql?.environment?.project?.organizationId ||
|
||||
volumeBackup.mariadb?.environment?.project?.organizationId ||
|
||||
volumeBackup.mongo?.environment?.project?.organizationId ||
|
||||
volumeBackup.redis?.environment?.project?.organizationId ||
|
||||
"";
|
||||
|
||||
// Map service type to match notification function expectations
|
||||
const mappedServiceType =
|
||||
volumeBackup.serviceType === "mongo"
|
||||
? "mongodb"
|
||||
: volumeBackup.serviceType;
|
||||
|
||||
await sendVolumeBackupNotifications({
|
||||
projectName,
|
||||
applicationName: volumeBackup.name,
|
||||
volumeName: volumeBackup.volumeName,
|
||||
serviceType: mappedServiceType as
|
||||
| "application"
|
||||
| "postgres"
|
||||
| "mysql"
|
||||
| "mongodb"
|
||||
| "mariadb"
|
||||
| "redis"
|
||||
| "compose",
|
||||
type: "error",
|
||||
organizationId,
|
||||
errorMessage: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
} catch (notificationError) {
|
||||
console.error(
|
||||
"Failed to send volume backup error notification:",
|
||||
notificationError,
|
||||
);
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
await sendVolumeBackupNotifications({
|
||||
projectName,
|
||||
applicationName: volumeBackup.name,
|
||||
volumeName: volumeBackup.volumeName,
|
||||
serviceType: mappedServiceType,
|
||||
type: "error",
|
||||
organizationId,
|
||||
errorMessage: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user