diff --git a/migrations/20250505082941_add_maintenance_status.js b/migrations/20250505082941_add_maintenance_status.js index 8ed58a3..7fb1aae 100644 --- a/migrations/20250505082941_add_maintenance_status.js +++ b/migrations/20250505082941_add_maintenance_status.js @@ -3,8 +3,53 @@ * @returns { Promise } */ export function up(knex) { - const test = knex("site_data").where('key', "colors").update({value: knex.jsonInsert("value", "$.MAINTENANCE", "#6699cc")}) - return test; + return new Promise(async (resolve) => { + await knex("site_data") + .where("key", "colors") + .update({ value: knex.jsonInsert("value", "$.MAINTENANCE", "#6699cc") }); + + // Due to alter() limitations on columns (specialy with SQlite and Amazon Redshift), + // we recreate the entire table with new modifications. + await knex.schema.createTable("incidents_temp", (table) => { + table.increments("id").primary(); + table.string("title", 255).notNullable(); + table.integer("start_date_time"); + table.integer("end_date_time"); + table.timestamp("created_at").defaultTo(knex.fn.now()); + table.timestamp("updated_at").defaultTo(knex.fn.now()); + table.string("status", 255).defaultTo("ACTIVE"); + table.string("state", 255).defaultTo("INVESTIGATING"); + table.text("incident_type").defaultTo("INCIDENT"); + table.text("incident_source").defaultTo("DASHBOARD"); + table.text("maintenance_strategy").nullable(); + table.text("cron").nullable(); + table.integer("maintenance_duration").nullable(); + }); + // Moving old data to new table. + const incidents = await knex("incidents").select("*"); + for (const incident of incidents) { + await knex("incidents_temp").insert({ + id: incident.id, + title: incident.title, + start_date_time: incident.start_date_time, + end_date_time: incident.end_date_time, + created_at: incident.created_at, + updated_at: incident.updated_at, + status: incident.status, + state: incident.state, + incident_type: incident.incident_type, + incident_source: incident.incident_source, + maintenance_strategy: incident.incident_type === "MAINTENANCE" ? "SINGLE" : null, + cron: null, + maintenance_duration: null, + }); + } + // Deleting old table and renaming new one. + await knex.schema.dropTable("incidents"); + await knex.schema.renameTable("incidents_temp", "incidents"); + + resolve(); + }); } /** @@ -12,5 +57,42 @@ export function up(knex) { * @returns { Promise } */ export function down(knex) { - return knex("site_data").where('key', "colors").update({value: knex.jsonRemove("value", "$.MAINTENANCE")}) + return new Promise(async (resolve) => { + await knex("site_data") + .where("key", "colors") + .update({ value: knex.jsonRemove("value", "$.MAINTENANCE") }); + + await knex.schema.createTable("incidents_temp", (table) => { + table.increments("id").primary(); + table.string("title", 255).notNullable(); + table.integer("start_date_time").notNullable(); + table.integer("end_date_time"); + table.timestamp("created_at").defaultTo(knex.fn.now()); + table.timestamp("updated_at").defaultTo(knex.fn.now()); + table.string("status", 255).defaultTo("ACTIVE"); + table.string("state", 255).defaultTo("INVESTIGATING"); + table.text("incident_type").defaultTo("INCIDENT"); + table.text("incident_source").defaultTo("DASHBOARD"); + }); + // Moving old data to new table. + const incidents = await knex("incidents").select("*"); + for (const incident of incidents) { + await knex("incidents_temp").insert({ + id: incident.id, + title: incident.title, + start_date_time: incident.start_date_time ?? Math.floor(Date.now() / 1000), // For safety perpose. + end_date_time: incident.end_date_time, + created_at: incident.created_at, + updated_at: incident.updated_at, + status: incident.status, + state: incident.state, + incident_type: incident.incident_type, + incident_source: incident.incident_source, + }); + } + // Deleting old table and renaming new one. + await knex.schema.dropTable("incidents"); + await knex.schema.renameTable("incidents_temp", "incidents"); + resolve(); + }); } diff --git a/src/lib/server/controllers/controller.js b/src/lib/server/controllers/controller.js index c200bb7..a9b03d4 100644 --- a/src/lib/server/controllers/controller.js +++ b/src/lib/server/controllers/controller.js @@ -745,25 +745,46 @@ export const GetDataGroupByDayAlternative = async (monitor_tag, start, end, time }; export const CreateIncident = async (data) => { - // TODO: depending on incident_type && maintenance_strategy, we should make or not these next conditions. - //return error if no title or startDateTime - if (!data.title || !data.start_date_time) { - throw new Error("Title and startDateTime are required"); + //return error if no title + if (!data.title) { + throw new Error("Title is required"); } let incident = { title: data.title, - start_date_time: data.start_date_time, - status: !!data.status ? data.status : "OPEN", - end_date_time: !!data.end_date_time ? data.end_date_time : null, - state: !!data.state ? data.state : "INVESTIGATING", - incident_type: !!data.incident_type ? data.incident_type : "INCIDENT", - incident_source: !!data.incident_source ? data.incident_source : "DASHBOARD", + start_date_time: data.start_date_time ?? null, + status: data.status ?? "OPEN", + end_date_time: data.end_date_time ?? null, + state: data.state ?? "INVESTIGATING", + incident_type: data.incident_type ?? "INCIDENT", + incident_source: data.incident_source ?? "DASHBOARD", + maintenance_strategy: data.maintenance_strategy ?? null, + cron: data.cron ?? null, + maintenance_duration: data.maintenance_duration ?? null, }; - //incident_type == INCIDENT delete endDateTime + // return error if no start_date_time depending on situation + if ( + !data.start_date_time && + (incident.incident_type === "INCIDENT" || + (incident.incident_type === "MAINTENANCE" && + !incident.maintenance_strategy && + incident.maintenance_strategy !== "RECURRING")) + ) { + throw new Error("StartDateTime is required"); + } + if (incident.incident_type === "INCIDENT") { + // incident_type == INCIDENT delete endDateTime incident.end_date_time = null; + incident.maintenance_strategy = null; + } else if (incident.incident_type === "MAINTENANCE") { + if (incident.maintenance_strategy && incident.maintenance_strategy !== "RECURRING") { + incident.cron = null; + } else { + incident.start_date_time = null; + incident.end_date_time = null; + } } //if endDateTime is provided and it is less than startDateTime, throw error @@ -771,6 +792,7 @@ export const CreateIncident = async (data) => { throw new Error("End date time cannot be less than start date time"); } + console.log(incident); let newIncident = await db.createIncident(incident); PushDataToQueue(newIncident.id, "createIncident", { message: `${incident.incident_type} Created`, diff --git a/src/lib/server/db/dbimpl.js b/src/lib/server/db/dbimpl.js index 77e12fd..0e6e911 100644 --- a/src/lib/server/db/dbimpl.js +++ b/src/lib/server/db/dbimpl.js @@ -663,6 +663,9 @@ class DbImpl { updated_at: this.knex.fn.now(), incident_type: data.incident_type, incident_source: data.incident_source, + maintenance_strategy: data.maintenance_strategy, + cron: data.cron, + maintenance_duration: data.maintenance_duration, }; // PostgreSQL supports returning clause