Compare commits

...

12 Commits

11 changed files with 756 additions and 467 deletions

View File

@@ -1,16 +1,17 @@
{ {
"types": [ "types": [
{"type": "feat", "section": "🌟 Enhancements"}, { "type": "feat", "section": "🌟 Enhancements" },
{"type": "fix", "section": "🐛 Bug fixes"}, { "type": "fix", "section": "🐛 Bug fixes" },
{"type": "chore", "hidden": false, "section": "📝 Chore"}, { "type": "chore", "hidden": false, "section": "📝 Chore" },
{"type": "docs", "section": "📚 Documentation"}, { "type": "docs", "section": "📚 Documentation" },
{"type": "style", "hidden": true}, { "type": "style", "hidden": true },
{"type": "refactor", "section": "🛠️ Code Refactor"}, { "type": "refactor", "section": "🛠️ Code Refactor" },
{"type": "perf", "hidden": false, "section": "🚀 Performance"}, { "type": "perf", "hidden": false, "section": "🚀 Performance" },
{"type": "test", "section": "📝 Testing Code"}, { "type": "test", "section": "📝 Testing Code" },
{"type": "ci", "section": "📈 Project changes"} { "type": "ci", "hidden": false, "section": "📈 Project changes" },
], { "type": "build", "hidden": true, "section": "📈 Project Builds" }
"commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits/{{hash}}", ],
"compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}", "commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits/{{hash}}",
"header": "# All CHanges to LST can be found below.\n" "compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}",
"header": "# All CHanges to LST can be found below.\n"
} }

View File

