diff --git a/.vscode/settings.json b/.vscode/settings.json index a18517a..d2f2a64 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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", diff --git a/backend/app.ts b/backend/app.ts index fccf02a..e712792 100644 --- a/backend/app.ts +++ b/backend/app.ts @@ -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 }; }; diff --git a/backend/configs/scaler.config.ts b/backend/configs/scaler.config.ts index 26c99bd..03bfe88 100644 --- a/backend/configs/scaler.config.ts +++ b/backend/configs/scaler.config.ts @@ -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: { diff --git a/backend/db/schema/settings.schema.ts b/backend/db/schema/settings.schema.ts index 54d0662..76ff0ec 100644 --- a/backend/db/schema/settings.schema.ts +++ b/backend/db/schema/settings.schema.ts @@ -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().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(), diff --git a/backend/db/schema/stats.schema.ts b/backend/db/schema/stats.schema.ts new file mode 100644 index 0000000..a534c05 --- /dev/null +++ b/backend/db/schema/stats.schema.ts @@ -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; diff --git a/backend/middleware/featureActive.middleware.ts b/backend/middleware/featureActive.middleware.ts new file mode 100644 index 0000000..7eba93a --- /dev/null +++ b/backend/middleware/featureActive.middleware.ts @@ -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(); + }; +}; diff --git a/backend/opendock/openDockRreleaseMonitor.utils.ts b/backend/opendock/openDockRreleaseMonitor.utils.ts index 1af8b1c..f8fe653 100644 --- a/backend/opendock/openDockRreleaseMonitor.utils.ts +++ b/backend/opendock/openDockRreleaseMonitor.utils.ts @@ -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}'`), diff --git a/backend/opendock/opendock.routes.ts b/backend/opendock/opendock.routes.ts index 05f7496..74bc81f 100644 --- a/backend/opendock/opendock.routes.ts +++ b/backend/opendock/opendock.routes.ts @@ -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); diff --git a/backend/scaler/opendockGetRelease.spec.ts b/backend/scaler/opendockGetRelease.spec.ts new file mode 100644 index 0000000..85160a1 --- /dev/null +++ b/backend/scaler/opendockGetRelease.spec.ts @@ -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", + }, + }, + }, + }, + }, + }, + }, + }, + }, +}; diff --git a/backend/server.ts b/backend/server.ts index dcad8ec..c24de47 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -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); diff --git a/backend/system/settings.route.ts b/backend/system/settings.route.ts index f92f6e3..144179a 100644 --- a/backend/system/settings.route.ts +++ b/backend/system/settings.route.ts @@ -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) { diff --git a/backend/system/settingsBase.controller.ts b/backend/system/settingsBase.controller.ts index e69de29..bde460e 100644 --- a/backend/system/settingsBase.controller.ts +++ b/backend/system/settingsBase.controller.ts @@ -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"); + } +}; diff --git a/backend/system/settingsFeatures.controller.ts b/backend/system/settingsFeatures.controller.ts new file mode 100644 index 0000000..2720a15 --- /dev/null +++ b/backend/system/settingsFeatures.controller.ts @@ -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); + } +}; diff --git a/backend/system/settingsUpdate.route.ts b/backend/system/settingsUpdate.route.ts index 00d3c73..6f970a6 100644 --- a/backend/system/settingsUpdate.route.ts +++ b/backend/system/settingsUpdate.route.ts @@ -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, }); }); diff --git a/backend/utils/croner.utils.ts b/backend/utils/croner.utils.ts index 0445776..4e38600 100644 --- a/backend/utils/croner.utils.ts +++ b/backend/utils/croner.utils.ts @@ -18,9 +18,10 @@ export interface JobInfo { // Store running cronjobs export const runningCrons: Record = {}; +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 = {}; // * │ │ │ │ │ │ ┌──── (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.`, + ); } }; diff --git a/brunoApi/auth/Register.bru b/brunoApi/auth/Register.bru new file mode 100644 index 0000000..f237003 --- /dev/null +++ b/brunoApi/auth/Register.bru @@ -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 +} diff --git a/brunoApi/collection.bru b/brunoApi/collection.bru index e69de29..8428a70 100644 --- a/brunoApi/collection.bru +++ b/brunoApi/collection.bru @@ -0,0 +1,3 @@ +docs { + All Api endpoints to the logistics support tool +} diff --git a/brunoApi/datamart/Get queries.bru b/brunoApi/datamart/Get queries.bru index 6a56320..f0a788d 100644 --- a/brunoApi/datamart/Get queries.bru +++ b/brunoApi/datamart/Get queries.bru @@ -5,7 +5,7 @@ meta { } get { - url: {{url}}/lst/api/datamart/deliveryByDateRange + url: {{url}}/lst/api/datamart body: none auth: inherit } diff --git a/brunoApi/datamart/Run Query.bru b/brunoApi/datamart/Run Query.bru new file mode 100644 index 0000000..38df4b6 --- /dev/null +++ b/brunoApi/datamart/Run Query.bru @@ -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 +} diff --git a/brunoApi/datamart/add new query.bru b/brunoApi/datamart/add new query.bru deleted file mode 100644 index b2a5b79..0000000 --- a/brunoApi/datamart/add new query.bru +++ /dev/null @@ -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 -} diff --git a/brunoApi/datamart/update new query.bru b/brunoApi/datamart/update new query.bru deleted file mode 100644 index 95c8ff5..0000000 --- a/brunoApi/datamart/update new query.bru +++ /dev/null @@ -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 -} diff --git a/brunoApi/prodSql/Sql Start.bru b/brunoApi/prodSql/Sql Start.bru new file mode 100644 index 0000000..b11be38 --- /dev/null +++ b/brunoApi/prodSql/Sql Start.bru @@ -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 +} diff --git a/brunoApi/datamart/sync queries.bru b/brunoApi/prodSql/Sql restart.bru similarity index 51% rename from brunoApi/datamart/sync queries.bru rename to brunoApi/prodSql/Sql restart.bru index 640999e..85defb3 100644 --- a/brunoApi/datamart/sync queries.bru +++ b/brunoApi/prodSql/Sql restart.bru @@ -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 diff --git a/brunoApi/prodSql/Sql stop.bru b/brunoApi/prodSql/Sql stop.bru new file mode 100644 index 0000000..75c5e07 --- /dev/null +++ b/brunoApi/prodSql/Sql stop.bru @@ -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 +} diff --git a/brunoApi/prodSql/folder.bru b/brunoApi/prodSql/folder.bru new file mode 100644 index 0000000..e3ed553 --- /dev/null +++ b/brunoApi/prodSql/folder.bru @@ -0,0 +1,8 @@ +meta { + name: prodSql + seq: 6 +} + +auth { + mode: inherit +} diff --git a/brunoApi/system/Get Settings.bru b/brunoApi/system/Get Settings.bru index ecb645c..01f912b 100644 --- a/brunoApi/system/Get Settings.bru +++ b/brunoApi/system/Get Settings.bru @@ -14,3 +14,7 @@ settings { encodeUrl: true timeout: 0 } + +docs { + returns all settings +} diff --git a/brunoApi/system/updateSetting.bru b/brunoApi/system/updateSetting.bru index 87ca359..fbe19c6 100644 --- a/brunoApi/system/updateSetting.bru +++ b/brunoApi/system/updateSetting.bru @@ -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 +} diff --git a/migrations/0014_heavy_kitty_pryde.sql b/migrations/0014_heavy_kitty_pryde.sql new file mode 100644 index 0000000..bc37b83 --- /dev/null +++ b/migrations/0014_heavy_kitty_pryde.sql @@ -0,0 +1 @@ +ALTER TABLE "settings" ADD COLUMN "seed_version" integer DEFAULT 1; \ No newline at end of file diff --git a/migrations/meta/0014_snapshot.json b/migrations/meta/0014_snapshot.json new file mode 100644 index 0000000..3de092e --- /dev/null +++ b/migrations/meta/0014_snapshot.json @@ -0,0 +1,1113 @@ +{ + "id": "07ac9d3e-db02-42f8-ba47-9e7ecabab07a", + "prevId": "4b3010f1-d9d4-44dd-84bf-62a0ea763ae1", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.job_audit_log": { + "name": "job_audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "job_name": { + "name": "job_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "finished_at": { + "name": "finished_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_stack": { + "name": "error_stack", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meta_data": { + "name": "meta_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_job_audit_logs_cleanup": { + "name": "idx_job_audit_logs_cleanup", + "columns": [ + { + "expression": "start_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apikey": { + "name": "apikey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 86400000 + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 10 + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_request": { + "name": "last_request", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "apikey_userId_idx": { + "name": "apikey_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "apikey_user_id_user_id_fk": { + "name": "apikey_user_id_user_id_fk", + "tableFrom": "apikey", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.jwks": { + "name": "jwks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.datamart": { + "name": "datamart", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "query": { + "name": "query", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "public_access": { + "name": "public_access", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "add_date": { + "name": "add_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "add_user": { + "name": "add_user", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'lst-system'" + }, + "upd_date": { + "name": "upd_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "upd_user": { + "name": "upd_user", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'lst-system'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "datamart_name_unique": { + "name": "datamart_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.logs": { + "name": "logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "module": { + "name": "module", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subModule": { + "name": "subModule", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stack": { + "name": "stack", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "checked": { + "name": "checked", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.opendock_apt": { + "name": "opendock_apt", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release": { + "name": "release", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "open_dock_apt_id": { + "name": "open_dock_apt_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appointment": { + "name": "appointment", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "upd_date": { + "name": "upd_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "opendock_apt_release_unique": { + "name": "opendock_apt_release_unique", + "nullsNotDistinct": false, + "columns": [ + "release" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "settings_id": { + "name": "settings_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "moduleName": { + "name": "moduleName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "roles": { + "name": "roles", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[\"systemAdmin\"]'::jsonb" + }, + "settingType": { + "name": "settingType", + "type": "setting_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "seed_version": { + "name": "seed_version", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1 + }, + "add_User": { + "name": "add_User", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'LST_System'" + }, + "add_Date": { + "name": "add_Date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "upd_User": { + "name": "upd_User", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'LST_System'" + }, + "upd_date": { + "name": "upd_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "name": { + "name": "name", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.setting_type": { + "name": "setting_type", + "schema": "public", + "values": [ + "feature", + "system", + "standard" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index 9ac17b6..c728143 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -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 } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 66449b0..80059e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 1d19449..48e6655 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/scripts/agentController.ps1 b/scripts/agentController.ps1 new file mode 100644 index 0000000..c349c6c --- /dev/null +++ b/scripts/agentController.ps1 @@ -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") \ No newline at end of file diff --git a/scripts/services.ps1 b/scripts/services.ps1 new file mode 100644 index 0000000..16d1629 --- /dev/null +++ b/scripts/services.ps1 @@ -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, +) +