mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(notifications): add build failed and invitation emails from react-email
This commit is contained in:
@@ -10,11 +10,17 @@ import {
|
||||
apiCreateSlack,
|
||||
apiCreateTelegram,
|
||||
apiFindOneNotification,
|
||||
apiSendTest,
|
||||
apiUpdateDestination,
|
||||
apiTestDiscordConnection,
|
||||
apiTestEmailConnection,
|
||||
apiTestSlackConnection,
|
||||
apiTestTelegramConnection,
|
||||
apiUpdateDiscord,
|
||||
apiUpdateEmail,
|
||||
apiUpdateSlack,
|
||||
apiUpdateTelegram,
|
||||
notifications,
|
||||
} from "@/server/db/schema";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { updateDestinationById } from "../services/destination";
|
||||
import {
|
||||
createDiscordNotification,
|
||||
createEmailNotification,
|
||||
@@ -22,8 +28,16 @@ import {
|
||||
createTelegramNotification,
|
||||
findNotificationById,
|
||||
removeNotificationById,
|
||||
sendDiscordTestNotification,
|
||||
sendEmailTestNotification,
|
||||
sendSlackTestNotification,
|
||||
sendTelegramTestNotification,
|
||||
updateDiscordNotification,
|
||||
updateEmailNotification,
|
||||
updateSlackNotification,
|
||||
updateTelegramNotification,
|
||||
} from "../services/notification";
|
||||
import nodemailer from "nodemailer";
|
||||
import { desc } from "drizzle-orm";
|
||||
|
||||
export const notificationRouter = createTRPCRouter({
|
||||
createSlack: adminProcedure
|
||||
@@ -35,7 +49,34 @@ export const notificationRouter = createTRPCRouter({
|
||||
console.log(error);
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the destination",
|
||||
message: "Error to create the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
updateSlack: adminProcedure
|
||||
.input(apiUpdateSlack)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await updateSlackNotification(input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
testSlackConnection: adminProcedure
|
||||
.input(apiTestSlackConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendSlackTestNotification(input);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to test the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
@@ -48,7 +89,35 @@ export const notificationRouter = createTRPCRouter({
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the destination",
|
||||
message: "Error to create the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
updateTelegram: adminProcedure
|
||||
.input(apiUpdateTelegram)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await updateTelegramNotification(input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
testTelegramConnection: adminProcedure
|
||||
.input(apiTestTelegramConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendTelegramTestNotification(input);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to test the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
@@ -61,7 +130,36 @@ export const notificationRouter = createTRPCRouter({
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the destination",
|
||||
message: "Error to create the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
updateDiscord: adminProcedure
|
||||
.input(apiUpdateDiscord)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await updateDiscordNotification(input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
testDiscordConnection: adminProcedure
|
||||
.input(apiTestDiscordConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendDiscordTestNotification(input);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to test the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
@@ -72,9 +170,37 @@ export const notificationRouter = createTRPCRouter({
|
||||
try {
|
||||
return await createEmailNotification(input);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the destination",
|
||||
message: "Error to create the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
updateEmail: adminProcedure
|
||||
.input(apiUpdateEmail)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await updateEmailNotification(input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
testEmailConnection: adminProcedure
|
||||
.input(apiTestEmailConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendEmailTestNotification(input);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to test the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
@@ -97,127 +223,6 @@ export const notificationRouter = createTRPCRouter({
|
||||
const notification = await findNotificationById(input.notificationId);
|
||||
return notification;
|
||||
}),
|
||||
testConnection: adminProcedure
|
||||
.input(apiSendTest)
|
||||
.mutation(async ({ input }) => {
|
||||
const notificationType = input.notificationType;
|
||||
console.log(input);
|
||||
|
||||
if (notificationType === "slack") {
|
||||
// go to your slack dashboard
|
||||
// go to integrations
|
||||
// add a new integration
|
||||
// select incoming webhook
|
||||
// copy the webhook url
|
||||
console.log("test slack");
|
||||
const { webhookUrl, channel } = input;
|
||||
try {
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ text: "Test notification", channel }),
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
} else if (notificationType === "telegram") {
|
||||
// start telegram
|
||||
// search BotFather
|
||||
// send /newbot
|
||||
// name
|
||||
// name-with-bot-at-the-end
|
||||
// copy the token
|
||||
// search @userinfobot
|
||||
// send /start
|
||||
// copy the Id
|
||||
const { botToken, chatId } = input;
|
||||
try {
|
||||
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: "Test notification",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Error sending Telegram notification: ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Telegram notification sent successfully");
|
||||
} catch (error) {
|
||||
console.error("Error sending Telegram notification:", error);
|
||||
throw new Error("Error sending Telegram notification");
|
||||
}
|
||||
} else if (notificationType === "discord") {
|
||||
const { webhookUrl } = input;
|
||||
try {
|
||||
// go to your discord server
|
||||
// go to settings
|
||||
// go to integrations
|
||||
// add a new integration
|
||||
// select webhook
|
||||
// copy the webhook url
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content: "Test notification",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Error sending Discord notification: ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Discord notification sent successfully");
|
||||
} catch (error) {
|
||||
console.error("Error sending Discord notification:", error);
|
||||
throw new Error("Error sending Discord notification");
|
||||
}
|
||||
} else if (notificationType === "email") {
|
||||
const { smtpServer, smtpPort, username, password, toAddresses } = input;
|
||||
try {
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: smtpServer,
|
||||
port: smtpPort,
|
||||
secure: smtpPort === "465",
|
||||
auth: {
|
||||
user: username,
|
||||
pass: password,
|
||||
},
|
||||
});
|
||||
// need to add a valid from address
|
||||
const fromAddress = "no-reply@emails.dokploy.com";
|
||||
const mailOptions = {
|
||||
from: fromAddress,
|
||||
to: toAddresses?.join(", "),
|
||||
subject: "Test email",
|
||||
text: "Test email",
|
||||
};
|
||||
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
console.log("Email notification sent successfully");
|
||||
} catch (error) {
|
||||
console.error("Error sending Email notification:", error);
|
||||
throw new Error("Error sending Email notification");
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
all: adminProcedure.query(async () => {
|
||||
return await db.query.notifications.findMany({
|
||||
with: {
|
||||
@@ -226,19 +231,7 @@ export const notificationRouter = createTRPCRouter({
|
||||
discord: true,
|
||||
email: true,
|
||||
},
|
||||
orderBy: desc(notifications.createdAt),
|
||||
});
|
||||
}),
|
||||
update: adminProcedure
|
||||
.input(apiUpdateDestination)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await updateDestinationById(input.destinationId, input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update this destination",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -18,6 +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";
|
||||
export type Application = typeof applications.$inferSelect;
|
||||
|
||||
export const createApplication = async (
|
||||
@@ -157,8 +158,17 @@ export const deployApplication = async ({
|
||||
await updateDeploymentStatus(deployment.deploymentId, "done");
|
||||
await updateApplicationStatus(applicationId, "done");
|
||||
} catch (error) {
|
||||
console.log("Error on build", error);
|
||||
await updateDeploymentStatus(deployment.deploymentId, "error");
|
||||
await updateApplicationStatus(applicationId, "error");
|
||||
await sendBuildFailedEmail({
|
||||
projectName: application.project.name,
|
||||
applicationName: application.appName,
|
||||
applicationType: "application",
|
||||
errorMessage: error?.message || "Error to build",
|
||||
buildLink: deployment.logPath,
|
||||
});
|
||||
|
||||
console.log(
|
||||
"Error on ",
|
||||
application.buildType,
|
||||
|
||||
@@ -4,14 +4,26 @@ import {
|
||||
type apiCreateEmail,
|
||||
type apiCreateSlack,
|
||||
type apiCreateTelegram,
|
||||
type apiTestDiscordConnection,
|
||||
type apiTestEmailConnection,
|
||||
type apiTestSlackConnection,
|
||||
type apiTestTelegramConnection,
|
||||
type apiUpdateDiscord,
|
||||
type apiUpdateEmail,
|
||||
type apiUpdateSlack,
|
||||
type apiUpdateTelegram,
|
||||
discord,
|
||||
email,
|
||||
notifications,
|
||||
slack,
|
||||
telegram,
|
||||
} from "@/server/db/schema";
|
||||
import { render } from "@react-email/components";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import nodemailer from "nodemailer";
|
||||
import { and, eq, isNotNull } from "drizzle-orm";
|
||||
import type SMTPTransport from "nodemailer/lib/smtp-transport";
|
||||
import { BuildFailedEmail } from "@/emails/emails/build-failed";
|
||||
|
||||
export type Notification = typeof notifications.$inferSelect;
|
||||
|
||||
@@ -61,6 +73,45 @@ export const createSlackNotification = async (
|
||||
});
|
||||
};
|
||||
|
||||
export const updateSlackNotification = async (
|
||||
input: typeof apiUpdateSlack._type,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newDestination = await tx
|
||||
.update(notifications)
|
||||
.set({
|
||||
name: input.name,
|
||||
appDeploy: input.appDeploy,
|
||||
userJoin: input.userJoin,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
if (!newDestination) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error Updating notification",
|
||||
});
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(slack)
|
||||
.set({
|
||||
channel: input.channel,
|
||||
webhookUrl: input.webhookUrl,
|
||||
})
|
||||
.where(eq(slack.slackId, input.slackId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
return newDestination;
|
||||
});
|
||||
};
|
||||
|
||||
export const createTelegramNotification = async (
|
||||
input: typeof apiCreateTelegram._type,
|
||||
) => {
|
||||
@@ -107,6 +158,45 @@ export const createTelegramNotification = async (
|
||||
});
|
||||
};
|
||||
|
||||
export const updateTelegramNotification = async (
|
||||
input: typeof apiUpdateTelegram._type,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newDestination = await tx
|
||||
.update(notifications)
|
||||
.set({
|
||||
name: input.name,
|
||||
appDeploy: input.appDeploy,
|
||||
userJoin: input.userJoin,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
if (!newDestination) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error Updating notification",
|
||||
});
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(telegram)
|
||||
.set({
|
||||
botToken: input.botToken,
|
||||
chatId: input.chatId,
|
||||
})
|
||||
.where(eq(telegram.telegramId, input.telegramId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
return newDestination;
|
||||
});
|
||||
};
|
||||
|
||||
export const createDiscordNotification = async (
|
||||
input: typeof apiCreateDiscord._type,
|
||||
) => {
|
||||
@@ -152,6 +242,44 @@ export const createDiscordNotification = async (
|
||||
});
|
||||
};
|
||||
|
||||
export const updateDiscordNotification = async (
|
||||
input: typeof apiUpdateDiscord._type,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newDestination = await tx
|
||||
.update(notifications)
|
||||
.set({
|
||||
name: input.name,
|
||||
appDeploy: input.appDeploy,
|
||||
userJoin: input.userJoin,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
if (!newDestination) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error Updating notification",
|
||||
});
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(discord)
|
||||
.set({
|
||||
webhookUrl: input.webhookUrl,
|
||||
})
|
||||
.where(eq(discord.discordId, input.discordId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
return newDestination;
|
||||
});
|
||||
};
|
||||
|
||||
export const createEmailNotification = async (
|
||||
input: typeof apiCreateEmail._type,
|
||||
) => {
|
||||
@@ -163,6 +291,7 @@ export const createEmailNotification = async (
|
||||
smtpPort: input.smtpPort,
|
||||
username: input.username,
|
||||
password: input.password,
|
||||
fromAddress: input.fromAddress,
|
||||
toAddresses: input.toAddresses,
|
||||
})
|
||||
.returning()
|
||||
@@ -201,6 +330,49 @@ export const createEmailNotification = async (
|
||||
});
|
||||
};
|
||||
|
||||
export const updateEmailNotification = async (
|
||||
input: typeof apiUpdateEmail._type,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
const newDestination = await tx
|
||||
.update(notifications)
|
||||
.set({
|
||||
name: input.name,
|
||||
appDeploy: input.appDeploy,
|
||||
userJoin: input.userJoin,
|
||||
appBuildError: input.appBuildError,
|
||||
databaseBackup: input.databaseBackup,
|
||||
dokployRestart: input.dokployRestart,
|
||||
})
|
||||
.where(eq(notifications.notificationId, input.notificationId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
if (!newDestination) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error Updating notification",
|
||||
});
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(email)
|
||||
.set({
|
||||
smtpServer: input.smtpServer,
|
||||
smtpPort: input.smtpPort,
|
||||
username: input.username,
|
||||
password: input.password,
|
||||
fromAddress: input.fromAddress,
|
||||
toAddresses: input.toAddresses,
|
||||
})
|
||||
.where(eq(email.emailId, input.emailId))
|
||||
.returning()
|
||||
.then((value) => value[0]);
|
||||
|
||||
return newDestination;
|
||||
});
|
||||
};
|
||||
|
||||
export const findNotificationById = async (notificationId: string) => {
|
||||
const notification = await db.query.notifications.findFirst({
|
||||
where: eq(notifications.notificationId, notificationId),
|
||||
@@ -244,21 +416,187 @@ export const updateDestinationById = async (
|
||||
return result[0];
|
||||
};
|
||||
|
||||
export const sendNotification = async (
|
||||
notificationData: Partial<Notification>,
|
||||
export const sendSlackTestNotification = async (
|
||||
slackTestConnection: typeof apiTestSlackConnection._type,
|
||||
) => {
|
||||
// if(notificationData.notificationType === "slack"){
|
||||
// const { webhookUrl, channel } = notificationData;
|
||||
// try {
|
||||
// const response = await fetch(webhookUrl, {
|
||||
// method: "POST",
|
||||
// headers: {
|
||||
// "Content-Type": "application/json",
|
||||
// },
|
||||
// body: JSON.stringify({ text: "Test notification", channel }),
|
||||
// });
|
||||
// } catch (err) {
|
||||
// console.log(err);
|
||||
// }
|
||||
// }
|
||||
const { webhookUrl, channel } = slackTestConnection;
|
||||
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ text: "Hi, From Dokploy 👋", channel }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Error to send test notification");
|
||||
}
|
||||
};
|
||||
|
||||
export const sendTelegramTestNotification = async (
|
||||
telegramTestConnection: typeof apiTestTelegramConnection._type,
|
||||
) => {
|
||||
const { botToken, chatId } = telegramTestConnection;
|
||||
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: "Hi, From Dokploy 👋",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Error to send test notification");
|
||||
}
|
||||
};
|
||||
|
||||
export const sendDiscordTestNotification = async (
|
||||
discordTestConnection: typeof apiTestDiscordConnection._type,
|
||||
) => {
|
||||
const { webhookUrl } = discordTestConnection;
|
||||
// go to your discord server
|
||||
// go to settings
|
||||
// go to integrations
|
||||
// add a new integration
|
||||
// select webhook
|
||||
// copy the webhook url
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content: "Hi, From Dokploy 👋",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Error to send test notification");
|
||||
}
|
||||
};
|
||||
|
||||
export const sendEmailTestNotification = async (
|
||||
emailTestConnection: typeof apiTestEmailConnection._type,
|
||||
) => {
|
||||
const { smtpServer, smtpPort, username, password, toAddresses, 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: toAddresses?.join(", "),
|
||||
subject: "Test email",
|
||||
text: "Hi, From Dokploy 👋",
|
||||
};
|
||||
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
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,
|
||||
applicationType,
|
||||
errorMessage,
|
||||
buildLink,
|
||||
}: {
|
||||
projectName: string;
|
||||
applicationName: string;
|
||||
applicationType: string;
|
||||
errorMessage: string;
|
||||
buildLink: string;
|
||||
}) => {
|
||||
const notificationList = await db.query.notifications.findMany({
|
||||
where: and(
|
||||
isNotNull(notifications.emailId),
|
||||
eq(notifications.appBuildError, true),
|
||||
),
|
||||
with: {
|
||||
email: true,
|
||||
},
|
||||
});
|
||||
|
||||
for (const notification of notificationList) {
|
||||
const { email } = 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user