mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-11 22:45:18 +00:00
feat(notifications): integrate custom notification handling in server threshold alerts
This commit is contained in:
@@ -2,6 +2,7 @@ import { and, eq } from "drizzle-orm";
|
|||||||
import { db } from "../../db";
|
import { db } from "../../db";
|
||||||
import { notifications } from "../../db/schema";
|
import { notifications } from "../../db/schema";
|
||||||
import {
|
import {
|
||||||
|
sendCustomNotification,
|
||||||
sendDiscordNotification,
|
sendDiscordNotification,
|
||||||
sendSlackNotification,
|
sendSlackNotification,
|
||||||
sendTelegramNotification,
|
sendTelegramNotification,
|
||||||
@@ -34,6 +35,7 @@ export const sendServerThresholdNotifications = async (
|
|||||||
discord: true,
|
discord: true,
|
||||||
telegram: true,
|
telegram: true,
|
||||||
slack: true,
|
slack: true,
|
||||||
|
custom: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -41,7 +43,7 @@ export const sendServerThresholdNotifications = async (
|
|||||||
const typeColor = 0xff0000; // Rojo para indicar alerta
|
const typeColor = 0xff0000; // Rojo para indicar alerta
|
||||||
|
|
||||||
for (const notification of notificationList) {
|
for (const notification of notificationList) {
|
||||||
const { discord, telegram, slack } = notification;
|
const { discord, telegram, slack, custom } = notification;
|
||||||
|
|
||||||
if (discord) {
|
if (discord) {
|
||||||
const decorate = (decoration: string, text: string) =>
|
const decorate = (decoration: string, text: string) =>
|
||||||
@@ -151,5 +153,20 @@ export const sendServerThresholdNotifications = async (
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (custom) {
|
||||||
|
await sendCustomNotification(custom, {
|
||||||
|
title: `Server ${payload.Type} Alert`,
|
||||||
|
message: payload.Message,
|
||||||
|
serverName: payload.ServerName,
|
||||||
|
type: payload.Type,
|
||||||
|
currentValue: payload.Value,
|
||||||
|
threshold: payload.Threshold,
|
||||||
|
timestamp: date.toISOString(),
|
||||||
|
date: date.toLocaleString(),
|
||||||
|
status: "alert",
|
||||||
|
alertType: "server-threshold",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,153 +1,193 @@
|
|||||||
import type {
|
import type {
|
||||||
discord,
|
custom,
|
||||||
email,
|
discord,
|
||||||
gotify,
|
email,
|
||||||
ntfy,
|
gotify,
|
||||||
slack,
|
ntfy,
|
||||||
telegram,
|
slack,
|
||||||
|
telegram,
|
||||||
} from "@dokploy/server/db/schema";
|
} from "@dokploy/server/db/schema";
|
||||||
import nodemailer from "nodemailer";
|
import nodemailer from "nodemailer";
|
||||||
|
|
||||||
export const sendEmailNotification = async (
|
export const sendEmailNotification = async (
|
||||||
connection: typeof email.$inferInsert,
|
connection: typeof email.$inferInsert,
|
||||||
subject: string,
|
subject: string,
|
||||||
htmlContent: string,
|
htmlContent: string
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
smtpServer,
|
smtpServer,
|
||||||
smtpPort,
|
smtpPort,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
fromAddress,
|
fromAddress,
|
||||||
toAddresses,
|
toAddresses,
|
||||||
} = connection;
|
} = connection;
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
host: smtpServer,
|
host: smtpServer,
|
||||||
port: smtpPort,
|
port: smtpPort,
|
||||||
auth: { user: username, pass: password },
|
auth: { user: username, pass: password },
|
||||||
});
|
});
|
||||||
|
|
||||||
await transporter.sendMail({
|
await transporter.sendMail({
|
||||||
from: fromAddress,
|
from: fromAddress,
|
||||||
to: toAddresses.join(", "),
|
to: toAddresses.join(", "),
|
||||||
subject,
|
subject,
|
||||||
html: htmlContent,
|
html: htmlContent,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendDiscordNotification = async (
|
export const sendDiscordNotification = async (
|
||||||
connection: typeof discord.$inferInsert,
|
connection: typeof discord.$inferInsert,
|
||||||
embed: any,
|
embed: any
|
||||||
) => {
|
) => {
|
||||||
// try {
|
// try {
|
||||||
await fetch(connection.webhookUrl, {
|
await fetch(connection.webhookUrl, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ embeds: [embed] }),
|
body: JSON.stringify({ embeds: [embed] }),
|
||||||
});
|
});
|
||||||
// } catch (err) {
|
// } catch (err) {
|
||||||
// console.log(err);
|
// console.log(err);
|
||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendTelegramNotification = async (
|
export const sendTelegramNotification = async (
|
||||||
connection: typeof telegram.$inferInsert,
|
connection: typeof telegram.$inferInsert,
|
||||||
messageText: string,
|
messageText: string,
|
||||||
inlineButton?: {
|
inlineButton?: {
|
||||||
text: string;
|
text: string;
|
||||||
url: string;
|
url: string;
|
||||||
}[][],
|
}[][]
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const url = `https://api.telegram.org/bot${connection.botToken}/sendMessage`;
|
const url = `https://api.telegram.org/bot${connection.botToken}/sendMessage`;
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
chat_id: connection.chatId,
|
chat_id: connection.chatId,
|
||||||
message_thread_id: connection.messageThreadId,
|
message_thread_id: connection.messageThreadId,
|
||||||
text: messageText,
|
text: messageText,
|
||||||
parse_mode: "HTML",
|
parse_mode: "HTML",
|
||||||
disable_web_page_preview: true,
|
disable_web_page_preview: true,
|
||||||
reply_markup: {
|
reply_markup: {
|
||||||
inline_keyboard: inlineButton,
|
inline_keyboard: inlineButton,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendSlackNotification = async (
|
export const sendSlackNotification = async (
|
||||||
connection: typeof slack.$inferInsert,
|
connection: typeof slack.$inferInsert,
|
||||||
message: any,
|
message: any
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
await fetch(connection.webhookUrl, {
|
await fetch(connection.webhookUrl, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(message),
|
body: JSON.stringify(message),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendGotifyNotification = async (
|
export const sendGotifyNotification = async (
|
||||||
connection: typeof gotify.$inferInsert,
|
connection: typeof gotify.$inferInsert,
|
||||||
title: string,
|
title: string,
|
||||||
message: string,
|
message: string
|
||||||
) => {
|
) => {
|
||||||
const response = await fetch(`${connection.serverUrl}/message`, {
|
const response = await fetch(`${connection.serverUrl}/message`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Gotify-Key": connection.appToken,
|
"X-Gotify-Key": connection.appToken,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
title: title,
|
title: title,
|
||||||
message: message,
|
message: message,
|
||||||
priority: connection.priority,
|
priority: connection.priority,
|
||||||
extras: {
|
extras: {
|
||||||
"client::display": {
|
"client::display": {
|
||||||
contentType: "text/plain",
|
contentType: "text/plain",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to send Gotify notification: ${response.statusText}`,
|
`Failed to send Gotify notification: ${response.statusText}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sendNtfyNotification = async (
|
export const sendNtfyNotification = async (
|
||||||
connection: typeof ntfy.$inferInsert,
|
connection: typeof ntfy.$inferInsert,
|
||||||
title: string,
|
title: string,
|
||||||
tags: string,
|
tags: string,
|
||||||
actions: string,
|
actions: string,
|
||||||
message: string,
|
message: string
|
||||||
) => {
|
) => {
|
||||||
const response = await fetch(`${connection.serverUrl}/${connection.topic}`, {
|
const response = await fetch(`${connection.serverUrl}/${connection.topic}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${connection.accessToken}`,
|
Authorization: `Bearer ${connection.accessToken}`,
|
||||||
"X-Priority": connection.priority?.toString() || "3",
|
"X-Priority": connection.priority?.toString() || "3",
|
||||||
"X-Title": title,
|
"X-Title": title,
|
||||||
"X-Tags": tags,
|
"X-Tags": tags,
|
||||||
"X-Actions": actions,
|
"X-Actions": actions,
|
||||||
},
|
},
|
||||||
body: message,
|
body: message,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to send ntfy notification: ${response.statusText}`);
|
throw new Error(`Failed to send ntfy notification: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sendCustomNotification = async (
|
||||||
|
connection: typeof custom.$inferInsert,
|
||||||
|
payload: Record<string, any>
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
// Parse headers if provided
|
||||||
|
let headers: Record<string, string> = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
if (connection.headers) {
|
||||||
|
try {
|
||||||
|
headers = { ...headers, ...JSON.parse(connection.headers) };
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error parsing headers:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default body with payload
|
||||||
|
const body = JSON.stringify(payload);
|
||||||
|
|
||||||
|
const response = await fetch(connection.endpoint, {
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to send custom notification: ${response.statusText}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending custom notification:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user