Compare commits

...

2 Commits

32 changed files with 2283 additions and 88 deletions

View File

@@ -5,14 +5,14 @@ meta {
} }
post { post {
url: {{url}}/lst/api/user/resetPassword url: {{url}}/lst/api/user/resetpassword
body: json body: json
auth: inherit auth: inherit
} }
body:json { body:json {
{ {
"email": "blake.matthes@alpla.com", "email": "blake.matthes@alpla.com"
} }
} }

View File

@@ -5,18 +5,15 @@ meta {
} }
post { post {
url: http://localhost:4200/api/auth/reset-password/gCo7OUP6CH2Qu7obhvOrhuo9?callbackURL url: http://localhost:4200/lst/api/auth/reset-password
body: json body: json
auth: inherit auth: inherit
} }
params:query {
callbackURL:
}
body:json { body:json {
{ {
"newPassword": "nova0511" "newPassword": "nova0511",
"token": "8ZtCt8c5BRwtcqD9k5RceLhx"
} }
} }

View File

@@ -1,11 +1,11 @@
meta { meta {
name: Health name: Stats
type: http type: http
seq: 1 seq: 1
} }
get { get {
url: {{url}}/lst/api/system/health url: {{url}}/lst/api/system/stats
body: none body: none
auth: inherit auth: inherit
} }

View File

@@ -1,4 +1,4 @@
vars { vars {
url: http://localhost:4200 url: https://usmcd1vms036.alpla.net
session_cookie: session_cookie:
} }

View File

