diff --git a/server/model/maintenance.js b/server/model/maintenance.js index 4910d2a0..d1197009 100644 --- a/server/model/maintenance.js +++ b/server/model/maintenance.js @@ -1,5 +1,5 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); -const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC } = require("../../src/util"); +const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC, log } = require("../../src/util"); const { isArray } = require("chart.js/helpers"); const { timeObjectToUTC, timeObjectToLocal } = require("../util-server"); const { R } = require("redbean-node"); @@ -62,8 +62,15 @@ class Maintenance extends BeanModel { } else if (obj.strategy === "manual") { obj.status = "under-maintenance"; } else if (obj.timeslotList.length > 0) { + let currentTimestamp = dayjs().unix(); + for (let timeslot of obj.timeslotList) { - if (dayjs.utc(timeslot.start_date) <= dayjs.utc() && dayjs.utc(timeslot.end_date) >= dayjs.utc()) { + if (dayjs.utc(timeslot.startDate).unix() <= currentTimestamp && dayjs.utc(timeslot.endDate).unix() >= currentTimestamp) { + log.debug("timeslot", "Timeslot ID: " + timeslot.id); + log.debug("timeslot", "currentTimestamp:" + currentTimestamp); + log.debug("timeslot", "timeslot.start_date:" + dayjs.utc(timeslot.startDate).unix()); + log.debug("timeslot", "timeslot.end_date:" + dayjs.utc(timeslot.endDate).unix()); + obj.status = "under-maintenance"; break; } diff --git a/server/model/maintenance_timeslot.js b/server/model/maintenance_timeslot.js index 3ac64b6b..4c13632d 100644 --- a/server/model/maintenance_timeslot.js +++ b/server/model/maintenance_timeslot.js @@ -1,7 +1,7 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); const { R } = require("redbean-node"); const dayjs = require("dayjs"); -const { log, utcToLocal, SQL_DATETIME_FORMAT_WITHOUT_SECOND } = require("../../src/util"); +const { log, utcToLocal, SQL_DATETIME_FORMAT_WITHOUT_SECOND, localToUTC } = require("../../src/util"); const { UptimeKumaServer } = require("../uptime-kuma-server"); class MaintenanceTimeslot extends BeanModel { @@ -26,17 +26,12 @@ class MaintenanceTimeslot extends BeanModel { } /** - * * @param {Maintenance} maintenance - * @param {dayjs} startFrom (For recurring type only) Generate Timeslot from this date, if it is smaller than the current date, it will use the current date instead. As generating a passed timeslot is meaningless. + * @param {dayjs} minDate (For recurring type only) Generate a next timeslot from this date. * @param {boolean} removeExist Remove existing timeslot before create - * @returns {Promise} + * @returns {Promise} */ - static async generateTimeslot(maintenance, startFrom = null, removeExist = false) { - if (!startFrom) { - startFrom = dayjs(); - } - + static async generateTimeslot(maintenance, minDate = null, removeExist = false) { if (removeExist) { await R.exec("DELETE FROM maintenance_timeslot WHERE maintenance_id = ? ", [ maintenance.id @@ -51,9 +46,67 @@ class MaintenanceTimeslot extends BeanModel { bean.start_date = maintenance.start_date; bean.end_date = maintenance.end_date; bean.generated_next = true; - await R.store(bean); + return await R.store(bean); } else if (maintenance.strategy === "recurring-interval") { - // TODO + let bean = R.dispense("maintenance_timeslot"); + + // Prevent dead loop, in case interval_day is not set + if (!maintenance.interval_day || maintenance.interval_day <= 0) { + maintenance.interval_day = 1; + } + + let startOfTheDay = dayjs.utc(maintenance.start_date).format("HH:mm"); + log.debug("timeslot", "startOfTheDay: " + startOfTheDay); + + // Start Time + let startTimeSecond = dayjs.utc(maintenance.start_time, "HH:mm").diff(dayjs.utc(startOfTheDay, "HH:mm"), "second"); + log.debug("timeslot", "startTime: " + startTimeSecond); + + // Duration + let duration = dayjs.utc(maintenance.end_time, "HH:mm").diff(dayjs.utc(maintenance.start_time, "HH:mm"), "second"); + // Add 24hours if it is across day + if (duration < 0) { + duration += 24 * 3600; + } + + // Bake StartDate + StartTime = Start DateTime + let startDateTime = dayjs.utc(maintenance.start_date).add(startTimeSecond, "second"); + let endDateTime; + + // Keep generating from the first possible date, until it is ok + while (true) { + log.debug("timeslot", "startDateTime: " + startDateTime.format()); + + // Handling out of effective date range + if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) { + log.debug("timeslot", "Out of effective date range"); + return null; + } + + endDateTime = startDateTime.add(duration, "second"); + + // If endDateTime is out of effective date range, use the end datetime from effective date range + if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) { + endDateTime = dayjs.utc(maintenance.end_date); + } + + // If minDate is set, the endDateTime must be bigger than it. + // And the endDateTime must be bigger current time + if ( + (!minDate || endDateTime.diff(minDate) > 0) && + endDateTime.diff(dayjs()) > 0 + ) { + break; + } + + startDateTime = startDateTime.add(maintenance.interval_day, "day"); + } + + bean.maintenance_id = maintenance.id; + bean.start_date = localToUTC(startDateTime); + bean.end_date = localToUTC(endDateTime); + bean.generated_next = false; + return await R.store(bean); } else if (maintenance.strategy === "recurring-weekday") { // TODO } else if (maintenance.strategy === "recurring-day-of-month") { diff --git a/server/server.js b/server/server.js index 41cf7c37..03b8b6cd 100644 --- a/server/server.js +++ b/server/server.js @@ -9,6 +9,7 @@ console.log("Welcome to Uptime Kuma"); const dayjs = require("dayjs"); dayjs.extend(require("dayjs/plugin/utc")); dayjs.extend(require("dayjs/plugin/timezone")); +dayjs.extend(require("dayjs/plugin/customParseFormat")); // Check Node.js Version const nodeVersion = parseInt(process.versions.node.split(".")[0]); @@ -1110,6 +1111,7 @@ let needSetup = false; }); sendInfo(socket); + server.sendMaintenanceList(socket); } catch (e) { callback({ diff --git a/server/util-server.js b/server/util-server.js index 7c81cde7..ac8bc488 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -671,18 +671,20 @@ function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) { obj.minutes += minutes; // Handle out of bound + if (obj.minutes < 0) { + obj.minutes += 60; + obj.hours--; + } else if (obj.minutes > 60) { + obj.minutes -= 60; + obj.hours++; + } + if (obj.hours < 0) { obj.hours += 24; } else if (obj.hours > 24) { obj.hours -= 24; } - if (obj.minutes < 0) { - obj.minutes += 24; - } else if (obj.minutes > 24) { - obj.minutes -= 24; - } - return obj; } diff --git a/src/components/MaintenanceTime.vue b/src/components/MaintenanceTime.vue index 66ee4abf..07d65740 100644 --- a/src/components/MaintenanceTime.vue +++ b/src/components/MaintenanceTime.vue @@ -1,9 +1,9 @@