import legacy frontend & fix dependency issues

This commit is contained in:
tw-blue
2025-12-07 12:51:57 +01:00
parent 91ac875a32
commit cd6cfec7f3
52 changed files with 3963 additions and 267 deletions
+27
View File
@@ -0,0 +1,27 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\dist\\index.js",
"outFiles": [
"${workspaceFolder}/**/*.js"
],
"env": {
"TKD_DB_USER": "webapi",
"TKD_DB_PASSWORD": "devpassword",
"TKD_DB_HOST": "localhost",
"TKD_COOKIE_SECRET": "devsecret"
},
"runtimeExecutable": "C:\\Users\\Toni\\AppData\\Roaming\\fnm\\aliases\\default\\node"
}
]
}
File diff suppressed because it is too large Load Diff
@@ -21,3 +21,5 @@ CREATE DATABASE keycloak
-- replace Frontend redirect URLS in realm-export.json
-- SET NODE_ENV=production when running on server
-- SET DEFAULT_PERSISSIONS for webapi user
-- add backend to allowed redirect urls in forntenc kc-client
-- fix web origins for kc-clients
+14 -18
View File
@@ -3,38 +3,34 @@
"version": "1.0.0",
"scripts": {
"start": "node dist/index.js",
"build": "tsc -p .",
"dev": "run-script-os",
"dev:win32": "wsl -- bash -ic 'pnpm run dev:linux'",
"dev:linux": "./scripts/dev.sh"
"build": "tsc -p ."
},
"type": "module",
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a",
"private": true,
"devDependencies": {
"@types/connect-pg-simple": "^7.0.3",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/connect-pg-simple": "^7.0.3",
"@types/express": "^5.0.5",
"@types/express-session": "^1.18.2",
"@types/node": "^24.10.1",
"@types/node": "^24.9.2",
"@types/pg": "^8.15.6",
"dotenv": "^17.2.3",
"prisma": "^7.1.0",
"run-script-os": "^1.1.6",
"tsx": "^4.21.0",
"prisma": "^7.0.1",
"tsx": "^4.20.6",
"typescript": "~5.9.3"
},
"dependencies": {
"@keycloak/keycloak-admin-client": "^26.4.7",
"@prisma/adapter-pg": "^7.1.0",
"@prisma/client": "^7.1.0",
"cors": "^2.8.5",
"rxjs": "~7.8.2",
"@keycloak/keycloak-admin-client": "^26.4.4",
"@prisma/adapter-pg": "^7.0.1",
"@prisma/client": "^7.0.1",
"@tsoa/runtime": "^6.6.0",
"connect-pg-simple": "^10.0.0",
"cors": "^2.8.5",
"express": "^5.2.1",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"express-session": "^1.18.2",
"keycloak-connect": "^26.1.1",
"pg": "^8.16.3",
"rxjs": "~7.8.2"
"pg": "^8.16.3"
}
}
@@ -13,10 +13,10 @@ import {
SuccessResponse,
} from "@tsoa/runtime";
import express from "express";
import { Claim } from "../dtos/claim.js";
import type { Member, MemberCreateArgs } from "../dtos/member.js";
import { inject } from "../infrastructure/di/index.js";
import { ErrorStates } from "../infrastructure/errorStates.js";
import { Claim } from "../models/claim.js";
import type { Member, MemberCreateArgs } from "../models/member.js";
import { KC_SECURITY_NAME } from "../services/keycloak/user/index.js";
import { MembersService } from "../services/membersService.js";
@@ -9,9 +9,9 @@ import {
Security,
SuccessResponse,
} from "@tsoa/runtime";
import { Claim } from "../dtos/claim.js";
import { type User } from "../dtos/user.js";
import { inject } from "../infrastructure/di/index.js";
import { Claim } from "../models/claim.js";
import { type User } from "../models/user.js";
import { KC_SECURITY_NAME } from "../services/keycloak/user/index.js";
import { UserService } from "../services/userService.js";
@@ -1,20 +1,20 @@
import { type MemberModel as DbMember } from "../generated/prisma/models.js";
export interface Member {
id?: string | null;
vorname?: string | null;
nachname?: string | null;
geburtsdatum?: Date | null;
geburtsort?: string | null;
geschlecht?: string | null;
passnummer?: string | null;
uvertrag?: boolean | null;
verein?: boolean | null;
graduierung?: string | null;
letztePruefung?: Date | null;
kontakt?: string | null;
kuendigungzum?: Date | null;
loeschenam?: string | null;
id: string | null;
vorname: string | null;
nachname: string | null;
geburtsdatum: Date | null;
geburtsort: string | null;
geschlecht: string | null;
passnummer: string | null;
uvertrag: boolean | null;
verein: boolean | null;
graduierung: string | null;
letztePruefung: Date | null;
kontakt: string | null;
kuendigungzum: Date | null;
loeschenam: Date | null;
}
export type MemberCreateArgs = Omit<Member, "id" | "loeschenam">;
@@ -34,5 +34,6 @@ export function mapDbMemberToMember(dbMember: DbMember): Member {
passnummer: dbMember.passnummer,
uvertrag: dbMember.uvertrag,
verein: dbMember.verein,
loeschenam: new Date(), //TODO
};
}
+2 -1
View File
@@ -14,7 +14,6 @@ const app = express();
app.use(sessionHandler);
app.use(keycloak.middleware());
// console.log("not using", keycloak.middleware);
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
@@ -25,6 +24,8 @@ app.use(
"https://tcc-1-ev-intern.web.app",
"http://localhost:4200",
"https://localhost:4200",
"http://localhost:3000",
"http://localhost:8080",
],
//TODO reevaluate
}),
+24 -7
View File
@@ -8,8 +8,11 @@ function promisifyMiddleware(
response?: Response,
): Promise<any> {
return new Promise((resolve, reject) => {
middleware(request, response || ({} as any), (result: any) => {
result instanceof Error ? reject(result) : resolve(result);
middleware(request, response || ({} as any), (next_result: any) => {
console.dir(next_result);
next_result instanceof Error
? reject(next_result)
: resolve(next_result);
});
});
}
@@ -20,10 +23,15 @@ async function doKeycloakAuth(
response?: Response,
): Promise<any> {
if (roles && roles.length > 0) {
return await promisifyMiddleware(
request,
keycloak.enforcer(roles?.map(role => `realm:${role}`)),
const grant = await keycloak.getGrant(request, response ?? ({} as any));
const allowed = roles.every(role =>
grant.access_token?.hasRealmRole(role),
);
if (allowed) {
return Promise.resolve();
} else {
return Promise.reject(httpError(403, "Forbidden"));
}
} else {
return await promisifyMiddleware(request, keycloak.protect(), response);
}
@@ -35,12 +43,21 @@ export async function expressAuthentication(
roles?: string[],
response?: Response,
): Promise<any> {
if (request.method === "OPTIONS") {
return Promise.resolve();
}
switch (securityName) {
case KC_SECURITY_NAME:
return doKeycloakAuth(request, roles, response);
return await doKeycloakAuth(request, roles, response);
case undefined:
return Promise.resolve();
default:
return Promise.reject("Unknown security name");
return Promise.reject(httpError(400, "Unknown security name"));
}
}
function httpError(status: number, message: string) {
const err: any = new Error(message);
err.status = status;
return err;
}
+6 -11
View File
@@ -4,10 +4,10 @@ import { PrismaClient } from "../../generated/prisma/client.js";
import { Injectable } from "../../infrastructure/di/injectable-decorator.js";
type ExtendedClient = ReturnType<typeof createExtendedClient>;
type TransactionClient = Omit<
ExtendedClient,
"$connect" | "$disconnect" | "$on" | "$transaction" | "$extends"
>;
// type TransactionClient = Omit<
// ExtendedClient,
// "$connect" | "$disconnect" | "$on" | "$transaction" | "$extends"
// >;
export type SafeClient = Omit<
ExtendedClient,
@@ -58,13 +58,8 @@ export class DatabaseService {
command: (prisma: SafeClient) => Promise<T>,
request: Request,
): Promise<T> {
const transaction = (request as any).transaction as SafeClient;
const transaction =
(request as any).transaction ?? (this.prismaClient as SafeClient);
return await command(transaction);
}
public async createTransaction(
action: (prisma: TransactionClient) => Promise<void>,
) {
await this.prismaClient.$transaction(action);
}
}
@@ -3,8 +3,8 @@ import kcClientConfig from "./nodejs-api.json" with { type: "json" };
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation.js";
import { Claim } from "../../../models/claim.js";
import { type User } from "../../../models/user.js";
import { Claim } from "../../../dtos/claim.js";
import { type User } from "../../../dtos/user.js";
@Injectable()
export class KeycloakAdmin {
@@ -1,10 +1,8 @@
{
"realm": "taekwondo",
"auth-server-url": "https://localhost:8080",
"ssl-required": "external",
"resource": "nodejs-api",
"credentials": {
"secret": "devsecret"
},
"confidential-port": 0
"realm": "taekwondo",
"auth-server-url": "http://localhost:8080/",
"ssl-required": "external",
"resource": "angular-frontend",
"public-client": true,
"confidential-port": 0
}
+7 -3
View File
@@ -1,11 +1,11 @@
import express from "express";
import { inject, Injectable } from "../infrastructure/di/index.js";
import { ErrorStates } from "../infrastructure/errorStates.js";
import {
type Member,
type MemberCreateArgs,
mapDbMemberToMember,
} from "../models/member.js";
} from "../dtos/member.js";
import { inject, Injectable } from "../infrastructure/di/index.js";
import { ErrorStates } from "../infrastructure/errorStates.js";
import { DatabaseService } from "./db/prisma.js";
@Injectable()
@@ -43,6 +43,10 @@ export class MembersService {
createArgs: MemberCreateArgs,
request: express.Request,
): Promise<Member> {
const x: MemberCreateArgs = {
...createArgs,
geburtsdatum: createArgs.geburtsdatum ?? null,
};
const newMember = await this.database.doRequest(
async prisma => await prisma.member.create({ data: createArgs }),
request,
+2 -2
View File
@@ -1,6 +1,6 @@
import { Claim } from "../dtos/claim.js";
import { type User } from "../dtos/user.js";
import { inject } from "../infrastructure/di/index.js";
import { Claim } from "../models/claim.js";
import { type User } from "../models/user.js";
import { KeycloakAdmin } from "./keycloak/admin/index.js";
export class UserService {