@@ -1,16 +1,13 @@
import type { Express, Request, Response } from "express"; import type { Express, Request, Response } from "express";
import healthRoutes from "./routes/healthRoutes.js";
import { setupAuthRoutes } from "../auth/routes/routes.js"; import { setupAuthRoutes } from "../auth/routes/routes.js";
import { setupAdminRoutes } from "../admin/routes.js"; import { setupAdminRoutes } from "../admin/routes.js";
import { setupSystemRoutes } from "../system/routes.js";
export const setupRoutes = (app: Express, basePath: string) => { export const setupRoutes = (app: Express, basePath: string) => {
// Root / health check
app.use(basePath + "/api/system/health", healthRoutes);
// all routes // all routes
setupAuthRoutes(app, basePath); setupAuthRoutes(app, basePath);
setupAdminRoutes(app, basePath); setupAdminRoutes(app, basePath);
setupSystemRoutes(app, basePath);
// always try to go to the app weather we are in dev or in production. // always try to go to the app weather we are in dev or in production.
app.get(basePath + "/", (req: Request, res: Response) => { app.get(basePath + "/", (req: Request, res: Response) => {

View File

@@ -1,10 +0,0 @@
import { Router } from "express";
const router = Router();
// GET /health
router.get("/", (req, res) => {
res.json({ status: "ok", uptime: process.uptime() });
});
export default router;

View File

@@ -0,0 +1,6 @@
import type { Express, Request, Response } from "express";
import stats from "./routes/stats.js";
export const setupSystemRoutes = (app: Express, basePath: string) => {
app.use(basePath + "/api/system/stats", stats);
};

View File

@@ -0,0 +1,34 @@
import { Router } from "express";
import { tryCatch } from "../../../pkg/utils/tryCatch.js";
import { db } from "../../../pkg/db/db.js";
import {
serverStats,
type ServerStats,
} from "../../../pkg/db/schema/serverstats.js";
import { eq } from "drizzle-orm";
import { format } from "date-fns-tz";
import { checkBuildUpdate } from "../utlis/checkForBuild.js";
const router = Router();
// GET /health
router.get("/", async (req, res) => {
const { data, error } = await tryCatch(
db.select().from(serverStats).where(eq(serverStats.id, "serverStats"))
);
if (error || !data) {
res.status(400).json({ error: error });
}
const statData = data as ServerStats[];
res.json({
status: "ok",
uptime: process.uptime(),
build: statData[0]?.build,
pendingUpdateFile: await checkBuildUpdate(["."]),
lastUpdate: format(statData[0].lastUpdate!, "MM/dd/yyyy HH:mm"),
});
});
export default router;

View File

@@ -0,0 +1,28 @@
import { readdir } from "fs/promises";
import { resolve, join } from "path";
/**
* Looks in one or more relative/absolute directories for a .zip file.
* Returns the **full path** to the first .zip file found, or null if none.
*/
export async function checkBuildUpdate(dirs: string[]): Promise<string | null> {
for (const inputDir of dirs) {
const dir = resolve(inputDir); // resolves "../../" relative to cwd
try {
const files = await readdir(dir);
const zipFile = files.find((file) =>
file.toLowerCase().endsWith(".zip")
);
if (zipFile) {
//return join(dir, zipFile);
return zipFile;
}
} catch (err) {
// Ignore if directory doesn't exist, allow search to continue
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
throw err;
}
}
}
return null;
}

View File

@@ -0,0 +1,12 @@
import type { InferInsertModel, InferSelectModel } from "drizzle-orm";
import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import type z from "zod";
export const serverStats = pgTable("serverStats", {
id: text("id").primaryKey().default("serverStats"),
build: integer("build").notNull().default(1),
lastUpdate: timestamp("lastUpdate").defaultNow(),
});
export type ServerStats = InferSelectModel<typeof serverStats>; // SELECT type
//export type NewServerStats = InferInsertModel<typeof serverStats, "insert">; // INSERT type

View File

@@ -3,3 +3,10 @@
APP_MODE=dev APP_MODE=dev
# The port is only needed if you plan to use a different port but you will need to change it in the wrapper too # The port is only needed if you plan to use a different port but you will need to change it in the wrapper too
PORT=8080 PORT=8080
# postgres connection
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=password
DATABASE_DB=lst

View File

@@ -5,6 +5,8 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"lst.net/pkg"
) )
// ---- Handle Build Counter ---- // ---- Handle Build Counter ----
@@ -22,5 +24,10 @@ func bumpBuild() (int, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
// update the db so we have the build number in here going forward.
pkg.UpdateServerStats(int64(buildNum))
return buildNum, nil return buildNum, nil
} }

View File

@@ -27,6 +27,9 @@ require (
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/hirochachacha/go-smb2 v1.1.0 // indirect github.com/hirochachacha/go-smb2 v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.6 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect

View File

@@ -43,6 +43,12 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI= github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE= github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=

View File

@@ -0,0 +1,48 @@
package pkg
import (
"context"
"fmt"
"os"
"github.com/jackc/pgx/v5"
)
func UpdateServerStats(buildNumber int64) {
//url := "postgres://username:password@localhost:5432/database_name"
url := fmt.Sprintf(
"postgres://%v:%v@%v:%v/%v",
os.Getenv("DATABASE_USER"),
os.Getenv("DATABASE_PASSWORD"),
os.Getenv("DATABASE_HOST"),
os.Getenv("DATABASE_PORT"),
os.Getenv("DATABASE_DB"),
)
ctx := context.Background()
conn, err := pgx.Connect(ctx, url)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
//os.Exit(1)
}
defer conn.Close(ctx)
sql := `
INSERT INTO public."serverStats" (id, build, "lastUpdate")
VALUES ($1, $2, NOW())
ON CONFLICT (id) DO UPDATE
SET build = EXCLUDED.build,
"lastUpdate" = NOW();
`
_, err = conn.Exec(ctx, sql, "serverStats", buildNumber)
if err != nil {
fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
//os.Exit(1)
}
}

View File

@@ -15,6 +15,7 @@ import (
"time" "time"
socketio "github.com/googollee/go-socket.io" socketio "github.com/googollee/go-socket.io"
"lst.net/pkg"
) )
func UpdateApp(server *socketio.Server) <-chan string { func UpdateApp(server *socketio.Server) <-chan string {
@@ -54,6 +55,7 @@ func UpdateApp(server *socketio.Server) <-chan string {
updates <- msg updates <- msg
server.BroadcastToRoom("/", "update", "updateLogs", msg) server.BroadcastToRoom("/", "update", "updateLogs", msg)
} }
msg := "Stopping the services" msg := "Stopping the services"
updates <- msg updates <- msg
server.BroadcastToRoom("/", "update", "updateLogs", msg) server.BroadcastToRoom("/", "update", "updateLogs", msg)
@@ -127,6 +129,16 @@ func UpdateApp(server *socketio.Server) <-chan string {
msg = "Deployment finished successfully" msg = "Deployment finished successfully"
updates <- msg updates <- msg
// remove the prefix
cleaned := strings.Replace(strconv.Itoa(version), "release-", "", 1)
num, err := strconv.Atoi(cleaned)
if err != nil {
fmt.Println("Error parsing number:", err)
}
pkg.UpdateServerStats(int64(num))
server.BroadcastToRoom("/", "update", "updateLogs", msg) server.BroadcastToRoom("/", "update", "updateLogs", msg)
default: default:
msg := fmt.Sprintf("Error: too many zip files in root: %v\n", zips) msg := fmt.Sprintf("Error: too many zip files in root: %v\n", zips)
@@ -194,6 +206,7 @@ func Unzip(srcZip, destDir string) error {
if err != nil { if err != nil {
return err return err
} }
} }
return nil return nil

View File

@@ -1,5 +1,4 @@
import { Server, Settings, User, type LucideIcon } from "lucide-react"; import { Server, Settings, User, type LucideIcon } from "lucide-react";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import { userAccess, type UserRoles } from "../../lib/authClient"; import { userAccess, type UserRoles } from "../../lib/authClient";
import { import {
SidebarGroup, SidebarGroup,
@@ -66,10 +65,6 @@ export default function Admin() {
</> </>
</SidebarMenuItem> </SidebarMenuItem>
))} ))}
{userAccess(null, ["systemAdmin"]) && (
<TanStackRouterDevtools position="bottom-right" />
)}
</SidebarMenu> </SidebarMenu>
</SidebarGroupContent> </SidebarGroupContent>
</SidebarGroup> </SidebarGroup>

