agent starting :D
This commit is contained in:
@@ -28,7 +28,7 @@ const createApp = async () => {
|
||||
app.use(lstCors());
|
||||
setupRoutes(baseUrl, app);
|
||||
|
||||
log.info("Express app created");
|
||||
log.info("Lst app created");
|
||||
return { app, baseUrl };
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { OpenAPIV3_1 } from "openapi-types";
|
||||
import { cronerActiveJobs } from "../scaler/cronerActiveJobs.spec.js";
|
||||
import { cronerStatusChange } from "../scaler/cronerStatusChange.spec.js";
|
||||
import { prodLoginSpec } from "../scaler/login.spec.js";
|
||||
import { openDockApt } from "../scaler/opendockGetRelease.spec.js";
|
||||
import { prodRestartSpec } from "../scaler/prodSqlRestart.spec.js";
|
||||
import { prodStartSpec } from "../scaler/prodSqlStart.spec.js";
|
||||
import { prodStopSpec } from "../scaler/prodSqlStop.spec.js";
|
||||
@@ -33,6 +34,7 @@ export const openApiBase: OpenAPIV3_1.Document = {
|
||||
description: "Development server",
|
||||
},
|
||||
],
|
||||
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
@@ -87,6 +89,10 @@ export const openApiBase: OpenAPIV3_1.Document = {
|
||||
name: "Utils",
|
||||
description: "All routes related to the utilities on the server",
|
||||
},
|
||||
{
|
||||
name: "Open Dock",
|
||||
description: "All routes related to the opendock on the server",
|
||||
},
|
||||
// { name: "TMS", description: "TMS integration" },
|
||||
],
|
||||
paths: {}, // Will be populated
|
||||
@@ -121,6 +127,7 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => {
|
||||
//...mergedDatamart,
|
||||
...cronerActiveJobs,
|
||||
...cronerStatusChange,
|
||||
...openDockApt,
|
||||
|
||||
// Add more specs here as you build features
|
||||
},
|
||||
@@ -134,7 +141,9 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => {
|
||||
apiReference({
|
||||
url: `${baseUrl}/api/docs.json`,
|
||||
theme: "purple",
|
||||
|
||||
darkMode: true,
|
||||
persistAuth: true,
|
||||
authentication: {
|
||||
securitySchemes: {
|
||||
httpBasic: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
boolean,
|
||||
integer,
|
||||
jsonb,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
@@ -13,9 +14,9 @@ import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
export const settingType = pgEnum("setting_type", [
|
||||
"feature",
|
||||
"system",
|
||||
"standard",
|
||||
"feature", // when changed deals with triggering the croner related to this
|
||||
"system", // when changed fires a system restart but this should be rare and all these settings should be in the env
|
||||
"standard", // will be effected by the next process, either croner or manual trigger
|
||||
]);
|
||||
|
||||
export const settings = pgTable(
|
||||
@@ -27,8 +28,9 @@ export const settings = pgTable(
|
||||
description: text("description"),
|
||||
moduleName: text("moduleName"), // what part of lst dose it belong to this is used to split the settings out later
|
||||
active: boolean("active").default(true),
|
||||
roles: jsonb("roles").notNull().default(["systemAdmin"]), // role or roles to see this goes along with the moduleName, need to have a x role in module to see this setting.
|
||||
roles: jsonb("roles").$type<string[]>().notNull().default(["systemAdmin"]), // role or roles to see this goes along with the moduleName, need to have a x role in module to see this setting.
|
||||
settingType: settingType(),
|
||||
seedVersion: integer("seed_version").default(1), // this is intended for if we want to update the settings.
|
||||
add_User: text("add_User").default("LST_System").notNull(),
|
||||
add_Date: timestamp("add_Date").defaultNow(),
|
||||
upd_user: text("upd_User").default("LST_System").notNull(),
|
||||
|
||||
10
backend/db/schema/stats.schema.ts
Normal file
10
backend/db/schema/stats.schema.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { InferSelectModel } from "drizzle-orm";
|
||||
import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
|
||||
export const serverStats = pgTable("stats", {
|
||||
id: text("id").primaryKey().default("serverStats"),
|
||||
build: integer("build").notNull().default(1),
|
||||
lastUpdate: timestamp("last_update").defaultNow(),
|
||||
});
|
||||
|
||||
export type ServerStats = InferSelectModel<typeof serverStats>;
|
||||
37
backend/middleware/featureActive.middleware.ts
Normal file
37
backend/middleware/featureActive.middleware.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { settings } from "../db/schema/settings.schema.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param moduleName name of the module we are checking if is enabled or not.
|
||||
*/
|
||||
export const featureCheck = (moduleName: string) => {
|
||||
// get the features from the settings
|
||||
|
||||
return async (_req: Request, res: Response, next: NextFunction) => {
|
||||
const { data: sData, error: sError } = await tryCatch(
|
||||
db
|
||||
.select()
|
||||
.from(settings)
|
||||
.where(
|
||||
and(
|
||||
eq(settings.settingType, "feature"),
|
||||
eq(settings.name, moduleName),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (sError) {
|
||||
return res.status(403).json({ error: "Internal Error" });
|
||||
}
|
||||
|
||||
if (!sData?.length || !sData[0]?.active) {
|
||||
return res.status(403).json({ error: "Feature disabled" });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
@@ -1,7 +1,8 @@
|
||||
import axios from "axios";
|
||||
import { settings } from "backend/db/schema/settings.schema.js";
|
||||
import { addHours } from "date-fns";
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { opendockApt } from "../db/schema/opendock.schema.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
@@ -273,7 +274,10 @@ export const monitorReleaseChanges = async () => {
|
||||
// TODO: validate if the setting for opendocks is active and start / stop the system based on this
|
||||
// if it changes we set to false and the next loop will stop.
|
||||
|
||||
const openDockMonitor = true;
|
||||
const openDockMonitor = await db
|
||||
.select()
|
||||
.from(settings)
|
||||
.where(eq(settings.name, "opendock_sync"));
|
||||
// console.info("Starting release monitor", lastCheck);
|
||||
|
||||
const sqlQuery = sqlQuerySelector(`releaseChecks`) as SqlQuery;
|
||||
@@ -290,8 +294,8 @@ export const monitorReleaseChanges = async () => {
|
||||
});
|
||||
}
|
||||
|
||||
if (openDockMonitor) {
|
||||
createCronJob("open-dock-monitor", "*/15 * * * * *", async () => {
|
||||
if (openDockMonitor[0]?.active) {
|
||||
createCronJob("opendock_sync", "*/15 * * * * *", async () => {
|
||||
try {
|
||||
const result = await prodQuery(
|
||||
sqlQuery.query.replace("[dateCheck]", `'${lastCheck}'`),
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { type Express, Router } from "express";
|
||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||
import getApt from "./opendockGetRelease.route.js";
|
||||
|
||||
export const setupOpendockRoutes = (baseUrl: string, app: Express) => {
|
||||
//setup all the routes
|
||||
// Apply auth to entire router
|
||||
const router = Router();
|
||||
|
||||
// is the feature even on?
|
||||
router.use(featureCheck("opendock_sync"));
|
||||
|
||||
// we need to make sure we are authenticated to see the releases
|
||||
router.use(requireAuth);
|
||||
|
||||
router.use(getApt);
|
||||
|
||||
36
backend/scaler/opendockGetRelease.spec.ts
Normal file
36
backend/scaler/opendockGetRelease.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { OpenAPIV3_1 } from "openapi-types";
|
||||
|
||||
export const openDockApt: OpenAPIV3_1.PathsObject = {
|
||||
"/api/opendock": {
|
||||
get: {
|
||||
summary: "Open Dock apt",
|
||||
description: "Returns the last 30 days of apt(s).",
|
||||
tags: ["Open Dock"],
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Jobs returned",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
success: {
|
||||
type: "boolean",
|
||||
format: "boolean",
|
||||
example: true,
|
||||
},
|
||||
message: {
|
||||
type: "string",
|
||||
format: "string",
|
||||
example:
|
||||
"The first 5 Apt(s) that were created in the last 30 days",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import { monitorReleaseChanges } from "./opendock/openDockRreleaseMonitor.utils.
|
||||
import { opendockSocketMonitor } from "./opendock/opendockSocketMonitor.utils.js";
|
||||
import { connectProdSql } from "./prodSql/prodSqlConnection.controller.js";
|
||||
import { setupSocketIORoutes } from "./socket.io/serverSetup.js";
|
||||
import { baseSettingValidationCheck } from "./system/settingsBase.controller.js";
|
||||
import { createCronJob } from "./utils/croner.utils.js";
|
||||
|
||||
const port = Number(process.env.PORT) || 3000;
|
||||
@@ -17,15 +18,20 @@ const start = async () => {
|
||||
// triggering long lived processes
|
||||
connectProdSql();
|
||||
|
||||
// start long live processes
|
||||
// trigger startup processes these must run before anything else can run
|
||||
await baseSettingValidationCheck();
|
||||
|
||||
//when starting up long lived features the name must match the setting name.
|
||||
setTimeout(() => {
|
||||
monitorReleaseChanges(); // this is od monitoring the db for all new releases
|
||||
opendockSocketMonitor();
|
||||
createCronJob("JobAuditLogCleanUp", "* 0 5 * * * *", () =>
|
||||
|
||||
// cleanup sql jobs
|
||||
createCronJob("JobAuditLogCleanUp", "0 0 5 * * *", () =>
|
||||
dbCleanup("jobs", 30),
|
||||
);
|
||||
createCronJob("logsCleanup", "* 15 5 * * * *", () => dbCleanup("logs", 30));
|
||||
createCronJob("opendockAptCleanup", "* 30 5 * * * *", () =>
|
||||
createCronJob("logsCleanup", "0 15 5 * * *", () => dbCleanup("logs", 120));
|
||||
createCronJob("opendockAptCleanup", "0 30 5 * * *", () =>
|
||||
dbCleanup("opendockApt", 90),
|
||||
);
|
||||
}, 5 * 1000);
|
||||
|
||||
@@ -15,7 +15,7 @@ const r = Router();
|
||||
|
||||
r.get("/", async (_, res: Response) => {
|
||||
const { data: sName, error: sError } = await tryCatch(
|
||||
db.select().from(settings),
|
||||
db.select().from(settings).orderBy(settings.name),
|
||||
);
|
||||
|
||||
if (sError) {
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
import { sql } from "drizzle-orm";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { type NewSetting, settings } from "../db/schema/settings.schema.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
|
||||
const newSettings: NewSetting[] = [
|
||||
// feature settings
|
||||
{
|
||||
name: "opendock_sync",
|
||||
value: "0",
|
||||
active: true,
|
||||
description: "Dock Scheduling system",
|
||||
moduleName: "opendock",
|
||||
settingType: "feature",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "ocp",
|
||||
value: "1",
|
||||
active: true,
|
||||
description: "One click print",
|
||||
moduleName: "ocp",
|
||||
settingType: "feature",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "ocme",
|
||||
value: "0",
|
||||
active: true,
|
||||
description: "Dayton Agv system",
|
||||
moduleName: "ocme",
|
||||
settingType: "feature",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "demandManagement",
|
||||
value: "1",
|
||||
active: true,
|
||||
description: "Fake EDI System",
|
||||
moduleName: "demandManagement",
|
||||
settingType: "feature",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "qualityRequest",
|
||||
value: "0",
|
||||
active: true,
|
||||
description: "Quality System",
|
||||
moduleName: "qualityRequest",
|
||||
settingType: "feature",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "tms",
|
||||
value: "0",
|
||||
active: true,
|
||||
description: "Transport system integration",
|
||||
moduleName: "tms",
|
||||
settingType: "feature",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
|
||||
// standard settings
|
||||
{
|
||||
name: "prolinkCheck",
|
||||
value: "1",
|
||||
active: true,
|
||||
description:
|
||||
"Will prolink be considered to check if matches, mainly used in plants that do not fully utilize prolink + ocp",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "bookin",
|
||||
value: "1",
|
||||
active: true,
|
||||
description: "Will we book in the labels after they are printed.",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin", "supervisor"],
|
||||
seedVersion: 2,
|
||||
},
|
||||
{
|
||||
name: "printDelay",
|
||||
value: "90",
|
||||
active: true,
|
||||
description: "The default time between label printing",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "dualPrinting",
|
||||
value: "0",
|
||||
active: true,
|
||||
description: "Are we producing on 2 lines that pack into the 1 packer",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "fifoCheck",
|
||||
value: "45",
|
||||
active: true,
|
||||
description:
|
||||
"This check is used to do a more near fifo check when pulling pallets for the agv's",
|
||||
moduleName: "ocme",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "dayCheck",
|
||||
value: "3",
|
||||
active: true,
|
||||
description: "how many days +/- to check for shipments in alplaprod",
|
||||
moduleName: "ocme",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "maxLotsPerTruck",
|
||||
value: "3",
|
||||
active: true,
|
||||
description:
|
||||
"What is the maximum amount of lots that can be pulled for a truck this",
|
||||
moduleName: "ocme",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "monitorAddress",
|
||||
value: "8",
|
||||
active: true,
|
||||
description:
|
||||
"What address(2) are we monitoring for lot restrictions. multiple addresses can be used but should be separated by a comma ,",
|
||||
moduleName: "ocme",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "ocmeCycleCount",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"Are you enabling the system count page? meaning that we will allow a 'manual cycle count' vs full auto",
|
||||
moduleName: "ocme",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "inhouseDelivery",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"This is for in-house plants that deliver direct to the customer, note if book-in is off this will be ignored ",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "dycoConnect",
|
||||
value: "0",
|
||||
active: true,
|
||||
description: "Connection to the dyco in dayton for the labeling process",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "dycoPrint",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"This tells us we want to use the dyco system to print the labels",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "strapperCheck",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"Strapper alarm check this is more used in tandem with dycoPrint setting",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "rfid_ocp",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"Enable the rfid pallet mgt system this replaces dycoPrint but can be overridden by dycoPrint",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "ocpCycleDelay",
|
||||
value: "10",
|
||||
active: true,
|
||||
description:
|
||||
"How long is the delay to fire off the printer check status, Defaulting to 10 seconds",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "pNgAddress",
|
||||
value: "139",
|
||||
active: true,
|
||||
description:
|
||||
"This is the P&G address that is used when uploading the new forecast from P&G",
|
||||
moduleName: "demandManagement",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "zechetti_1",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"Active the Zechetti 1 process, to print from and no longer utilize the pc",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "zechetti_2",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"Active the Zechetti 2 process, to print from and no longer utilize the pc",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "checkColor",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"During the material check are we going to check the color has enough provided to create the next pallet",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "checkPKG",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"During the material check are we going to check the packaging has enough provided to create the next pallet",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
{
|
||||
name: "lotPrintDelay",
|
||||
value: "0",
|
||||
active: true,
|
||||
description:
|
||||
"Override ride the printer printer delay setting, by default if this is on all printers are controlled by this.",
|
||||
moduleName: "ocp",
|
||||
settingType: "standard",
|
||||
roles: ["admin"],
|
||||
seedVersion: 1,
|
||||
},
|
||||
];
|
||||
|
||||
export const baseSettingValidationCheck = async () => {
|
||||
const log = createLogger({ module: "system", subModule: "settings" });
|
||||
const { data, error } = await tryCatch(
|
||||
db
|
||||
.insert(settings)
|
||||
.values(newSettings)
|
||||
.onConflictDoUpdate({
|
||||
target: settings.name,
|
||||
set: {
|
||||
roles: sql`excluded.roles`,
|
||||
description: sql`excluded.description`,
|
||||
moduleName: sql`excluded."moduleName"`,
|
||||
settingType: sql`excluded."settingType"`,
|
||||
seedVersion: sql`excluded.seed_version`,
|
||||
upd_user: "LST_System",
|
||||
upd_date: sql`now()`,
|
||||
},
|
||||
where: sql`
|
||||
settings.seed_version IS NULL
|
||||
OR settings.seed_version < excluded.seed_version
|
||||
`,
|
||||
})
|
||||
.returning(),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
log.error(
|
||||
{ error: error },
|
||||
"There was an error when adding or updating the settings.",
|
||||
);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
log.info({}, "All Settings were added/updated");
|
||||
}
|
||||
};
|
||||
|
||||
16
backend/system/settingsFeatures.controller.ts
Normal file
16
backend/system/settingsFeatures.controller.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* When a feature setting gets updated we will handle it here.
|
||||
* we will stop jobs, stop cycles
|
||||
*/
|
||||
|
||||
import type { Setting } from "../db/schema/settings.schema.js";
|
||||
import { resumeCronJob, stopCronJob } from "../utils/croner.utils.js";
|
||||
|
||||
export const featureControl = async (data: Setting) => {
|
||||
// when a feature is changed to active or deactivated we will update the cron.
|
||||
if (data.active) {
|
||||
resumeCronJob(data.name);
|
||||
} else {
|
||||
stopCronJob(data.name);
|
||||
}
|
||||
};
|
||||
@@ -5,9 +5,8 @@ import { settings } from "../db/schema/settings.schema.js";
|
||||
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||
import { featureControl } from "./settingsFeatures.controller.js";
|
||||
|
||||
// export const updateSetting = async (setting: Setting) => {
|
||||
// // TODO: when the setting is a feature setting we will need to have it run each kill switch on the crons well just stop them and during a reset it just wont start them
|
||||
// // TODO: when the setting is a system we will need to force an app restart
|
||||
// // TODO: when the setting is standard we don't do anything.
|
||||
// };
|
||||
@@ -38,17 +37,17 @@ r.patch("/:name", async (req: Request, res: Response) => {
|
||||
});
|
||||
}
|
||||
|
||||
// if (sName?.length === 0) {
|
||||
// return apiReturn(res, {
|
||||
// success: false,
|
||||
// level: "error",
|
||||
// module: "system",
|
||||
// subModule: "settings",
|
||||
// message: `The setting "${name}" dose not appear to be a valid setting please check the name and try again. `,
|
||||
// data: [],
|
||||
// status: 400,
|
||||
// });
|
||||
// }
|
||||
if (sName?.length === 0) {
|
||||
return apiReturn(res, {
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "settings",
|
||||
message: `The setting "${name}" dose not appear to be a valid setting please check the name and try again. `,
|
||||
data: [],
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
// manage the actual setting. we will still do an upsert just in case we strangely get past everything
|
||||
|
||||
@@ -79,14 +78,32 @@ r.patch("/:name", async (req: Request, res: Response) => {
|
||||
updates.upd_user = req.user?.username || "lst_user";
|
||||
updates.upd_date = sql`NOW()`;
|
||||
|
||||
const updatedSetting = await db
|
||||
.update(settings)
|
||||
.set(updates)
|
||||
.where(eq(settings.name, name ?? ""))
|
||||
.returning();
|
||||
|
||||
// the switch statment will only run when the setting actually updates
|
||||
switch (updatedSetting[0]?.settingType) {
|
||||
case "feature":
|
||||
await featureControl(updatedSetting[0]);
|
||||
break;
|
||||
case "system":
|
||||
// TODO: add the system control logic in to restart the app if not in dev mode
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "system",
|
||||
subModule: "settings",
|
||||
message: `Setting "${name}" Was just updated. `,
|
||||
data: [updates],
|
||||
status: 400,
|
||||
data: updatedSetting,
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -18,9 +18,10 @@ export interface JobInfo {
|
||||
|
||||
// Store running cronjobs
|
||||
export const runningCrons: Record<string, Cron> = {};
|
||||
const log = createLogger({ module: "system", subModule: "croner" });
|
||||
|
||||
// how to se the times
|
||||
// * ┌──────────────── (optional) second (0 - 59) \n
|
||||
// * ┌──────────────── (optional) second (0 - 59)
|
||||
// * │ ┌────────────── minute (0 - 59)
|
||||
// * │ │ ┌──────────── hour (0 - 23)
|
||||
// * │ │ │ ┌────────── day of month (1 - 31)
|
||||
@@ -30,6 +31,8 @@ export const runningCrons: Record<string, Cron> = {};
|
||||
// * │ │ │ │ │ │ ┌──── (optional) year (1 - 9999)
|
||||
// * │ │ │ │ │ │ │
|
||||
// * * 05 * * * * *
|
||||
// note that when leaving * anywhere means ever part of that. IE * in the seconds part will run every second inside that min
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name Name of the job we want to run
|
||||
@@ -43,7 +46,6 @@ export const createCronJob = async (
|
||||
) => {
|
||||
// get the timezone based on the os timezone set
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const log = createLogger({ module: "system", subModule: "croner" });
|
||||
|
||||
// Destroy existing job if it exist
|
||||
if (runningCrons[name]) {
|
||||
@@ -124,11 +126,19 @@ export const removeCronJob = (name: string) => {
|
||||
export const stopCronJob = (name: string) => {
|
||||
if (runningCrons[name]) {
|
||||
runningCrons[name].pause();
|
||||
log.info(
|
||||
{},
|
||||
`${name} was just stopped either manually or due to a setting change.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const resumeCronJob = (name: string) => {
|
||||
if (runningCrons[name]) {
|
||||
runningCrons[name].resume();
|
||||
log.info(
|
||||
{},
|
||||
`${name} was just restarted either manually or due to a setting change.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user