agent starting :D
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -52,7 +52,9 @@
|
||||
"alpla",
|
||||
"alplamart",
|
||||
"alplaprod",
|
||||
"bookin",
|
||||
"Datamart",
|
||||
"dyco",
|
||||
"intiallally",
|
||||
"manadatory",
|
||||
"OCME",
|
||||
@@ -61,6 +63,7 @@
|
||||
"opendocks",
|
||||
"ppoo",
|
||||
"prodlabels",
|
||||
"prolink",
|
||||
"trycatch"
|
||||
],
|
||||
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
|
||||
|
||||
@@ -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.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
34
brunoApi/auth/Register.bru
Normal file
34
brunoApi/auth/Register.bru
Normal file
@@ -0,0 +1,34 @@
|
||||
meta {
|
||||
name: Register
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{url}}/lst/api/authentication/register
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"username": "jane005",
|
||||
"email": "jane@alpla.com",
|
||||
"password": "superSecretPassword"
|
||||
}
|
||||
}
|
||||
|
||||
script:post-response {
|
||||
// // grab the raw Set-Cookie header
|
||||
// const cookies = res.headers["set-cookie"];
|
||||
|
||||
// const sessionCookie = cookies[0].split(";")[0];
|
||||
|
||||
// // Save it as an environment variable
|
||||
// bru.setEnvVar("session_cookie", sessionCookie);
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
docs {
|
||||
All Api endpoints to the logistics support tool
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ meta {
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{url}}/lst/api/datamart/deliveryByDateRange
|
||||
url: {{url}}/lst/api/datamart
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
20
brunoApi/datamart/Run Query.bru
Normal file
20
brunoApi/datamart/Run Query.bru
Normal file
@@ -0,0 +1,20 @@
|
||||
meta {
|
||||
name: Run Query
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{url}}/lst/api/datamart/:name
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:path {
|
||||
name: activeArticles
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
meta {
|
||||
name: add new query
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{url}}/lst/api/datamart
|
||||
body: multipartForm
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name": "active av",
|
||||
"description":"this is just the query on what it dose",
|
||||
"query": "select * \nfrom tableA"
|
||||
}
|
||||
}
|
||||
|
||||
body:multipart-form {
|
||||
name: sqlStats
|
||||
description: returns all active articles for the server with custom data
|
||||
options: ""
|
||||
queryFile: @file(C:\Users\matthes01\Nextcloud2\sqlQuerys\basisArticles.sql)
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
meta {
|
||||
name: update new query
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
patch {
|
||||
url: {{url}}/lst/api/datamart/f737aeba-186d-495f-a86e-57412ba6687e
|
||||
body: multipartForm
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"name": "active av",
|
||||
"description":"this is just the query on what it dose",
|
||||
"query": "select * \nfrom tableA"
|
||||
}
|
||||
}
|
||||
|
||||
body:multipart-form {
|
||||
setPublicActive: true
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
15
brunoApi/prodSql/Sql Start.bru
Normal file
15
brunoApi/prodSql/Sql Start.bru
Normal file
@@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: Sql Start
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{url}}/lst/api/system/prodsql/start
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
}
|
||||
@@ -1,19 +1,15 @@
|
||||
meta {
|
||||
name: sync queries
|
||||
name: Sql restart
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{url}}/lst/api/datamart/sync?time=15
|
||||
post {
|
||||
url: {{url}}/lst/api/system/prodsql/restart
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
time: 15
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
16
brunoApi/prodSql/Sql stop.bru
Normal file
16
brunoApi/prodSql/Sql stop.bru
Normal file
@@ -0,0 +1,16 @@
|
||||
meta {
|
||||
name: Sql stop
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{url}}/lst/api/system/prodsql/stop
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
8
brunoApi/prodSql/folder.bru
Normal file
8
brunoApi/prodSql/folder.bru
Normal file
@@ -0,0 +1,8 @@
|
||||
meta {
|
||||
name: prodSql
|
||||
seq: 6
|
||||
}
|
||||
|
||||
auth {
|
||||
mode: inherit
|
||||
}
|
||||
@@ -14,3 +14,7 @@ settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
docs {
|
||||
returns all settings
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@ meta {
|
||||
}
|
||||
|
||||
patch {
|
||||
url: {{url}}/lst/api/settings/something
|
||||
url: {{url}}/lst/api/settings/opendock_sync
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"value" : "true",
|
||||
"active": "false"
|
||||
"value" : "0",
|
||||
"active": "true"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,13 @@ settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
docs {
|
||||
Allows the changing of a setting based on the parameter.
|
||||
|
||||
* when a setting that is being changed is a feature there will be some backgound logic that will stop that features processes and no long work.
|
||||
|
||||
* when the setting is being changed is system the entire app will do a full restart
|
||||
|
||||
* when a seeting is being changed and is standard nothing will happen until the next action is completed. example someone prints a label and you changed the default to 120 second from 90 seconds
|
||||
}
|
||||
|
||||
1
migrations/0014_heavy_kitty_pryde.sql
Normal file
1
migrations/0014_heavy_kitty_pryde.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "settings" ADD COLUMN "seed_version" integer DEFAULT 1;
|
||||
1113
migrations/meta/0014_snapshot.json
Normal file
1113
migrations/meta/0014_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -99,6 +99,13 @@
|
||||
"when": 1771598443244,
|
||||
"tag": "0013_flaky_quicksilver",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 14,
|
||||
"version": "7",
|
||||
"when": 1772012229060,
|
||||
"tag": "0014_heavy_kitty_pryde",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
200
package-lock.json
generated
200
package-lock.json
generated
@@ -31,6 +31,7 @@
|
||||
"morgan": "^1.10.1",
|
||||
"mssql": "^12.2.0",
|
||||
"multer": "^2.0.2",
|
||||
"net-snmp": "^3.26.1",
|
||||
"nodemailer": "^8.0.1",
|
||||
"nodemailer-express-handlebars": "^7.0.0",
|
||||
"pg": "^8.18.0",
|
||||
@@ -54,6 +55,7 @@
|
||||
"@types/morgan": "^1.9.10",
|
||||
"@types/mssql": "^9.1.9",
|
||||
"@types/multer": "^2.0.0",
|
||||
"@types/net-snmp": "^3.23.0",
|
||||
"@types/node": "^25.2.3",
|
||||
"@types/nodemailer": "^7.0.10",
|
||||
"@types/nodemailer-express-handlebars": "^4.0.6",
|
||||
@@ -63,9 +65,7 @@
|
||||
"@types/swagger-ui-express": "^4.1.8",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"commitizen": "^4.3.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"nodemon": "^3.1.11",
|
||||
"npm-check-updates": "^19.3.2",
|
||||
"openapi-types": "^12.1.3",
|
||||
"supertest": "^7.2.2",
|
||||
@@ -4596,6 +4596,26 @@
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/net-snmp": {
|
||||
"version": "3.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/net-snmp/-/net-snmp-3.23.0.tgz",
|
||||
"integrity": "sha512-54Y5NLlQ8isegHTUZdEaIFhR1iz/qlRkQlpkuXfsWjWDVLNfStLmvraaj9ZS7tmcZEltFkb4ZeDBjnSYeFc3+w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^24.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/net-snmp/node_modules/@types/node": {
|
||||
"version": "24.10.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.14.tgz",
|
||||
"integrity": "sha512-OowOUbD1lBCOFIPOZ8xnMIhgqA4sCutMiYOmPHL1PTLt5+y1XA+g2+yC9OOyz8p+deMZqPZLxfMjYIfrKsPeFg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
|
||||
@@ -5392,6 +5412,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asn1-ber": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/asn1-ber/-/asn1-ber-1.2.2.tgz",
|
||||
"integrity": "sha512-CbNem/7hxrjSiOAOOTX4iZxu+0m3jiLqlsERQwwPM1IDR/22M8IPpA1VVndCLw5KtjRYyRODbvAEIfuTogNDng==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/assertion-error": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
||||
@@ -6398,47 +6424,6 @@
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
|
||||
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"rxjs": "7.8.2",
|
||||
"shell-quote": "1.8.3",
|
||||
"supports-color": "8.1.1",
|
||||
"tree-kill": "1.2.2",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"conc": "dist/bin/concurrently.js",
|
||||
"concurrently": "dist/bin/concurrently.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently/node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
||||
@@ -9107,13 +9092,6 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
@@ -11323,6 +11301,16 @@
|
||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/net-snmp": {
|
||||
"version": "3.26.1",
|
||||
"resolved": "https://registry.npmjs.org/net-snmp/-/net-snmp-3.26.1.tgz",
|
||||
"integrity": "sha512-ZWsfchno5Lxj6OOUt4YS+88KLwce4tpnh4pLxiiwUULg3QQsN1n4OYAli4Ch2C+fkjqQXjhoI8rKltQyBVFzxg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asn1-ber": "^1.2.1",
|
||||
"smart-buffer": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -11361,58 +11349,6 @@
|
||||
"nodemailer": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.11",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz",
|
||||
"integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
@@ -12285,13 +12221,6 @@
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||
@@ -12867,19 +12796,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
@@ -12965,19 +12881,6 @@
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
@@ -12988,6 +12891,16 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io": {
|
||||
"version": "4.8.3",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz",
|
||||
@@ -13684,16 +13597,6 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
@@ -13982,13 +13885,6 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"dev:agent": "cd agent/src && tsx watch agent.ts",
|
||||
"dev:db:migrate": "npx drizzle-kit push",
|
||||
"dev:db:generate": "tsc && npx drizzle-kit generate --config=drizzle.config.ts",
|
||||
"build": "rimraf dist && npm run specCheck && npm run lint && npm run dev:db:generate && npm run dev:db:migrate && npm run build:app && npm run build:copySql",
|
||||
"build": "rimraf dist && npm run dev:db:generate && npm run dev:db:migrate && npm run build:app && npm run build:copySql",
|
||||
"build:app": "tsc",
|
||||
"build:agent": "cd agent && tsc -p tsconfig.json",
|
||||
"build:docker": "docker compose up --force-recreate --build -d",
|
||||
@@ -50,6 +50,7 @@
|
||||
"@types/morgan": "^1.9.10",
|
||||
"@types/mssql": "^9.1.9",
|
||||
"@types/multer": "^2.0.0",
|
||||
"@types/net-snmp": "^3.23.0",
|
||||
"@types/node": "^25.2.3",
|
||||
"@types/nodemailer": "^7.0.10",
|
||||
"@types/nodemailer-express-handlebars": "^4.0.6",
|
||||
@@ -88,6 +89,7 @@
|
||||
"morgan": "^1.10.1",
|
||||
"mssql": "^12.2.0",
|
||||
"multer": "^2.0.2",
|
||||
"net-snmp": "^3.26.1",
|
||||
"nodemailer": "^8.0.1",
|
||||
"nodemailer-express-handlebars": "^7.0.0",
|
||||
"pg": "^8.18.0",
|
||||
|
||||
85
scripts/agentController.ps1
Normal file
85
scripts/agentController.ps1
Normal file
@@ -0,0 +1,85 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# config
|
||||
$Servers = @("appserver1", "appserver2") # hostnames or IPs
|
||||
$ServiceName = "MyAppService" # Windows service name (or pm2 process name logic)
|
||||
$AppDir= "C:\Users\matthes01\Documents\lst_v3"
|
||||
$RemoteTempZip = "C:\Windows\Temp\release.zip"
|
||||
$RemoteReleasesRoot = "C:\App\releases"
|
||||
$RemoteCurrent = "C:\App\current"
|
||||
|
||||
#--------------------------------------------------
|
||||
# below this shouldnt really need to be messed with
|
||||
#--------------------------------------------------
|
||||
|
||||
function Show-Menu {
|
||||
Clear-Host
|
||||
Write-Host "==============================="
|
||||
Write-Host " Deployment Menu "
|
||||
Write-Host "==============================="
|
||||
Write-Host "1. Build app"
|
||||
Write-Host "2. Deploy New Release"
|
||||
Write-Host "3. Restart Service"
|
||||
Write-Host "4. Exit"
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Select-Server {
|
||||
param([string[]]$List)
|
||||
for ($i = 0; $i -lt $List.Count; $i++) {
|
||||
Write-Host ("{0}. {1}" -f ($i+1), $List[$i])
|
||||
}
|
||||
$sel = Read-Host "Select server by number"
|
||||
if ($sel -match '^\d+$' -and [int]$sel -ge 1 -and [int]$sel -le $List.Count) {
|
||||
return $List[[int]$sel - 1]
|
||||
} else {
|
||||
Write-Host "Invalid selection"
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
Show-Menu
|
||||
$choice = Read-Host "Select an option"
|
||||
|
||||
switch ($choice) {
|
||||
"1" {
|
||||
try {
|
||||
Push-Location $AppDir
|
||||
Write-Host "Running: npm run build in $AppDir"
|
||||
npm run build
|
||||
|
||||
Write-Host "Build completed successfully."
|
||||
Read-Host -Prompt "Press Enter to continue..."
|
||||
}
|
||||
catch {
|
||||
Write-Host "Build failed: $_"
|
||||
throw
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
"2" {
|
||||
$server = Select-Server -List $Servers
|
||||
if ($null -ne $server) {
|
||||
$zip = Read-Host "Path to zip (local)"
|
||||
Deploy-ToServer -Server $server -ZipPath $zip
|
||||
}
|
||||
}
|
||||
"3" {
|
||||
Write-Host "Restart selected"
|
||||
psql -h localhost -p 5433 -U adm_cowch -d lst_dev -c "SELECT count(*) FROM public.logs;"
|
||||
}
|
||||
"4" {
|
||||
Write-Host "Exiting..."
|
||||
exit
|
||||
}
|
||||
default {
|
||||
Write-Host "Invalid selection"
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
}
|
||||
|
||||
} while ($choice -ne "3")
|
||||
10
scripts/services.ps1
Normal file
10
scripts/services.ps1
Normal file
@@ -0,0 +1,10 @@
|
||||
param (
|
||||
[string]$serviceName,
|
||||
[string]$option,
|
||||
[string]$appPath,
|
||||
[string]$command, # just the command like run start or what ever you have in npm.
|
||||
[string]$description,
|
||||
[string]$remote,
|
||||
[string]$server,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user