View File

@@ -8,15 +8,21 @@
// You should NOT make any changes in this file as it will be overwritten. // You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { createFileRoute } from '@tanstack/react-router'
import { Route as rootRouteImport } from './routes/__root' import { Route as rootRouteImport } from './routes/__root'
import { Route as AdminLayoutRouteRouteImport } from './routes/_adminLayout/route' import { Route as AdminLayoutRouteRouteImport } from './routes/_adminLayout/route'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
import { Route as authLoginRouteImport } from './routes/(auth)/login' import { Route as authLoginRouteImport } from './routes/(auth)/login'
import { Route as AdminLayoutAdminUsersRouteImport } from './routes/_adminLayout/admin/users'
import { Route as AdminLayoutAdminSettingsRouteImport } from './routes/_adminLayout/admin/settings' import { Route as AdminLayoutAdminSettingsRouteImport } from './routes/_adminLayout/admin/settings'
import { Route as AdminLayoutAdminServersRouteImport } from './routes/_adminLayout/admin/servers' import { Route as AdminLayoutAdminServersRouteImport } from './routes/_adminLayout/admin/servers'
import { Route as authUserSignupRouteImport } from './routes/(auth)/user/signup' import { Route as authUserSignupRouteImport } from './routes/(auth)/user/signup'
import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user/resetpassword' import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user/resetpassword'
import { Route as AdminLayoutAdminUsersRouteRouteImport } from './routes/_adminLayout/admin/_users/route'
import { Route as AdminLayoutAdminUsersUsersRouteImport } from './routes/_adminLayout/admin/_users/users'
import { Route as AdminLayoutAdminUsersProdUsersRouteImport } from './routes/_adminLayout/admin/_users/prodUsers'
const AdminLayoutAdminRouteImport = createFileRoute('/_adminLayout/admin')()
const AdminLayoutRouteRoute = AdminLayoutRouteRouteImport.update({ const AdminLayoutRouteRoute = AdminLayoutRouteRouteImport.update({
id: '/_adminLayout', id: '/_adminLayout',
@@ -27,26 +33,26 @@ const IndexRoute = IndexRouteImport.update({
path: '/', path: '/',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const AdminLayoutAdminRoute = AdminLayoutAdminRouteImport.update({
id: '/admin',
path: '/admin',
getParentRoute: () => AdminLayoutRouteRoute,
} as any)
const authLoginRoute = authLoginRouteImport.update({ const authLoginRoute = authLoginRouteImport.update({
id: '/(auth)/login', id: '/(auth)/login',
path: '/login', path: '/login',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const AdminLayoutAdminUsersRoute = AdminLayoutAdminUsersRouteImport.update({
id: '/admin/users',
path: '/admin/users',
getParentRoute: () => AdminLayoutRouteRoute,
} as any)
const AdminLayoutAdminSettingsRoute = const AdminLayoutAdminSettingsRoute =
AdminLayoutAdminSettingsRouteImport.update({ AdminLayoutAdminSettingsRouteImport.update({
id: '/admin/settings', id: '/settings',
path: '/admin/settings', path: '/settings',
getParentRoute: () => AdminLayoutRouteRoute, getParentRoute: () => AdminLayoutAdminRoute,
} as any) } as any)
const AdminLayoutAdminServersRoute = AdminLayoutAdminServersRouteImport.update({ const AdminLayoutAdminServersRoute = AdminLayoutAdminServersRouteImport.update({
id: '/admin/servers', id: '/servers',
path: '/admin/servers', path: '/servers',
getParentRoute: () => AdminLayoutRouteRoute, getParentRoute: () => AdminLayoutAdminRoute,
} as any) } as any)
const authUserSignupRoute = authUserSignupRouteImport.update({ const authUserSignupRoute = authUserSignupRouteImport.update({
id: '/(auth)/user/signup', id: '/(auth)/user/signup',
@@ -58,65 +64,96 @@ const authUserResetpasswordRoute = authUserResetpasswordRouteImport.update({
path: '/user/resetpassword', path: '/user/resetpassword',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const AdminLayoutAdminUsersRouteRoute =
AdminLayoutAdminUsersRouteRouteImport.update({
id: '/_users',
getParentRoute: () => AdminLayoutAdminRoute,
} as any)
const AdminLayoutAdminUsersUsersRoute =
AdminLayoutAdminUsersUsersRouteImport.update({
id: '/users',
path: '/users',
getParentRoute: () => AdminLayoutAdminUsersRouteRoute,
} as any)
const AdminLayoutAdminUsersProdUsersRoute =
AdminLayoutAdminUsersProdUsersRouteImport.update({
id: '/prodUsers',
path: '/prodUsers',
getParentRoute: () => AdminLayoutAdminUsersRouteRoute,
} as any)
export interface FileRoutesByFullPath { export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
'/login': typeof authLoginRoute '/login': typeof authLoginRoute
'/admin': typeof AdminLayoutAdminUsersRouteRouteWithChildren
'/user/resetpassword': typeof authUserResetpasswordRoute '/user/resetpassword': typeof authUserResetpasswordRoute
'/user/signup': typeof authUserSignupRoute '/user/signup': typeof authUserSignupRoute
'/admin/servers': typeof AdminLayoutAdminServersRoute '/admin/servers': typeof AdminLayoutAdminServersRoute
'/admin/settings': typeof AdminLayoutAdminSettingsRoute '/admin/settings': typeof AdminLayoutAdminSettingsRoute
'/admin/users': typeof AdminLayoutAdminUsersRoute '/admin/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute
'/admin/users': typeof AdminLayoutAdminUsersUsersRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
'/login': typeof authLoginRoute '/login': typeof authLoginRoute
'/admin': typeof AdminLayoutAdminUsersRouteRouteWithChildren
'/user/resetpassword': typeof authUserResetpasswordRoute '/user/resetpassword': typeof authUserResetpasswordRoute
'/user/signup': typeof authUserSignupRoute '/user/signup': typeof authUserSignupRoute
'/admin/servers': typeof AdminLayoutAdminServersRoute '/admin/servers': typeof AdminLayoutAdminServersRoute
'/admin/settings': typeof AdminLayoutAdminSettingsRoute '/admin/settings': typeof AdminLayoutAdminSettingsRoute
'/admin/users': typeof AdminLayoutAdminUsersRoute '/admin/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute
'/admin/users': typeof AdminLayoutAdminUsersUsersRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
__root__: typeof rootRouteImport __root__: typeof rootRouteImport
'/': typeof IndexRoute '/': typeof IndexRoute
'/_adminLayout': typeof AdminLayoutRouteRouteWithChildren '/_adminLayout': typeof AdminLayoutRouteRouteWithChildren
'/(auth)/login': typeof authLoginRoute '/(auth)/login': typeof authLoginRoute
'/_adminLayout/admin': typeof AdminLayoutAdminRouteWithChildren
'/_adminLayout/admin/_users': typeof AdminLayoutAdminUsersRouteRouteWithChildren
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute '/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
'/(auth)/user/signup': typeof authUserSignupRoute '/(auth)/user/signup': typeof authUserSignupRoute
'/_adminLayout/admin/servers': typeof AdminLayoutAdminServersRoute '/_adminLayout/admin/servers': typeof AdminLayoutAdminServersRoute
'/_adminLayout/admin/settings': typeof AdminLayoutAdminSettingsRoute '/_adminLayout/admin/settings': typeof AdminLayoutAdminSettingsRoute
'/_adminLayout/admin/users': typeof AdminLayoutAdminUsersRoute '/_adminLayout/admin/_users/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute
'/_adminLayout/admin/_users/users': typeof AdminLayoutAdminUsersUsersRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: fullPaths:
| '/' | '/'
| '/login' | '/login'
| '/admin'
| '/user/resetpassword' | '/user/resetpassword'
| '/user/signup' | '/user/signup'
| '/admin/servers' | '/admin/servers'
| '/admin/settings' | '/admin/settings'
| '/admin/prodUsers'
| '/admin/users' | '/admin/users'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: to:
| '/' | '/'
| '/login' | '/login'
| '/admin'
| '/user/resetpassword' | '/user/resetpassword'
| '/user/signup' | '/user/signup'
| '/admin/servers' | '/admin/servers'
| '/admin/settings' | '/admin/settings'
| '/admin/prodUsers'
| '/admin/users' | '/admin/users'
id: id:
| '__root__' | '__root__'
| '/' | '/'
| '/_adminLayout' | '/_adminLayout'
| '/(auth)/login' | '/(auth)/login'
| '/_adminLayout/admin'
| '/_adminLayout/admin/_users'
| '/(auth)/user/resetpassword' | '/(auth)/user/resetpassword'
| '/(auth)/user/signup' | '/(auth)/user/signup'
| '/_adminLayout/admin/servers' | '/_adminLayout/admin/servers'
| '/_adminLayout/admin/settings' | '/_adminLayout/admin/settings'
| '/_adminLayout/admin/users' | '/_adminLayout/admin/_users/prodUsers'
| '/_adminLayout/admin/_users/users'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
@@ -143,6 +180,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexRouteImport preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/_adminLayout/admin': {
id: '/_adminLayout/admin'
path: '/admin'
fullPath: '/admin'
preLoaderRoute: typeof AdminLayoutAdminRouteImport
parentRoute: typeof AdminLayoutRouteRoute
}
'/(auth)/login': { '/(auth)/login': {
id: '/(auth)/login' id: '/(auth)/login'
path: '/login' path: '/login'
@@ -150,26 +194,19 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof authLoginRouteImport preLoaderRoute: typeof authLoginRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/_adminLayout/admin/users': {
id: '/_adminLayout/admin/users'
path: '/admin/users'
fullPath: '/admin/users'
preLoaderRoute: typeof AdminLayoutAdminUsersRouteImport
parentRoute: typeof AdminLayoutRouteRoute
}
'/_adminLayout/admin/settings': { '/_adminLayout/admin/settings': {
id: '/_adminLayout/admin/settings' id: '/_adminLayout/admin/settings'
path: '/admin/settings' path: '/settings'
fullPath: '/admin/settings' fullPath: '/admin/settings'
preLoaderRoute: typeof AdminLayoutAdminSettingsRouteImport preLoaderRoute: typeof AdminLayoutAdminSettingsRouteImport
parentRoute: typeof AdminLayoutRouteRoute parentRoute: typeof AdminLayoutAdminRoute
} }
'/_adminLayout/admin/servers': { '/_adminLayout/admin/servers': {
id: '/_adminLayout/admin/servers' id: '/_adminLayout/admin/servers'
path: '/admin/servers' path: '/servers'
fullPath: '/admin/servers' fullPath: '/admin/servers'
preLoaderRoute: typeof AdminLayoutAdminServersRouteImport preLoaderRoute: typeof AdminLayoutAdminServersRouteImport
parentRoute: typeof AdminLayoutRouteRoute parentRoute: typeof AdminLayoutAdminRoute
} }
'/(auth)/user/signup': { '/(auth)/user/signup': {
id: '/(auth)/user/signup' id: '/(auth)/user/signup'
@@ -185,19 +222,67 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof authUserResetpasswordRouteImport preLoaderRoute: typeof authUserResetpasswordRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/_adminLayout/admin/_users': {
id: '/_adminLayout/admin/_users'
path: '/admin'
fullPath: '/admin'
preLoaderRoute: typeof AdminLayoutAdminUsersRouteRouteImport
parentRoute: typeof AdminLayoutAdminRoute
}
'/_adminLayout/admin/_users/users': {
id: '/_adminLayout/admin/_users/users'
path: '/users'
fullPath: '/admin/users'
preLoaderRoute: typeof AdminLayoutAdminUsersUsersRouteImport
parentRoute: typeof AdminLayoutAdminUsersRouteRoute
}
'/_adminLayout/admin/_users/prodUsers': {
id: '/_adminLayout/admin/_users/prodUsers'
path: '/prodUsers'
fullPath: '/admin/prodUsers'
preLoaderRoute: typeof AdminLayoutAdminUsersProdUsersRouteImport
parentRoute: typeof AdminLayoutAdminUsersRouteRoute
}
} }
} }
interface AdminLayoutRouteRouteChildren { interface AdminLayoutAdminUsersRouteRouteChildren {
AdminLayoutAdminUsersProdUsersRoute: typeof AdminLayoutAdminUsersProdUsersRoute
AdminLayoutAdminUsersUsersRoute: typeof AdminLayoutAdminUsersUsersRoute
}
const AdminLayoutAdminUsersRouteRouteChildren: AdminLayoutAdminUsersRouteRouteChildren =
{
AdminLayoutAdminUsersProdUsersRoute: AdminLayoutAdminUsersProdUsersRoute,
AdminLayoutAdminUsersUsersRoute: AdminLayoutAdminUsersUsersRoute,
}
const AdminLayoutAdminUsersRouteRouteWithChildren =
AdminLayoutAdminUsersRouteRoute._addFileChildren(
AdminLayoutAdminUsersRouteRouteChildren,
)
interface AdminLayoutAdminRouteChildren {
AdminLayoutAdminUsersRouteRoute: typeof AdminLayoutAdminUsersRouteRouteWithChildren
AdminLayoutAdminServersRoute: typeof AdminLayoutAdminServersRoute AdminLayoutAdminServersRoute: typeof AdminLayoutAdminServersRoute
AdminLayoutAdminSettingsRoute: typeof AdminLayoutAdminSettingsRoute AdminLayoutAdminSettingsRoute: typeof AdminLayoutAdminSettingsRoute
AdminLayoutAdminUsersRoute: typeof AdminLayoutAdminUsersRoute }
const AdminLayoutAdminRouteChildren: AdminLayoutAdminRouteChildren = {
AdminLayoutAdminUsersRouteRoute: AdminLayoutAdminUsersRouteRouteWithChildren,
AdminLayoutAdminServersRoute: AdminLayoutAdminServersRoute,
AdminLayoutAdminSettingsRoute: AdminLayoutAdminSettingsRoute,
}
const AdminLayoutAdminRouteWithChildren =
AdminLayoutAdminRoute._addFileChildren(AdminLayoutAdminRouteChildren)
interface AdminLayoutRouteRouteChildren {
AdminLayoutAdminRoute: typeof AdminLayoutAdminRouteWithChildren
} }
const AdminLayoutRouteRouteChildren: AdminLayoutRouteRouteChildren = { const AdminLayoutRouteRouteChildren: AdminLayoutRouteRouteChildren = {
AdminLayoutAdminServersRoute: AdminLayoutAdminServersRoute, AdminLayoutAdminRoute: AdminLayoutAdminRouteWithChildren,
AdminLayoutAdminSettingsRoute: AdminLayoutAdminSettingsRoute,
AdminLayoutAdminUsersRoute: AdminLayoutAdminUsersRoute,
} }
const AdminLayoutRouteRouteWithChildren = const AdminLayoutRouteRouteWithChildren =

View File

@@ -8,6 +8,8 @@ import Nav from "../components/navBar/Nav";
import { ThemeProvider } from "../lib/providers/theme-provider"; import { ThemeProvider } from "../lib/providers/theme-provider";
import { SidebarProvider } from "../components/ui/sidebar"; import { SidebarProvider } from "../components/ui/sidebar";
import SideBarNav from "../components/navBar/SideBarNav"; import SideBarNav from "../components/navBar/SideBarNav";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import { userAccess } from "../lib/authClient";
interface RootRouteContext { interface RootRouteContext {
queryClient: QueryClient; queryClient: QueryClient;
@@ -34,6 +36,9 @@ const RootLayout = () => {
</SidebarProvider> </SidebarProvider>
</div> </div>
<Toaster expand richColors closeButton /> <Toaster expand richColors closeButton />
{userAccess(null, ["systemAdmin"]) && (
<TanStackRouterDevtools position="bottom-right" />
)}
</div> </div>
</ThemeProvider> </ThemeProvider>
</SessionGuard> </SessionGuard>

View File

@@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/_adminLayout/admin/_users/prodUsers')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/_adminLayout/admin/_users/prodUsers"!</div>
}

View File

@@ -0,0 +1,30 @@
import { createFileRoute, Link, Outlet } from "@tanstack/react-router";
export const Route = createFileRoute("/_adminLayout/admin/_users")({
component: RouteComponent,
});
function RouteComponent() {
return (
<div>
<nav className="flex justify-center gap-3">
<Link
to="/admin/users"
className="[&.active]:font-bold [&.active]:underline"
activeOptions={{
exact: true,
}}
>
Users
</Link>
<Link
to="/admin/prodUsers"
className="[&.active]:font-bold [&.active]:underline"
>
Prod Users
</Link>
</nav>
<Outlet />
</div>
);
}

View File

@@ -0,0 +1,9 @@
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/_adminLayout/admin/_users/users")({
component: RouteComponent,
});
function RouteComponent() {
return <div className="">Hello "/_admin/admin/users "!</div>;
}

View File

@@ -1,9 +0,0 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/_adminLayout/admin/users')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/_admin/admin/users"!</div>
}

View File

@@ -0,0 +1,5 @@
CREATE TABLE "serverStats" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"build" integer DEFAULT 1 NOT NULL,
"lastUpdate" timestamp DEFAULT now()
);

View File

@@ -0,0 +1,2 @@
ALTER TABLE "serverStats" ALTER COLUMN "id" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "serverStats" ALTER COLUMN "id" SET DEFAULT 'serverStats';

View File

@@ -0,0 +1,921 @@
{
"id": "164ae2f1-91c6-4c31-87eb-2f9c5a1fcf86",
"prevId": "33b56ace-aa18-498f-922f-513e13ccc6ef",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.apiHits": {
"name": "apiHits",
"schema": "",
"columns": {
"apiHit_id": {
"name": "apiHit_id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"method": {
"name": "method",
"type": "text",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"body": {
"name": "body",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"ip": {
"name": "ip",
"type": "text",
"primaryKey": false,
"notNull": false
},
"duration": {
"name": "duration",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"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": {},
"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": {},
"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
}
},
"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": {},
"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
},
"last_login": {
"name": "last_login",
"type": "timestamp",
"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": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.logs": {
"name": "logs",
"schema": "",
"columns": {
"log_id": {
"name": "log_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
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.serverStats": {
"name": "serverStats",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"build": {
"name": "build",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"lastUpdate": {
"name": "lastUpdate",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"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"
},
"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
},
"public.user_roles": {
"name": "user_roles",
"schema": "",
"columns": {
"user_role_id": {
"name": "user_role_id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"module": {
"name": "module",
"type": "text",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"unique_user_module": {
"name": "unique_user_module",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "module",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"user_roles_user_id_user_id_fk": {
"name": "user_roles_user_id_user_id_fk",
"tableFrom": "user_roles",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,921 @@
{
"id": "7f5da907-4bed-4584-b32b-1f7f2ce17455",
"prevId": "164ae2f1-91c6-4c31-87eb-2f9c5a1fcf86",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.apiHits": {
"name": "apiHits",
"schema": "",
"columns": {
"apiHit_id": {
"name": "apiHit_id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"method": {
"name": "method",
"type": "text",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"body": {
"name": "body",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"ip": {
"name": "ip",
"type": "text",
"primaryKey": false,
"notNull": false
},
"duration": {
"name": "duration",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"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": {},
"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": {},
"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
}
},
"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": {},
"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
},
"last_login": {
"name": "last_login",
"type": "timestamp",
"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": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.logs": {
"name": "logs",
"schema": "",
"columns": {
"log_id": {
"name": "log_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
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.serverStats": {
"name": "serverStats",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "'serverStats'"
},
"build": {
"name": "build",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"lastUpdate": {
"name": "lastUpdate",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"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"
},
"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
},
"public.user_roles": {
"name": "user_roles",
"schema": "",
"columns": {
"user_role_id": {
"name": "user_role_id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"module": {
"name": "module",
"type": "text",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"unique_user_module": {
"name": "unique_user_module",
"columns": [
{
"expression": "user_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "module",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"user_roles_user_id_user_id_fk": {
"name": "user_roles_user_id_user_id_fk",
"tableFrom": "user_roles",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -57,6 +57,20 @@
"when": 1758755206107, "when": 1758755206107,
"tag": "0007_common_kronos", "tag": "0007_common_kronos",
"breakpoints": true "breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1758890062084,
"tag": "0008_exotic_scrambler",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1758891252758,
"tag": "0009_cultured_slayback",
"breakpoints": true
} }
] ]
} }

21
package-lock.json generated
View File

@@ -14,6 +14,8 @@
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"better-auth": "^1.3.9", "better-auth": "^1.3.9",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.31.4", "drizzle-kit": "^0.31.4",
"drizzle-orm": "^0.44.5", "drizzle-orm": "^0.44.5",
"drizzle-zod": "^0.8.3", "drizzle-zod": "^0.8.3",
@@ -4611,6 +4613,25 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"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/dateformat": { "node_modules/dateformat": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",

View File

@@ -46,6 +46,8 @@
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"better-auth": "^1.3.9", "better-auth": "^1.3.9",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.31.4", "drizzle-kit": "^0.31.4",
"drizzle-orm": "^0.44.5", "drizzle-orm": "^0.44.5",
"drizzle-zod": "^0.8.3", "drizzle-zod": "^0.8.3",

View File

@@ -186,6 +186,43 @@ function Update-Server {
Write-Output "[$key] already exists -> skipping" Write-Output "[$key] already exists -> skipping"
} }
} }
# update the controller .env as well to make sure we have anything enw in here.
$requiredController = @(
@{ Key = "DATABASE_HOST"; Value = "localhost"; Comment = "used for better auth secrets" },
@{ Key = "DATABASE_PORT"; Value = 5432; Comment = "The better auth url" }
@{ Key = "DATABASE_USER"; Value = "postgres"; Comment = "" }
@{ Key = "DATABASE_PASSWORD"; Value = "obelix"; Comment = "" }
@{ Key = "DATABASE_DB"; Value = "lst$(if ($token -eq "usiow2") { "_2" })"; Comment = "" }
)
$envFileController = "$LocalPath\controller\.env"
Write-Host $envFileController
if (-not (Test-Path $envFileController)) {
New-Item -ItemType File -Path $envFileController -Force | Out-Null
}
$lines = Get-Content $envFileController
foreach ($item in $requiredController) {
$key = $item.Key
$value = $item.Value
$comment = "# $($item.Comment)"
$exists = $lines | Where-Object { $_ -match "^\s*$key\s*=" }
if (-not $exists) {
Write-Output "[$key] missing -> adding to .env"
Add-Content -Path $envFileController -Value "`n$comment"
Add-Content -Path $envFileController -Value "$key=$value"
}
else {
Write-Output "[$key] already exists -> skipping"
}
}
} }

View File

@@ -14,7 +14,7 @@ param (
# example string to pass over, you must be in the script dir when you run this script. or it will fail to find the linked scripts # example string to pass over, you must be in the script dir when you run this script. or it will fail to find the linked scripts
# If we do not pass plant to update over it will auto do all plants if we want a specific plant we need to do like below # If we do not pass plant to update over it will auto do all plants if we want a specific plant we need to do like below
# .\update-controllers.ps1 -App_Path "C:\Users\matthes01\Documents\lst" -Token "test3" -BuildController yes -PlantToUpdate "usmcd1vms036" -Remote_Path "E$\LST" # .\update-controllers.ps1 -App_Path "C:\Users\matthes01\Documents\lst" -Token "usiow2" -BuildController no -PlantToUpdate "usiow1vms006" -Remote_Path "D$\LST\lst_2"
# .\update-controllers.ps1 -App_Path "C:\Users\matthes01\Documents\lst" -Token "test3" -BuildController yes # .\update-controllers.ps1 -App_Path "C:\Users\matthes01\Documents\lst" -Token "test3" -BuildController yes
$Plants = @( $Plants = @(