diff --git a/components/dashboard/settings/notifications/update-notification.tsx b/components/dashboard/settings/notifications/update-notification.tsx index 0ab2b127..695ca8ed 100644 --- a/components/dashboard/settings/notifications/update-notification.tsx +++ b/components/dashboard/settings/notifications/update-notification.tsx @@ -398,7 +398,19 @@ export const UpdateNotification = ({ notificationId }: Props) => { SMTP Port - + { + const value = e.target.value; + if (value) { + const port = Number.parseInt(value); + if (port > 0 && port < 65536) { + field.onChange(port); + } + } + }} + /> diff --git a/server/api/services/application.ts b/server/api/services/application.ts index c757f80b..e407b098 100644 --- a/server/api/services/application.ts +++ b/server/api/services/application.ts @@ -18,7 +18,7 @@ import { getAdvancedStats } from "@/server/monitoring/utilts"; import { validUniqueServerAppName } from "./project"; import { generatePassword } from "@/templates/utils"; import { generateAppName } from "@/server/db/schema/utils"; -import { sendBuildFailedEmail } from "./notification"; +import { sendBuildErrorNotifications } from "./notification"; export type Application = typeof applications.$inferSelect; export const createApplication = async ( @@ -161,7 +161,7 @@ export const deployApplication = async ({ console.log("Error on build", error); await updateDeploymentStatus(deployment.deploymentId, "error"); await updateApplicationStatus(applicationId, "error"); - await sendBuildFailedEmail({ + await sendBuildErrorNotifications({ projectName: application.project.name, applicationName: application.appName, applicationType: "application", diff --git a/server/api/services/notification.ts b/server/api/services/notification.ts index ca926adf..d481ac13 100644 --- a/server/api/services/notification.ts +++ b/server/api/services/notification.ts @@ -507,38 +507,6 @@ export const sendEmailTestNotification = async ( console.log("Email notification sent successfully"); }; -// export const sendInvitationEmail = async ( -// emailTestConnection: typeof apiTestEmailConnection._type, -// inviteLink: string, -// toEmail: string, -// ) => { -// const { smtpServer, smtpPort, username, password, fromAddress } = -// emailTestConnection; -// const transporter = nodemailer.createTransport({ -// host: smtpServer, -// port: smtpPort, -// secure: smtpPort === 465, -// auth: { -// user: username, -// pass: password, -// }, -// } as SMTPTransport.Options); -// // need to add a valid from address -// const mailOptions = { -// from: fromAddress, -// to: toEmail, -// subject: "Invitation to join Dokploy", -// html: InvitationTemplate({ -// inviteLink: inviteLink, -// toEmail: toEmail, -// }), -// }; - -// await transporter.sendMail(mailOptions); - -// console.log("Email notification sent successfully"); -// }; - export const sendBuildFailedEmail = async ({ projectName, applicationName, @@ -600,3 +568,210 @@ export const sendBuildFailedEmail = async ({ } } }; + +// export const + +export const sendBuildErrorNotifications = async ({ + projectName, + applicationName, + applicationType, + errorMessage, + buildLink, +}: { + projectName: string; + applicationName: string; + applicationType: string; + errorMessage: string; + buildLink: string; +}) => { + const date = new Date(); + const notificationList = await db.query.notifications.findMany({ + where: eq(notifications.appBuildError, true), + with: { + email: true, + discord: true, + telegram: true, + slack: true, + }, + }); + + for (const notification of notificationList) { + const { email, discord, telegram, slack } = notification; + if (email) { + const { + smtpServer, + smtpPort, + username, + password, + fromAddress, + toAddresses, + } = email; + const transporter = nodemailer.createTransport({ + host: smtpServer, + port: smtpPort, + secure: smtpPort === 465, + auth: { + user: username, + pass: password, + }, + } as SMTPTransport.Options); + const mailOptions = { + from: fromAddress, + to: toAddresses?.join(", "), + subject: "Build failed for dokploy", + html: render( + BuildFailedEmail({ + projectName, + applicationName, + applicationType, + errorMessage, + buildLink, + }), + ), + }; + await transporter.sendMail(mailOptions); + } + + if (discord) { + const { webhookUrl } = discord; + const embed = { + title: "⚠️ Build Failed", + color: 0xff0000, // Rojo + fields: [ + { + name: "Project", + value: projectName, + inline: true, + }, + { + name: "Application", + value: applicationName, + inline: true, + }, + { + name: "Type", + value: applicationType, + inline: true, + }, + { + name: "Error", + value: errorMessage, + }, + { + name: "Build Link", + value: buildLink, + }, + ], + timestamp: date.toISOString(), + footer: { + text: "Dokploy Build Notification", + }, + }; + const response = await fetch(webhookUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + embeds: [embed], + }), + }); + + if (!response.ok) { + throw new Error("Error to send test notification"); + } + } + + if (telegram) { + const { botToken, chatId } = telegram; + const messageText = ` + ⚠️ Build Failed + + Project: ${projectName} + Application: ${applicationName} + Type: ${applicationType} + Time: ${date.toLocaleString()} + + Error: +
${errorMessage}
+ + Build Details: ${buildLink} + `; + const url = `https://api.telegram.org/bot${botToken}/sendMessage`; + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + chat_id: chatId, + text: messageText, + parse_mode: "HTML", + disable_web_page_preview: true, + }), + }); + + if (!response.ok) { + throw new Error("Error to send test notification"); + } + } + + if (slack) { + const { webhookUrl, channel } = slack; + const message = { + 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: "https://doks.dev/build-details", + }, + ], + }, + ], + }; + const response = await fetch(webhookUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(message), + }); + + if (!response.ok) { + throw new Error("Error to send test notification"); + } + } + } +};