@@ -1,5 +1,130 @@
# All CHanges to LST can be found below. # All CHanges to LST can be found below.
## [2.9.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.8.0...v2.9.0) (2025-03-23)
### 📈 Project changes
* **frontend:** added ocme as a proxy in the dev ([eb2c34c](https://git.tuffraid.net/cowch/lstV2/commits/eb2c34c557b72c3387b70addac30a4d8291402d4))
### 📚 Documentation
* **install:** added more env params and an install install stuff ([09d3a70](https://git.tuffraid.net/cowch/lstV2/commits/09d3a7041a18283a5add86ea845a8d7249522769))
* **install:** removed the super secret key ([357c118](https://git.tuffraid.net/cowch/lstV2/commits/357c1183964be0f3c02207c24bc8f83347282211))
* **logs:** changes how logs are put into the db they will be there name vs key ([18daca9](https://git.tuffraid.net/cowch/lstV2/commits/18daca904e0305371c6128988b48d54e3aec9a2a))
* **migration:** added more documents on the install md ([0bd217c](https://git.tuffraid.net/cowch/lstV2/commits/0bd217c727d726d62ddf06a0e44e95c4606361cf))
### 📝 Testing Code
* **ocme:** cycle count intital improvements ([7a22b52](https://git.tuffraid.net/cowch/lstV2/commits/7a22b52c916335c748598b82e78819c325bb8c4c))
* **ocp dash:** more work on the dashboard ([f3c4c26](https://git.tuffraid.net/cowch/lstV2/commits/f3c4c26ef957e6fe359a77f139ad36cdacefb8ef))
* **ocp:** more work on the dashboard ([8324fff](https://git.tuffraid.net/cowch/lstV2/commits/8324fffeb664bff3751ffc26e988a4a506b658a9))
* **returnres:** tryed to make a standard return res but will come back to this later ([58b5842](https://git.tuffraid.net/cowch/lstV2/commits/58b58424abbf98feec0c5442a59f4d055bbd1811))
* **rfid:** more work on the rfid service ([21c3749](https://git.tuffraid.net/cowch/lstV2/commits/21c374903b5cba56ced44b7eb2066ee902fc7bc3))
* **server:** start/stop/restart buttons added. comment [#14](https://git.tuffraid.net/cowch/lstV2/issues/14) ([76bc0db](https://git.tuffraid.net/cowch/lstV2/commits/76bc0db3dd9c48b69e4f6f571181a1f07c48bdeb))
* **streaming logs:** more test but failed again ([08c9b34](https://git.tuffraid.net/cowch/lstV2/commits/08c9b3404f548a167464445ec2f19288a092b0dc))
* **streaming logs:** test for streaming logs ([73eb705](https://git.tuffraid.net/cowch/lstV2/commits/73eb70538e36601cf436aaba244f99d5bd873d34))
* **streaming logs:** will come back to this later this is killing me inside ([97eb73c](https://git.tuffraid.net/cowch/lstV2/commits/97eb73c6d1aef747ef98f5f666fe47622795746f))
* **streaming:** more streaming test ([4db4eea](https://git.tuffraid.net/cowch/lstV2/commits/4db4eea2d12e37809879e96ed4279d6e23e83acc))
* **streaming:** more testing on streaming the lofs ([e82ef76](https://git.tuffraid.net/cowch/lstV2/commits/e82ef76316f0562b57124eb977c86fd2c6a3f332))
### 🌟 Enhancements
* **admincheck:** this check is so we dont use stuff on the wrong servers ([3d08398](https://git.tuffraid.net/cowch/lstV2/commits/3d083986aed528c2f881d6f673c0be03b8986c0b))
* **auth:** add, update were added for adm account in backend only ([d8eddaf](https://git.tuffraid.net/cowch/lstV2/commits/d8eddafcaea9141e9413a122a320649c7dd325e5))
* **auth:** remove all old localstorage if no session ([8fb06c7](https://git.tuffraid.net/cowch/lstV2/commits/8fb06c71d370a27697628077474a261596b567e0))
* **db:** logs, manualprints added ([0914b53](https://git.tuffraid.net/cowch/lstV2/commits/0914b5334119fa705eedddc6c9e8303cb82da551))
* **installer:** added a check for lstv2 already installed ([4696835](https://git.tuffraid.net/cowch/lstV2/commits/4696835c6557c2eae3be6a292144493be9d98f67))
* **logger:** logger service created with its endpoints ([7ec5c5b](https://git.tuffraid.net/cowch/lstV2/commits/7ec5c5beb0a9b02e8b8761908ee75ac2cfd317ee))
* **logger:** streaming logs works server side not frontend for now ([e833c48](https://git.tuffraid.net/cowch/lstV2/commits/e833c48cc8f68af40888ea161100e02f6ad19604))
* **lst:** added in delay global function ([7497432](https://git.tuffraid.net/cowch/lstV2/commits/74974323f0a7bd7c2eaa22024b7a8e91db2868e2))
* **lst:** added prettier config so we have the same formatting across all computers ([132e8d0](https://git.tuffraid.net/cowch/lstV2/commits/132e8d0146318fa9deb673bbcabf0d80c2a6d39f))
* **ocme:** added in ocme service so we can utlize 2 ports ([ae7e3fd](https://git.tuffraid.net/cowch/lstV2/commits/ae7e3fd54e5c256fb82e68f2e935e3b914e43d13))
* **ocme:** cycle count implemeneted ([74bcd6e](https://git.tuffraid.net/cowch/lstV2/commits/74bcd6e805c34e181f0c48310a799daf3afaee66))
* **ocmeserver:** the server was just migrated so it can be upgraded to lstv2 ([e258aae](https://git.tuffraid.net/cowch/lstV2/commits/e258aaead9a56cc4de36c17ed60b0bdaa91019cb))
* **ocp:** added in service plus manual print log ([7165c95](https://git.tuffraid.net/cowch/lstV2/commits/7165c959b9d5b37c0d4b01cb3f5bc27b40cec71d))
* **ports:** added in production port if in production ([121bed5](https://git.tuffraid.net/cowch/lstV2/commits/121bed59fda04b2ad134feb0895428515a1c56d8))
* **scripts:** made moving scripts more proper ([d0a0d08](https://git.tuffraid.net/cowch/lstV2/commits/d0a0d0890255acf890ba402386847b19566c92df))
* **serverdata:** added in huston, sherman. and corrected contact info in westbend ([4908d66](https://git.tuffraid.net/cowch/lstV2/commits/4908d6644a392395e660d382536c0fd31e3d0647))
* **server:** ocpService and loggerService added ([2d3f308](https://git.tuffraid.net/cowch/lstV2/commits/2d3f30887744bddfe22dc764188cf727a5e476df))
* **servers:** added dayton in ([bbd7a17](https://git.tuffraid.net/cowch/lstV2/commits/bbd7a17144e1e1a0faa192139cb1539c2f1ecc5c))
* **settings:** added in setting store ([1cd1d3a](https://git.tuffraid.net/cowch/lstV2/commits/1cd1d3a3e9e1ec1bf16ac2552caf24aa299959bf))
* **settings:** more seed settings ([e597968](https://git.tuffraid.net/cowch/lstV2/commits/e597968777e88289d361fdc01ec683a1f4c80192))
* **trycatch:** added in theo's try catch to reduce the code and love it ([72d52d9](https://git.tuffraid.net/cowch/lstV2/commits/72d52d925677eeeac6d158028114201862b6e2a2))
### 🛠️ Code Refactor
* **auth:** added in correct bycrptjs ([208cd61](https://git.tuffraid.net/cowch/lstV2/commits/208cd615af8250686745aa5b6779706ae267e423))
* **auth:** moved prod back to server as we run 2 instances during migration ([7a15b16](https://git.tuffraid.net/cowch/lstV2/commits/7a15b160ac2393cd66a932e598ffaa5aeda5812f))
* **consume materail:** get token from localstorage as the store isnt wokring properly ([354f326](https://git.tuffraid.net/cowch/lstV2/commits/354f3260a55b53bfb461a37db9d64550bacbfe04))
* **frontend:** added date-fns into the frontend ([bba0aa2](https://git.tuffraid.net/cowch/lstV2/commits/bba0aa2ee4e9b9be1db184da894ce6e96fd2e38f))
* **login:** removed all the data from teh login dropdown as it could cause issues ([5dfece0](https://git.tuffraid.net/cowch/lstV2/commits/5dfece09b7285dda96875bbc740df803d816b92a))
* **login:** removed roles from the login to shrink the jwt ([c9aa41a](https://git.tuffraid.net/cowch/lstV2/commits/c9aa41ab0099b7a05d50d9a981cf7e8a42a04733))
* **production:** changes ocp to viewwer ([ab5af4d](https://git.tuffraid.net/cowch/lstV2/commits/ab5af4deacbeaf1ed93c6231fb98b187f7540ca4))
* **server query:** bumped the refresh from 500ms to 2500ms ([866b6d5](https://git.tuffraid.net/cowch/lstV2/commits/866b6d5120810252b089580d341f3fb1b62e951a))
* **serverdata:** remapped the server list to all be on the E drive and deactivated ([8b8c9ac](https://git.tuffraid.net/cowch/lstV2/commits/8b8c9acb6969b63f157ea95b7d61923bf4bb4eae))
* **server:** removed the websocket wrapper going wiht normal ws ([bb6d523](https://git.tuffraid.net/cowch/lstV2/commits/bb6d523abbd3c9423eddbaab96e297b4850e2aa8))
* **settings:** refactored the admincheck so we can reuse it ([ca0ba7f](https://git.tuffraid.net/cowch/lstV2/commits/ca0ba7fe59f7e19d0de4924a419cce461de4b7a1))
* **settings:** removed the need to login to get the settings ([5945ace](https://git.tuffraid.net/cowch/lstV2/commits/5945ace9f259f6ef418c1621c246982b5b572dc1))
* **settings:** used the common response function created ([316b27e](https://git.tuffraid.net/cowch/lstV2/commits/316b27e3e011a0c0b4ce88ea579290807b8927c5))
* **stores:** added in axios ([3b8f180](https://git.tuffraid.net/cowch/lstV2/commits/3b8f18093ead2a988b2b19d1e8f25db6eaeaaee8))
* **view access:** if role [] then allow them to see it ([e17b8e7](https://git.tuffraid.net/cowch/lstV2/commits/e17b8e7bbe94c25c1bd3414b1db31191c87553d6))
### 🐛 Bug fixes
* **auth:** added in the correct function for days between logins ([ed11b2b](https://git.tuffraid.net/cowch/lstV2/commits/ed11b2b26ff80fde9f94615f740eb5152b16744d))
* **auth:** fixed the getaccess to be getuseraccess as it was orignally ([b9dd6e3](https://git.tuffraid.net/cowch/lstV2/commits/b9dd6e3ae2f5c158dd4827ae0c9db2c6747c57e1))
* **calendar:** this component had a bug and needed a lib update ([93ed2e9](https://git.tuffraid.net/cowch/lstV2/commits/93ed2e9ee8c98edd6a8c47d6e7a0caf6a8e93278))
* **consume material:** when we consumed material the button was never reenabled ([07e47e6](https://git.tuffraid.net/cowch/lstV2/commits/07e47e64ae2f4ddd325a2fdb34c82143c9adf84b)), closes [#15](https://git.tuffraid.net/cowch/lstV2/issues/15)
* **frontend:** removed unwanted import ([10d88f5](https://git.tuffraid.net/cowch/lstV2/commits/10d88f53ebaf670c9f6b3ca59cbbaf4d88f26b9f))
* **loginform:** removed the console log that was left by accident ([2ae3c8b](https://git.tuffraid.net/cowch/lstV2/commits/2ae3c8ba5916b5249135b86b374ac1bf32837478))
* **login:** if we have a wrong password or username we didnt properly error instead we crashed ([2e5de34](https://git.tuffraid.net/cowch/lstV2/commits/2e5de34cb50c79cd60e038492b2397eee69def11))
* **scaler:** fix due to update ([edcfff6](https://git.tuffraid.net/cowch/lstV2/commits/edcfff6cc6cf81e56b5532f0876383659b951a5d))
* **serverlist:** corrected the time by removing teh Z at the end of the time ([f940bcd](https://git.tuffraid.net/cowch/lstV2/commits/f940bcdc9df2d3e9989d49feae88036a6f8c7013))
* **sqlserver:** if we already have a connection just return we dont want to try a second time ([b7773ec](https://git.tuffraid.net/cowch/lstV2/commits/b7773ec02aa26c01530723dc146e0c9f4dae41d3))
### 📝 Chore
* **builds:** bummped lstv1 build ([739e6bb](https://git.tuffraid.net/cowch/lstV2/commits/739e6bbe9fa48fae682f9931a2c8bcb763feb636))
* bump build number to 20 ([0975f4e](https://git.tuffraid.net/cowch/lstV2/commits/0975f4e499a8a2aec0662352cb4496299292d4ea))
* bump build number to 21 ([4e885ce](https://git.tuffraid.net/cowch/lstV2/commits/4e885ce74c02ee1fd95a93402d1d32ecf357b1cb))
* bump build number to 22 ([43ca16d](https://git.tuffraid.net/cowch/lstV2/commits/43ca16dc807b9fa3496498e90a871568f0e5f54c))
* bump build number to 23 ([bff0e77](https://git.tuffraid.net/cowch/lstV2/commits/bff0e77766b49c72d77fa55cfaab2d347a1a75dc))
* bump build number to 24 ([f4433f4](https://git.tuffraid.net/cowch/lstV2/commits/f4433f41926dab72a239fc585ddd1e14acb80c7e))
* bump build number to 25 ([f1979f0](https://git.tuffraid.net/cowch/lstV2/commits/f1979f0fc914f3b94bad1816cd405a6431d1ba4a))
* bump build number to 26 ([491de26](https://git.tuffraid.net/cowch/lstV2/commits/491de26a0bbe6dfca9e1cb068991789c29a09ac0))
* bump build number to 27 ([26ea8d5](https://git.tuffraid.net/cowch/lstV2/commits/26ea8d5e89bb1b44ceb6b205da3ad158c603fca0))
* bump build number to 28 ([1e02d4f](https://git.tuffraid.net/cowch/lstV2/commits/1e02d4fa4fc1a007634da49fe2697d63c89cba18))
* bump build number to 29 ([9796947](https://git.tuffraid.net/cowch/lstV2/commits/9796947db5443c8b5678d7502037458d680e4018))
* bump build number to 30 ([4a48dd2](https://git.tuffraid.net/cowch/lstV2/commits/4a48dd2bb57064953ef6e192c76b91bb844a24de))
* bump build number to 31 ([227e2aa](https://git.tuffraid.net/cowch/lstV2/commits/227e2aa00c2a3e5526e0347c76676de345dfea5d))
* bump build number to 32 ([f035e6f](https://git.tuffraid.net/cowch/lstV2/commits/f035e6f14a9e2123a10010d4f515f78f0c222599))
* bump build number to 33 ([03aa7e5](https://git.tuffraid.net/cowch/lstV2/commits/03aa7e5aeee39b1b390b4da2019f44459487e0a0))
* bump build number to 34 ([f4c44fb](https://git.tuffraid.net/cowch/lstV2/commits/f4c44fb02ba857890af66a2747381ef1c3def25b))
* bump build number to 35 ([8b72a1b](https://git.tuffraid.net/cowch/lstV2/commits/8b72a1b47e715f4146e586e9fdd6abcabd97743d))
* bump build number to 36 ([8a143fb](https://git.tuffraid.net/cowch/lstV2/commits/8a143fbb19d2270b0139a7a4edbce745c477b6b1))
* bump build number to 37 ([b0634d9](https://git.tuffraid.net/cowch/lstV2/commits/b0634d9427f6fff3a239680204b5e6daf6163e37))
* bump build number to 38 ([751b9d5](https://git.tuffraid.net/cowch/lstV2/commits/751b9d5701cf7e81641f154a02041869e1b80c49))
* bump build number to 39 ([6dd5f4b](https://git.tuffraid.net/cowch/lstV2/commits/6dd5f4b61f3a27779980cf14915c4394256eae20))
* bump build number to 40 ([d98a659](https://git.tuffraid.net/cowch/lstV2/commits/d98a6592628f36c654039ccea25db163ddf15e8c))
* bump build number to 41 ([807a4ca](https://git.tuffraid.net/cowch/lstV2/commits/807a4ca6993b5dfa82a45aaf44a2d661c3e03428))
* bump build number to 42 ([196ea00](https://git.tuffraid.net/cowch/lstV2/commits/196ea009720a65c520f5626658ac7885a41796cb))
* bump build number to 43 ([34b80cf](https://git.tuffraid.net/cowch/lstV2/commits/34b80cf2368228b70cd6a79d44ba0f95b5c5941a))
* bump build number to 44 ([808e3d8](https://git.tuffraid.net/cowch/lstV2/commits/808e3d84efa0889077a12cbf8e28df794a51f2bc))
* bump build number to 45 ([38d1043](https://git.tuffraid.net/cowch/lstV2/commits/38d10436069d3db1612a622d9b9e0c7aec04f6dd))
* bump build number to 46 ([532a722](https://git.tuffraid.net/cowch/lstV2/commits/532a7227631cf67664ca41133330d8cfa59f429b))
* bump build number to 47 ([f665406](https://git.tuffraid.net/cowch/lstV2/commits/f6654067f5f01c3ee4855f0cbe07593f13263ce7))
* bump build number to 48 ([97b9c4d](https://git.tuffraid.net/cowch/lstV2/commits/97b9c4db4a67faf68edae4dc1217b28f87d003e8))
* bump build number to 49 ([acb9876](https://git.tuffraid.net/cowch/lstV2/commits/acb9876d9b715894481d31d9bb104e54561710d0))
* **pkg updates:** updated all pkgs ([fb9ee15](https://git.tuffraid.net/cowch/lstV2/commits/fb9ee15bda89257815012023ed5543ef55b5f379))
* **updatescript:** added in so we can do a full install with an env creation for old ([cb3ab66](https://git.tuffraid.net/cowch/lstV2/commits/cb3ab668d866ea9e3428e548d9065a9681174e82))
## [2.8.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.7.0...v2.8.0) (2025-03-16) ## [2.8.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.7.0...v2.8.0) (2025-03-16)

View File

@@ -28,6 +28,7 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"hono": "^4.7.5", "hono": "^4.7.5",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
@@ -3775,6 +3776,15 @@
"url": "https://github.com/sponsors/kossnocorp" "url": "https://github.com/sponsors/kossnocorp"
} }
}, },
"node_modules/date-fns-tz": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz",
"integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==",
"license": "MIT",
"peerDependencies": {
"date-fns": "^3.0.0 || ^4.0.0"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",

View File

@@ -32,6 +32,7 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"hono": "^4.7.5", "hono": "^4.7.5",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",

View File

@@ -1,108 +1,125 @@
import {LstCard} from "@/components/extendedUI/LstCard"; import { LstCard } from "@/components/extendedUI/LstCard";
import { Skeleton } from "@/components/ui/skeleton";
import {Skeleton} from "@/components/ui/skeleton"; import {
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table"; Table,
import {useSessionStore} from "@/lib/store/sessionStore"; TableBody,
import {useModuleStore} from "@/lib/store/useModuleStore"; TableCell,
import {getServers} from "@/utils/querys/servers"; TableHead,
import {useQuery} from "@tanstack/react-query"; TableHeader,
import {useRouter} from "@tanstack/react-router"; TableRow,
import {format} from "date-fns"; } from "@/components/ui/table";
import { useSessionStore } from "@/lib/store/sessionStore";
import { useModuleStore } from "@/lib/store/useModuleStore";
import { getServers } from "@/utils/querys/servers";
import { useQuery } from "@tanstack/react-query";
import { useRouter } from "@tanstack/react-router";
import { format } from "date-fns";
import UpdateServer from "./UpdateServer"; import UpdateServer from "./UpdateServer";
import {adminUrlCheck} from "@/utils/adminUrlCheck"; import { adminUrlCheck } from "@/utils/adminUrlCheck";
import RestartServer from "./RestartServer"; import RestartServer from "./RestartServer";
import StopServer from "./StopServer"; import StopServer from "./StopServer";
import StartServer from "./StartServer"; import StartServer from "./StartServer";
export type Servers = { export type Servers = {
server_id?: string; server_id?: string;
sName?: string; sName?: string;
serverDNS?: string; serverDNS?: string;
plantToken?: string; plantToken?: string;
idAddress: string; idAddress: string;
lastUpdated: string; lastUpdated: string;
isUpgrading: boolean; isUpgrading: boolean;
}; };
export default function ServerPage() { export default function ServerPage() {
const {user, token} = useSessionStore(); const { user, token } = useSessionStore();
const {modules} = useModuleStore(); const { modules } = useModuleStore();
const router = useRouter(); const router = useRouter();
const {data, isError, error, isLoading} = useQuery(getServers(token ?? "")); const { data, isError, error, isLoading } = useQuery(getServers(token ?? ""));
const adminModule = modules.filter((n) => n.name === "admin"); const adminModule = modules.filter((n) => n.name === "admin");
const userLevel = user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) || []; const userLevel =
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) || [];
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) { if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
router.navigate({to: "/"}); router.navigate({ to: "/" });
} }
if (isError) { if (isError) {
return <div>{JSON.stringify(error)}</div>; return <div>{JSON.stringify(error)}</div>;
} }
return (
<LstCard className="m-2 flex place-content-center w-dvh"> console.log(data);
<Table> return (
<TableHeader> <LstCard className="m-2 flex place-content-center w-dvh">
<TableRow> <Table>
<TableHead>Name</TableHead> <TableHeader>
<TableHead>Server</TableHead> <TableRow>
<TableHead>PlantToken</TableHead> <TableHead>Name</TableHead>
<TableHead>IP Address</TableHead> <TableHead>Server</TableHead>
<TableHead>Date Last updated</TableHead> <TableHead>PlantToken</TableHead>
<TableHead>Update Server</TableHead> <TableHead>IP Address</TableHead>
</TableRow> <TableHead>Date Last updated</TableHead>
</TableHeader> <TableHead>Update Server</TableHead>
{isLoading ? ( </TableRow>
<> </TableHeader>
<TableBody> {isLoading ? (
{Array(10) <>
.fill(0) <TableBody>
.map((_, i) => ( {Array(10)
<TableRow key={i}> .fill(0)
<TableCell className="font-medium"> .map((_, i) => (
<Skeleton className="h-4" /> <TableRow key={i}>
</TableCell> <TableCell className="font-medium">
<TableCell> <Skeleton className="h-4" />
<Skeleton className="h-4" /> </TableCell>
</TableCell> <TableCell>
<TableCell> <Skeleton className="h-4" />
<Skeleton className="h-4" /> </TableCell>
</TableCell> <TableCell>
<TableCell> <Skeleton className="h-4" />
<Skeleton className="h-4" /> </TableCell>
</TableCell> <TableCell>
</TableRow> <Skeleton className="h-4" />
))} </TableCell>
</TableBody> </TableRow>
</> ))}
) : ( </TableBody>
<TableBody> </>
{data?.map((server: Servers) => ( ) : (
<TableRow key={server.server_id}> <TableBody>
<TableCell className="font-medium">{server.sName}</TableCell> {data?.map((server: Servers) => {
<TableCell className="font-medium">{server.serverDNS}</TableCell> const strippedDate = server.lastUpdated.replace("Z", ""); // Remove Z
<TableCell className="font-medium">{server.plantToken}</TableCell> const formattedDate = format(strippedDate, "MM/dd/yyyy hh:mm a");
<TableCell className="font-medium">{server.idAddress}</TableCell> return (
<TableCell className="font-medium"> <TableRow key={server.server_id}>
{format(server.lastUpdated, "MM/dd/yyyy hh:mm")} <TableCell className="font-medium">{server.sName}</TableCell>
</TableCell> <TableCell className="font-medium">
<TableCell className="font-medium"> {server.serverDNS}
{adminUrlCheck() && ( </TableCell>
<div className="flex flex-row"> <TableCell className="font-medium">
<UpdateServer server={server} token={token as string} /> {server.plantToken}
<StartServer /> </TableCell>
<StopServer /> <TableCell className="font-medium">
<RestartServer /> {server.idAddress}
</div> </TableCell>
)} <TableCell className="font-medium">{formattedDate}</TableCell>
</TableCell> <TableCell className="font-medium">
</TableRow> {adminUrlCheck() && (
))} <div className="flex flex-row">
</TableBody> <UpdateServer server={server} token={token as string} />
)} <StartServer />
</Table> <StopServer />
</LstCard> <RestartServer />
); </div>
)}
</TableCell>
</TableRow>
);
})}
</TableBody>
)}
</Table>
</LstCard>
);
} }

View File

@@ -1,153 +1,164 @@
import {useSessionStore} from "../../lib/store/sessionStore"; import { useSessionStore } from "../../lib/store/sessionStore";
import {LstCard} from "../extendedUI/LstCard"; import { LstCard } from "../extendedUI/LstCard";
import {CardHeader} from "../ui/card"; import { CardHeader } from "../ui/card";
import {toast} from "sonner"; import { toast } from "sonner";
import {z} from "zod"; import { z } from "zod";
import {useRouter} from "@tanstack/react-router"; import { useRouter } from "@tanstack/react-router";
import {Controller, useForm} from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import {zodResolver} from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import {Label} from "../ui/label"; import { Label } from "../ui/label";
import {Input} from "../ui/input"; import { Input } from "../ui/input";
import {Checkbox} from "../ui/checkbox"; import { Checkbox } from "../ui/checkbox";
import {Button} from "../ui/button"; import { Button } from "../ui/button";
const FormSchema = z.object({ const FormSchema = z.object({
username: z.string().min(1, "You must enter a valid username"), username: z.string().min(1, "You must enter a valid username"),
password: z.string().min(4, "You must enter a valid password"), password: z.string().min(4, "You must enter a valid password"),
rememberMe: z.boolean(), rememberMe: z.boolean(),
}); });
const LoginForm = () => { const LoginForm = () => {
const {setSession} = useSessionStore(); const { setSession } = useSessionStore();
const rememeberMe = localStorage.getItem("rememberMe") === "true"; const rememeberMe = localStorage.getItem("rememberMe") === "true";
const username = localStorage.getItem("username") || ""; const username = localStorage.getItem("username") || "";
const router = useRouter(); const router = useRouter();
const { const {
register, register,
handleSubmit, handleSubmit,
control, control,
formState: {errors}, formState: { errors },
} = useForm<z.infer<typeof FormSchema>>({ } = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
defaultValues: { defaultValues: {
username: username || "", username: username || "",
password: "", password: "",
rememberMe: rememeberMe, rememberMe: rememeberMe,
},
});
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
// Do something with form data
// first update the rememberMe incase it was selected
if (value.rememberMe) {
localStorage.setItem("rememberMe", value.rememberMe.toString());
localStorage.setItem("username", value.username);
} else {
localStorage.removeItem("rememberMe");
localStorage.removeItem("username");
}
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
}, },
}); body: JSON.stringify({
username: value.username,
password: value.password,
}),
});
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => { const data = await response.json();
// Do something with form data
// first update the rememberMe incase it was selected // Store token in localStorage
if (value.rememberMe) { // localStorage.setItem("auth_token", data.data.token);
localStorage.setItem("rememberMe", value.rememberMe.toString()); if (data.success) {
localStorage.setItem("username", value.username); const prod = btoa(`${value.username.toLowerCase()}:${value.password}`);
} else { const prodUser = { ...data.user, prod: prod };
localStorage.removeItem("rememberMe");
localStorage.removeItem("username");
}
try { setSession(prodUser, data.token);
const response = await fetch("/api/auth/login", { toast.success(`You are logged in as ${data.user.username}`);
method: "POST", router.navigate({ to: "/" });
headers: { }
"Content-Type": "application/json",
},
body: JSON.stringify({username: value.username, password: value.password}),
});
const data = await response.json(); if (!data.success) {
toast.error(`${data.message}`);
}
// Store token in localStorage //console.log(data);
// localStorage.setItem("auth_token", data.data.token); } catch (err) {
if (data.success) { toast.error("Invalid credentials");
const prod = btoa(`${value.username.toLowerCase()}:${value.password}`); }
const prodUser = {...data.user, prod: prod}; };
setSession(prodUser, data.token); return (
toast.success(`You are logged in as ${data.user.username}`); <div className="ml-[25%]">
router.navigate({to: "/"}); <LstCard className="p-3 w-96">
} <CardHeader>
<div>
<p className="text-2xl">Login to LST</p>
</div>
</CardHeader>
<hr className="rounded"></hr>
<form onSubmit={handleSubmit(onSubmitLogin)}>
<div>
<Label htmlFor="username" className="m-1">
Username
</Label>
<Input
placeholder="smith001"
{...register("username")}
className={errors.username ? "border-red-500" : ""}
aria-invalid={!!errors.username}
/>
{errors.username && (
<p className="text-red-500 text-sm mt-1">
{errors.username.message}
</p>
)}
</div>
<div>
<>
<Label htmlFor={"password"} className="m-1">
Password
</Label>
<Input
type="password"
{...register("password")}
className={errors.password ? "border-red-500" : ""}
aria-invalid={!!errors.password}
/>
{errors.password && (
<p className="text-red-500 text-sm mt-1">
{errors.password.message}
</p>
)}
</>
</div>
<div className="flex justify-between pt-2">
<div className="flex">
<Controller
render={({ field }) => (
<>
<Checkbox
id="remember"
checked={field.value}
onCheckedChange={field.onChange}
/>
<label
htmlFor="remember"
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
remember me
</label>
</>
)}
control={control}
name="rememberMe"
defaultValue={rememeberMe}
/>
</div>
if (!data.success) { <div className="flex justify-end">
toast.error(`${data.message}`); <Button type="submit">Submit</Button>
} </div>
</div>
console.log(data); </form>
} catch (err) { </LstCard>
toast.error("Invalid credentials"); </div>
} );
};
return (
<div className="ml-[25%]">
<LstCard className="p-3 w-96">
<CardHeader>
<div>
<p className="text-2xl">Login to LST</p>
</div>
</CardHeader>
<hr className="rounded"></hr>
<form onSubmit={handleSubmit(onSubmitLogin)}>
<div>
<Label htmlFor="username" className="m-1">
Username
</Label>
<Input
placeholder="smith001"
{...register("username")}
className={errors.username ? "border-red-500" : ""}
aria-invalid={!!errors.username}
/>
{errors.username && <p className="text-red-500 text-sm mt-1">{errors.username.message}</p>}
</div>
<div>
<>
<Label htmlFor={"password"} className="m-1">
Password
</Label>
<Input
type="password"
{...register("password")}
className={errors.password ? "border-red-500" : ""}
aria-invalid={!!errors.password}
/>
{errors.password && <p className="text-red-500 text-sm mt-1">{errors.password.message}</p>}
</>
</div>
<div className="flex justify-between pt-2">
<div className="flex">
<Controller
render={({field}) => (
<>
<Checkbox
id="remember"
checked={field.value}
onCheckedChange={field.onChange}
/>
<label
htmlFor="remember"
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
remember me
</label>
</>
)}
control={control}
name="rememberMe"
defaultValue={rememeberMe}
/>
</div>
<div className="flex justify-end">
<Button type="submit">Submit</Button>
</div>
</div>
</form>
</LstCard>
</div>
);
}; };
export default LoginForm; export default LoginForm;

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "lstv2", "name": "lstv2",
"version": "2.8.0", "version": "2.9.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "lstv2", "name": "lstv2",
"version": "2.8.0", "version": "2.9.0",
"dependencies": { "dependencies": {
"@dotenvx/dotenvx": "^1.39.0", "@dotenvx/dotenvx": "^1.39.0",
"@hono/node-server": "^1.14.0", "@hono/node-server": "^1.14.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "lstv2", "name": "lstv2",
"version": "2.8.0", "version": "2.9.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"", "dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
@@ -32,7 +32,7 @@
} }
}, },
"admConfig": { "admConfig": {
"build": 47, "build": 50,
"oldBuild": "backend-0.1.3.zip" "oldBuild": "backend-0.1.3.zip"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,153 +1,193 @@
import AdmZip from "adm-zip"; import AdmZip from "adm-zip";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
import {execSync} from "child_process"; import { execSync } from "child_process";
import {createLog} from "../services/logger/logger.js"; import { createLog } from "../services/logger/logger.js";
import {getAppInfo} from "../globalUtils/appInfo.js"; import { getAppInfo } from "../globalUtils/appInfo.js";
// create the ignore list // create the ignore list
const ignoreList = [ const ignoreList = [
".git", ".git",
"builds", "builds",
"server", "server",
"node_modules", "node_modules",
"apiDocsLSTV2", "apiDocsLSTV2",
"testFiles", "testFiles",
".env", ".env",
".gitignore", ".gitignore",
".versionrc.json", ".versionrc.json",
"drizzle-dev.config.ts", "drizzle-dev.config.ts",
"nssm.exe", "nssm.exe",
"postgresql-17.2-3-windows-x64.exe", "postgresql-17.2-3-windows-x64.exe",
// front end ignore // front end ignore
"frontend/node_modules", "frontend/node_modules",
"fonrtend/.env", "fonrtend/.env",
"frontend/public", "frontend/public",
"frontend/src", "frontend/src",
"frontend/.gitignore", "frontend/.gitignore",
"frontend/eslint.config.js", "frontend/eslint.config.js",
"frontend/index.html", "frontend/index.html",
"frontend/package.json", "frontend/package.json",
"frontend/package-lock.json", "frontend/package-lock.json",
"frontend/README.md", "frontend/README.md",
"frontend/tsconfig.json", "frontend/tsconfig.json",
"frontend/tsconfig.app.json", "frontend/tsconfig.app.json",
"frontend/tsconfig.node.json", "frontend/tsconfig.node.json",
"frontend/vite.config.ts", "frontend/vite.config.ts",
"frontend/components.json", "frontend/components.json",
]; ];
const shouldIgnore = (itemPath: any) => { const shouldIgnore = (itemPath: any) => {
const normalizedItemPath = itemPath.replace(/\\/g, "/"); const normalizedItemPath = itemPath.replace(/\\/g, "/");
return ignoreList.some((ignorePattern) => { return ignoreList.some((ignorePattern) => {
const normalizedIgnorePatther = ignorePattern.replace(/\\/g, "/"); const normalizedIgnorePatther = ignorePattern.replace(/\\/g, "/");
return ( return (
normalizedItemPath === normalizedIgnorePatther || normalizedItemPath === normalizedIgnorePatther ||
normalizedItemPath.startsWith(`${normalizedIgnorePatther}/`) normalizedItemPath.startsWith(`${normalizedIgnorePatther}/`)
); );
}); });
}; };
const addToZip = (zip: any, currentPath: string, rootPath: string) => { const addToZip = (zip: any, currentPath: string, rootPath: string) => {
const items = fs.readdirSync(currentPath); const items = fs.readdirSync(currentPath);
items.forEach((item) => { items.forEach((item) => {
const itemPath = path.join(currentPath, item); const itemPath = path.join(currentPath, item);
const relativePath = path.relative(rootPath, itemPath); const relativePath = path.relative(rootPath, itemPath);
// Skip if the item is in the ignore list // Skip if the item is in the ignore list
if (shouldIgnore(relativePath)) { if (shouldIgnore(relativePath)) {
createLog("info", "lst", "zipUpBuild", `Ignoring: ${relativePath}`); createLog("info", "lst", "zipUpBuild", `Ignoring: ${relativePath}`);
return; return;
} }
const stat = fs.statSync(itemPath); const stat = fs.statSync(itemPath);
if (stat.isDirectory()) { if (stat.isDirectory()) {
// If it's a directory, recursively add its contents // If it's a directory, recursively add its contents
addToZip(zip, itemPath, rootPath); addToZip(zip, itemPath, rootPath);
} else { } else {
// If it's a file, add it to the zip with the preserved folder structure // If it's a file, add it to the zip with the preserved folder structure
zip.addLocalFile(itemPath, path.dirname(relativePath)); zip.addLocalFile(itemPath, path.dirname(relativePath));
} }
}); });
}; };
const updateBuildNumber = (appLock: string) => { const updateBuildNumber = (appLock: string) => {
const packagePath = path.join(appLock, "package.json"); // Adjust path if necessary const packagePath = path.join(appLock, "package.json"); // Adjust path if necessary
try { try {
// Read package.json // Read package.json
const pkgData = fs.readFileSync(packagePath, "utf8"); const pkgData = fs.readFileSync(packagePath, "utf8");
const pkgJson = JSON.parse(pkgData); const pkgJson = JSON.parse(pkgData);
// Ensure admConfig exists // Ensure admConfig exists
if (pkgJson.admConfig && typeof pkgJson.admConfig.build === "number") { if (pkgJson.admConfig && typeof pkgJson.admConfig.build === "number") {
// Increment the build number // Increment the build number
pkgJson.admConfig.build += 1; pkgJson.admConfig.build += 1;
// Write the updated data back // Write the updated data back
fs.writeFileSync(packagePath, JSON.stringify(pkgJson, null, 2), "utf8"); fs.writeFileSync(packagePath, JSON.stringify(pkgJson, null, 2), "utf8");
createLog("info", "lst", "zipUpBuild", `Build number updated to: ${pkgJson.admConfig.build}`); createLog(
// Auto-commit changes "info",
execSync("git add package.json"); "lst",
execSync(`git commit -m "chore: bump build number to ${pkgJson.admConfig.build}"`); "zipUpBuild",
} else { `Build number updated to: ${pkgJson.admConfig.build}`
createLog("error", "lst", "zipUpBuild", "admConfig.build is missing or not a number"); );
} // Auto-commit changes
} catch (error) { execSync("git add package.json");
createLog("error", "lst", "zipUpBuild", `Error updating build number: ${error}`); execSync(
`git commit -m "build: bump build number to ${pkgJson.admConfig.build}"`
);
} else {
createLog(
"error",
"lst",
"zipUpBuild",
"admConfig.build is missing or not a number"
);
} }
} catch (error) {
createLog(
"error",
"lst",
"zipUpBuild",
`Error updating build number: ${error}`
);
}
}; };
export const createZip = async (appLock: string) => { export const createZip = async (appLock: string) => {
const app = await getAppInfo(appLock); const app = await getAppInfo(appLock);
const zip = new AdmZip(); const zip = new AdmZip();
//dest path for this app... hard coded for meow will be in db later //dest path for this app... hard coded for meow will be in db later
const destPath = `${process.env.DEVFOLDER}\\builds`; const destPath = `${process.env.DEVFOLDER}\\builds`;
const srcPath = `${process.env.DEVFOLDER}`; const srcPath = `${process.env.DEVFOLDER}`;
addToZip(zip, srcPath, srcPath); addToZip(zip, srcPath, srcPath);
// Write the zip file to disk // Write the zip file to disk
const outputZipPath = path.join(destPath, `${app.name}-${app.version}-${app.admConfig.build}.zip`); const outputZipPath = path.join(
zip.writeZip(outputZipPath); destPath,
`${app.name}-${app.version}-${app.admConfig.build}.zip`
);
zip.writeZip(outputZipPath);
createLog("info", "lst", "zipUpBuild", `Zip file created at ${outputZipPath}`); createLog(
updateBuildNumber(appLock); "info",
"lst",
"zipUpBuild",
`Zip file created at ${outputZipPath}`
);
updateBuildNumber(appLock);
// only keep the last 5 builds for the type we have. // only keep the last 5 builds for the type we have.
try { try {
const appFiles = fs const appFiles = fs
.readdirSync(destPath) .readdirSync(destPath)
.filter((file) => file.startsWith(app.name)) // Ensure only backend files are matched .filter((file) => file.startsWith(app.name)) // Ensure only backend files are matched
.map((file) => ({ .map((file) => ({
name: file, name: file,
time: fs.statSync(path.join(destPath, file)).mtime.getTime(), time: fs.statSync(path.join(destPath, file)).mtime.getTime(),
})) }))
.sort((a, b) => a.time - b.time); // Sort by modification time (oldest first) .sort((a, b) => a.time - b.time); // Sort by modification time (oldest first)
createLog("info", "lst", "zipUpBuild", `app Files (sorted by time):", ${JSON.stringify(appFiles)}`); createLog(
"info",
"lst",
"zipUpBuild",
`app Files (sorted by time):", ${JSON.stringify(appFiles)}`
);
if (appFiles.length > 5) { if (appFiles.length > 5) {
appFiles.slice(0, -5).forEach((file) => { appFiles.slice(0, -5).forEach((file) => {
const filePath = path.join(destPath, file.name); const filePath = path.join(destPath, file.name);
try { try {
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
createLog("info", "lst", "zipUpBuild", `Deleted: ${file.name}`); createLog("info", "lst", "zipUpBuild", `Deleted: ${file.name}`);
} catch (error: any) { } catch (error: any) {
createLog("error", "lst", "zipUpBuild", `Failed to delete ${file.name}: ${error.message}`); createLog(
} "error",
}); "lst",
} else { "zipUpBuild",
createLog("info", "lst", "zipUpBuild", "No files to delete."); `Failed to delete ${file.name}: ${error.message}`
);
} }
} catch (error: any) { });
createLog("error", "lst", "zipUpBuild", `Error reading directory or deleting files:", ${error.message}`); } else {
createLog("info", "lst", "zipUpBuild", "No files to delete.");
} }
} catch (error: any) {
createLog(
"error",
"lst",
"zipUpBuild",
`Error reading directory or deleting files:", ${error.message}`
);
}
}; };
//createZip("C:\\Users\\matthes01\\Documents\\lstv2"); //createZip("C:\\Users\\matthes01\\Documents\\lstv2");
@@ -155,16 +195,16 @@ export const createZip = async (appLock: string) => {
// Only call `createZip` if the script is executed directly // Only call `createZip` if the script is executed directly
if (process.argv.length > 2) { if (process.argv.length > 2) {
const location = process.argv[2]; const location = process.argv[2];
if (!location) { if (!location) {
createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
process.exit(1);
} else {
createLog("info", "lst", "zipUpBuild", "Startiing the zip process.");
}
createZip(location);
} else {
createLog("error", "lst", "zipUpBuild", "Error: No location provided."); createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
process.exit(1);
} else {
createLog("info", "lst", "zipUpBuild", "Startiing the zip process.");
}
createZip(location);
} else {
createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
} }

View File

@@ -1,10 +1,7 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { apiHit } from "../../../../globalUtils/apiHits.js";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import type { CustomJwtPayload } from "../../../../types/jwtToken.js"; import type { CustomJwtPayload } from "../../../../types/jwtToken.js";
import { authMiddleware } from "../../middleware/authMiddleware.js"; import { authMiddleware } from "../../middleware/authMiddleware.js";
import hasCorrectRole from "../../middleware/roleCheck.js";
import { roleCheck } from "../../controllers/userRoles/getUserAccess.js"; import { roleCheck } from "../../controllers/userRoles/getUserAccess.js";
const { verify } = jwt; const { verify } = jwt;
@@ -16,10 +13,10 @@ const responseSchema = z.object({
app.openapi( app.openapi(
createRoute({ createRoute({
tags: ["Auth:user"], tags: ["auth:user"],
summary: "returns the users access", summary: "returns the users access",
method: "get", method: "get",
path: "/getAccess", path: "/getuseraccess",
middleware: [authMiddleware], middleware: [authMiddleware],
responses: { responses: {
200: { 200: {

View File

@@ -1,111 +1,198 @@
import sql from "mssql"; import sql from "mssql";
import {prodSqlConfig} from "./utils/prodServerConfig.js"; import { prodSqlConfig } from "./utils/prodServerConfig.js";
import {createLog} from "../logger/logger.js"; import { createLog } from "../logger/logger.js";
import {db} from "../../../database/dbclient.js"; import { db } from "../../../database/dbclient.js";
import {settings} from "../../../database/schema/settings.js"; import { settings } from "../../../database/schema/settings.js";
import {eq} from "drizzle-orm"; import { eq } from "drizzle-orm";
import {installed} from "../../index.js"; import { installed } from "../../index.js";
import {checkHostnamePort} from "../../globalUtils/pingServer.js"; import { checkHostnamePort } from "../../globalUtils/pingServer.js";
let pool: any; let pool: any;
let connected: boolean = false; let connected: boolean = false;
export const initializeProdPool = async () => { export const initializeProdPool = async () => {
if (!installed) { if (!installed) {
createLog("info", "lst", "sqlProd", "The server was not installed will reconnect in 5 seconds"); createLog(
setTimeout(() => { "info",
initializeProdPool(); "lst",
}, 5 * 1000); "sqlProd",
"The server was not installed will reconnect in 5 seconds"
);
setTimeout(() => {
initializeProdPool();
}, 5 * 1000);
return {success: false, message: "The server is not installed."}; return { success: false, message: "The server is not installed." };
} }
const dbServer = await db.select().from(settings).where(eq(settings.name, "dbServer")); const dbServer = await db
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`); .select()
.from(settings)
.where(eq(settings.name, "dbServer"));
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);
if (!serverUp) { if (!serverUp) {
createLog("error", "lst", "server", `The sql ${dbServer[0].value} is not reachable`); createLog(
return {success: false, message: `The sql ${dbServer[0].value} is not reachable`}; "error",
} "lst",
"server",
`The sql ${dbServer[0].value} is not reachable`
);
return {
success: false,
message: `The sql ${dbServer[0].value} is not reachable`,
};
}
// make sure the server is not set to localhost this will prevent some weird issues later but can be localhost on the dev // make sure the server is not set to localhost this will prevent some weird issues later but can be localhost on the dev
const serverLoc = await db.select().from(settings).where(eq(settings.name, "dbServer")); const serverLoc = await db
if (serverLoc[0].value === "localhost" && process.env.NODE_ENV !== "development") { .select()
createLog("error", "lst", "sqlProd", "The server is set to localhost, and you are not in development mode."); .from(settings)
return {success: false, message: "The server is set to localhost, and you are not in development mode."}; .where(eq(settings.name, "dbServer"));
} if (
serverLoc[0].value === "localhost" &&
process.env.NODE_ENV !== "development"
) {
createLog(
"error",
"lst",
"sqlProd",
"The server is set to localhost, and you are not in development mode."
);
return {
success: false,
message:
"The server is set to localhost, and you are not in development mode.",
};
}
// if you were restarting from the endpoint you get this lovely error // if you were restarting from the endpoint you get this lovely error
if (connected) { if (connected) {
createLog("error", "lst", "sqlProd", "There is already a connection."); createLog("error", "lst", "sqlProd", "There is already a connection.");
return {success: false, message: "There is already a connection."}; return { success: false, message: "There is already a connection." };
} }
try { try {
const config = await prodSqlConfig(); const config = await prodSqlConfig();
pool = await sql.connect(config!); pool = await sql.connect(config!);
createLog("info", "lst", "sqlProd", `Connected to ${config?.server}, and looking at ${config?.database}`); createLog(
connected = true; "info",
return {success: true, message: "The sql server connection has been closed"}; "lst",
} catch (error) { "sqlProd",
createLog("error", "lst", "sqlProd", `${JSON.stringify(error)}, "There was an error connecting to the pool."`); `Connected to ${config?.server}, and looking at ${config?.database}`
throw new Error("There was an error closing the sql connection"); );
} connected = true;
return {
success: true,
message: "The sql server connection has been closed",
};
} catch (error) {
createLog(
"error",
"lst",
"sqlProd",
`${JSON.stringify(error)}, "There was an error connecting to the pool."`
);
throw new Error("There was an error closing the sql connection");
}
}; };
export const closePool = async () => { export const closePool = async () => {
try { if (!connected) {
await pool.close(); createLog(
createLog("info", "lst", "sqlProd", "Connection pool closed"); "error",
connected = false; "lst",
return {success: true, message: "The sql server connection has been closed"}; "sqlProd",
} catch (error) { "There is no connection a connection."
createLog( );
"error", return { success: false, message: "There is already a connection." };
"lst", }
"sqlProd", try {
`${JSON.stringify(error)}, "There was an error closing the sql connection"` await pool.close();
); createLog("info", "lst", "sqlProd", "Connection pool closed");
throw new Error("There was an error closing the sql connection"); connected = false;
} return {
success: true,
message: "The sql server connection has been closed",
};
} catch (error) {
createLog(
"error",
"lst",
"sqlProd",
`${JSON.stringify(
error
)}, "There was an error closing the sql connection"`
);
throw new Error("There was an error closing the sql connection");
}
}; };
export async function query(queryToRun: string, name: string) { export async function query(queryToRun: string, name: string) {
/** /**
* Just an extra catch incase someone tried to run a query while we were not connected to the server or sql server * Just an extra catch incase someone tried to run a query while we were not connected to the server or sql server
*/ */
const dbServer = await db.select().from(settings).where(eq(settings.name, "dbServer")); const dbServer = await db
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`); .select()
.from(settings)
.where(eq(settings.name, "dbServer"));
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);
if (!serverUp) { if (!serverUp) {
createLog("error", "lst", "server", `The sql ${dbServer[0].value} is not reachable`); createLog(
return {success: false, message: `The sql ${dbServer[0].value} is not reachable`}; "error",
"lst",
"server",
`The sql ${dbServer[0].value} is not reachable`
);
return {
success: false,
message: `The sql ${dbServer[0].value} is not reachable`,
};
}
if (!connected) {
createLog(
"error",
"lst",
"server",
`The sql ${dbServer[0].value} is not connected`
);
return {
success: false,
message: `The sql ${dbServer[0].value} is not not connected`,
};
}
/**
* We no longer need to send over the plant token change as we do it inside the query function.
*/
const plantToken = await db
.select()
.from(settings)
.where(eq(settings.name, "plantToken"));
const query = queryToRun.replaceAll("test1", plantToken[0].value);
try {
const result = await pool.request().query(query);
return result.recordset;
} catch (error: any) {
if (error.code === "ETIMEOUT") {
createLog(
"error",
"lst",
"sqlProd",
`${JSON.stringify(error)}, ${name} did not run due to a timeout.`
);
throw new Error(`${name} query did not run due to a timeout.`);
} }
if (!connected) { if (error.code === "EREQUEST") {
createLog("error", "lst", "server", `The sql ${dbServer[0].value} is not connected`); throw new Error(
return {success: false, message: `The sql ${dbServer[0].value} is not not connected`}; `${name} encoutnered an error ${error.originalError.info.message}`
);
} }
/**
* We no longer need to send over the plant token change as we do it inside the query function.
*/
const plantToken = await db.select().from(settings).where(eq(settings.name, "plantToken"));
const query = queryToRun.replaceAll("test1", plantToken[0].value);
try { //console.log(error.originalError.info.message);
const result = await pool.request().query(query); //EREQUEST
//throw new Error(`${name} encoutnered an error ${error.code}`);
return result.recordset; }
} catch (error: any) {
if (error.code === "ETIMEOUT") {
createLog("error", "lst", "sqlProd", `${JSON.stringify(error)}, ${name} did not run due to a timeout.`);
throw new Error(`${name} query did not run due to a timeout.`);
}
if (error.code === "EREQUEST") {
throw new Error(`${name} encoutnered an error ${error.originalError.info.message}`);
}
//console.log(error.originalError.info.message);
//EREQUEST
//throw new Error(`${name} encoutnered an error ${error.code}`);
}
} }