mirror of
https://github.com/koichixD/uptime-kuma.git
synced 2026-09-04 09:13:21 +00:00
Merge branch 'master' into websocket_test
This commit is contained in:
+122
-20
@@ -59,7 +59,7 @@ if (process.env.UPTIME_KUMA_WS_ORIGIN_CHECK === "bypass") {
|
||||
}
|
||||
|
||||
const checkVersion = require("./check-version");
|
||||
log.info("server", "Uptime Kuma Version: " + checkVersion.version);
|
||||
log.info("server", "Uptime Kuma Version:", checkVersion.version);
|
||||
|
||||
log.info("server", "Loading modules");
|
||||
|
||||
@@ -96,6 +96,8 @@ const { getSettings, setSettings, setting, initJWTSecret, checkLogin, doubleChec
|
||||
log.debug("server", "Importing Notification");
|
||||
const { Notification } = require("./notification");
|
||||
Notification.init();
|
||||
log.debug("server", "Importing Web-Push");
|
||||
const webpush = require("web-push");
|
||||
|
||||
log.debug("server", "Importing Database");
|
||||
const Database = require("./database");
|
||||
@@ -108,6 +110,9 @@ const { apiAuth } = require("./auth");
|
||||
const { login } = require("./auth");
|
||||
const passwordHash = require("./password-hash");
|
||||
|
||||
const { Prometheus } = require("./prometheus");
|
||||
const { UptimeCalculator } = require("./uptime-calculator");
|
||||
|
||||
const hostname = config.hostname;
|
||||
|
||||
if (hostname) {
|
||||
@@ -192,6 +197,9 @@ let needSetup = false;
|
||||
server.entryPage = await Settings.get("entryPage");
|
||||
await StatusPage.loadDomainMappingList();
|
||||
|
||||
log.debug("server", "Initializing Prometheus");
|
||||
await Prometheus.init();
|
||||
|
||||
log.debug("server", "Adding route");
|
||||
|
||||
// ***************************
|
||||
@@ -674,7 +682,7 @@ let needSetup = false;
|
||||
|
||||
let user = R.dispense("user");
|
||||
user.username = username;
|
||||
user.password = passwordHash.generate(password);
|
||||
user.password = await passwordHash.generate(password);
|
||||
await R.store(user);
|
||||
|
||||
needSetup = false;
|
||||
@@ -720,6 +728,17 @@ let needSetup = false;
|
||||
|
||||
monitor.rabbitmqNodes = JSON.stringify(monitor.rabbitmqNodes);
|
||||
|
||||
/*
|
||||
* List of frontend-only properties that should not be saved to the database.
|
||||
* Should clean up before saving to the database.
|
||||
*/
|
||||
const frontendOnlyProperties = [ "humanReadableInterval" ];
|
||||
for (const prop of frontendOnlyProperties) {
|
||||
if (prop in monitor) {
|
||||
delete monitor[prop];
|
||||
}
|
||||
}
|
||||
|
||||
bean.import(monitor);
|
||||
bean.user_id = socket.userID;
|
||||
|
||||
@@ -794,6 +813,7 @@ let needSetup = false;
|
||||
bean.wsSubprotocol = monitor.wsSubprotocol;
|
||||
bean.method = monitor.method;
|
||||
bean.body = monitor.body;
|
||||
bean.ipFamily = monitor.ipFamily;
|
||||
bean.headers = monitor.headers;
|
||||
bean.basic_auth_user = monitor.basic_auth_user;
|
||||
bean.basic_auth_pass = monitor.basic_auth_pass;
|
||||
@@ -803,6 +823,7 @@ let needSetup = false;
|
||||
bean.oauth_auth_method = monitor.oauth_auth_method;
|
||||
bean.oauth_token_url = monitor.oauth_token_url;
|
||||
bean.oauth_scopes = monitor.oauth_scopes;
|
||||
bean.oauth_audience = monitor.oauth_audience;
|
||||
bean.tlsCa = monitor.tlsCa;
|
||||
bean.tlsCert = monitor.tlsCert;
|
||||
bean.tlsKey = monitor.tlsKey;
|
||||
@@ -837,6 +858,7 @@ let needSetup = false;
|
||||
bean.mqttTopic = monitor.mqttTopic;
|
||||
bean.mqttSuccessMessage = monitor.mqttSuccessMessage;
|
||||
bean.mqttCheckType = monitor.mqttCheckType;
|
||||
bean.mqttWebsocketPath = monitor.mqttWebsocketPath;
|
||||
bean.databaseConnectionString = monitor.databaseConnectionString;
|
||||
bean.databaseQuery = monitor.databaseQuery;
|
||||
bean.authMethod = monitor.authMethod;
|
||||
@@ -868,6 +890,7 @@ let needSetup = false;
|
||||
monitor.kafkaProducerAllowAutoTopicCreation;
|
||||
bean.gamedigGivenPortOnly = monitor.gamedigGivenPortOnly;
|
||||
bean.remote_browser = monitor.remote_browser;
|
||||
bean.smtpSecurity = monitor.smtpSecurity;
|
||||
bean.snmpVersion = monitor.snmpVersion;
|
||||
bean.snmpOid = monitor.snmpOid;
|
||||
bean.jsonPathOperator = monitor.jsonPathOperator;
|
||||
@@ -876,6 +899,12 @@ let needSetup = false;
|
||||
bean.rabbitmqUsername = monitor.rabbitmqUsername;
|
||||
bean.rabbitmqPassword = monitor.rabbitmqPassword;
|
||||
bean.conditions = JSON.stringify(monitor.conditions);
|
||||
bean.manual_status = monitor.manual_status;
|
||||
|
||||
// ping advanced options
|
||||
bean.ping_numeric = monitor.ping_numeric;
|
||||
bean.ping_count = monitor.ping_count;
|
||||
bean.ping_per_request_timeout = monitor.ping_per_request_timeout;
|
||||
|
||||
bean.validate();
|
||||
|
||||
@@ -1028,30 +1057,78 @@ let needSetup = false;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("deleteMonitor", async (monitorID, callback) => {
|
||||
socket.on("deleteMonitor", async (monitorID, deleteChildren, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
|
||||
log.info("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`);
|
||||
|
||||
if (monitorID in server.monitorList) {
|
||||
await server.monitorList[monitorID].stop();
|
||||
delete server.monitorList[monitorID];
|
||||
// Backward compatibility: if deleteChildren is omitted, the second parameter is the callback
|
||||
if (typeof deleteChildren === "function") {
|
||||
callback = deleteChildren;
|
||||
deleteChildren = false;
|
||||
}
|
||||
|
||||
checkLogin(socket);
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
await R.exec("DELETE FROM monitor WHERE id = ? AND user_id = ? ", [
|
||||
// Check if this is a group monitor
|
||||
const monitor = await R.findOne("monitor", " id = ? AND user_id = ? ", [
|
||||
monitorID,
|
||||
socket.userID,
|
||||
]);
|
||||
|
||||
// Log with context about deletion type
|
||||
if (monitor && monitor.type === "group") {
|
||||
if (deleteChildren) {
|
||||
log.info("manage", `Delete Group and Children: ${monitorID} User ID: ${socket.userID}`);
|
||||
} else {
|
||||
log.info("manage", `Delete Group (unlink children): ${monitorID} User ID: ${socket.userID}`);
|
||||
}
|
||||
} else {
|
||||
log.info("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`);
|
||||
}
|
||||
|
||||
if (monitor && monitor.type === "group") {
|
||||
// Get all children before processing
|
||||
const children = await Monitor.getChildren(monitorID);
|
||||
|
||||
if (deleteChildren) {
|
||||
// Delete all child monitors recursively
|
||||
if (children && children.length > 0) {
|
||||
for (const child of children) {
|
||||
await Monitor.deleteMonitorRecursively(child.id, socket.userID);
|
||||
await server.sendDeleteMonitorFromList(socket, child.id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unlink all children from the group (set parent to null)
|
||||
await Monitor.unlinkAllChildren(monitorID);
|
||||
|
||||
// Notify frontend to update each child monitor's parent to null
|
||||
if (children && children.length > 0) {
|
||||
for (const child of children) {
|
||||
await server.sendUpdateMonitorIntoList(socket, child.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the monitor itself
|
||||
await Monitor.deleteMonitor(monitorID, socket.userID);
|
||||
|
||||
// Fix #2880
|
||||
apicache.clear();
|
||||
|
||||
const endTime = Date.now();
|
||||
|
||||
log.info("DB", `Delete Monitor completed in : ${endTime - startTime} ms`);
|
||||
// Log completion with context about children handling
|
||||
if (monitor && monitor.type === "group") {
|
||||
if (deleteChildren) {
|
||||
log.info("DB", `Delete Monitor completed (group and children deleted) in: ${endTime - startTime} ms`);
|
||||
} else {
|
||||
log.info("DB", `Delete Monitor completed (group deleted, children unlinked) in: ${endTime - startTime} ms`);
|
||||
}
|
||||
} else {
|
||||
log.info("DB", `Delete Monitor completed in: ${endTime - startTime} ms`);
|
||||
}
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
@@ -1484,12 +1561,38 @@ let needSetup = false;
|
||||
socket.on("checkApprise", async (callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
callback(Notification.checkApprise());
|
||||
callback(await Notification.checkApprise());
|
||||
} catch (e) {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("getWebpushVapidPublicKey", async (callback) => {
|
||||
try {
|
||||
let publicVapidKey = await Settings.get("webpushPublicVapidKey");
|
||||
|
||||
if (!publicVapidKey) {
|
||||
log.debug("webpush", "Generating new VAPID keys");
|
||||
const vapidKeys = webpush.generateVAPIDKeys();
|
||||
|
||||
await Settings.set("webpushPublicVapidKey", vapidKeys.publicKey);
|
||||
await Settings.set("webpushPrivateVapidKey", vapidKeys.privateKey);
|
||||
|
||||
publicVapidKey = vapidKeys.publicKey;
|
||||
}
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: publicVapidKey,
|
||||
});
|
||||
} catch (e) {
|
||||
callback({
|
||||
ok: false,
|
||||
msg: e.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("clearEvents", async (monitorID, callback) => {
|
||||
try {
|
||||
checkLogin(socket);
|
||||
@@ -1520,9 +1623,11 @@ let needSetup = false;
|
||||
|
||||
log.info("manage", `Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`);
|
||||
|
||||
await R.exec("DELETE FROM heartbeat WHERE monitor_id = ?", [
|
||||
monitorID
|
||||
]);
|
||||
await UptimeCalculator.clearStatistics(monitorID);
|
||||
|
||||
if (monitorID in server.monitorList) {
|
||||
await restartMonitor(socket.userID, monitorID);
|
||||
}
|
||||
|
||||
await sendHeartbeatList(socket, monitorID, true, true);
|
||||
|
||||
@@ -1544,10 +1649,7 @@ let needSetup = false;
|
||||
|
||||
log.info("manage", `Clear Statistics User ID: ${socket.userID}`);
|
||||
|
||||
await R.exec("DELETE FROM heartbeat");
|
||||
await R.exec("DELETE FROM stat_daily");
|
||||
await R.exec("DELETE FROM stat_hourly");
|
||||
await R.exec("DELETE FROM stat_minutely");
|
||||
await UptimeCalculator.clearAllStatistics();
|
||||
|
||||
// Restart all monitors to reset the stats
|
||||
for (let monitorID in server.monitorList) {
|
||||
|
||||
Reference in New Issue
Block a user