dev env setup

This commit is contained in:
tw-blue
2025-12-06 21:27:29 +01:00
parent 987a380758
commit bc9f0f9f3b
38 changed files with 5953 additions and 733 deletions
+17 -9
View File
@@ -1,7 +1,13 @@
import { PrismaPg } from "@prisma/adapter-pg";
import { type Request } from "express";
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"
>;
export type SafeClient = Omit<
ExtendedClient,
@@ -33,9 +39,9 @@ function createExtendedClient(client: PrismaClient) {
// });
}
@Injectable()
export class DatabaseService {
private readonly prismaClient: ExtendedClient;
private readonly safeClient: SafeClient;
public constructor() {
const dbUser = process.env["TKD_DB_USER"];
@@ -46,17 +52,19 @@ export class DatabaseService {
const adapter = new PrismaPg({ connectionString });
this.prismaClient = createExtendedClient(new PrismaClient({ adapter }));
this.safeClient = this.prismaClient as SafeClient;
// this.prismaClient.$connect();
// this.prismaClient.$disconnect();
// this.prismaClient.$on();
// this.prismaClient.$transaction();
}
public async doRequest<T>(
request: (prisma: SafeClient) => Promise<T>,
command: (prisma: SafeClient) => Promise<T>,
request: Request,
): Promise<T> {
return await request(this.safeClient);
const transaction = (request as any).transaction as SafeClient;
return await command(transaction);
}
public async createTransaction(
action: (prisma: TransactionClient) => Promise<void>,
) {
await this.prismaClient.$transaction(action);
}
}
@@ -0,0 +1,8 @@
import { Injectable } from "../infrastructure/di/index.js";
@Injectable()
export class EnvironmentService {
public isDev(): boolean {
return process.env["NODE_ENV"] !== "production";
}
}
@@ -1,10 +1,10 @@
import RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import { Injectable } from "../../../infrastructure/di/injectable-decorator";
import { Injectable } from "../../../infrastructure/di/injectable-decorator.js";
import kcClientConfig from "./nodejs-api.json" with { type: "json" };
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
import { Claim } from "../../../models/claim";
import { User } from "../../../models/user";
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";
@Injectable()
export class KeycloakAdmin {
@@ -54,7 +54,7 @@ export class KeycloakAdmin {
const client = await this.kcAdminClient;
const kcUsers = await client.users.find();
return kcUsers.map(kcUser => ({
id: kcUser.id,
id: kcUser.id ?? "", //TODO handle undefined id
username: kcUser.username || "",
roles: (kcUser.realmRoles || []).map(role => role as Claim),
}));
@@ -2,16 +2,16 @@
"clientId": "nodejs-api",
"name": "NodejsApi",
"description": "",
"rootUrl": "https://tkd-api.toni714.de",
"adminUrl": "https://tkd-api.toni714.de",
"baseUrl": "https://tkd-api.toni714.de",
"rootUrl": "http://localhost:3000",
"adminUrl": "http://localhost:3000",
"baseUrl": "http://localhost:3000",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"secret": "btdeoaq2mgtoa7SpCEL1phLYcw2gGhGp",
"redirectUris": ["https://tkd-api.toni714.de/*"],
"webOrigins": ["https://tkd-api.toni714.de"],
"secret": "devsecret",
"redirectUris": ["http://localhost:3000/*"],
"webOrigins": ["http://localhost:3000"],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
@@ -1,10 +1,10 @@
{
"realm": "taekwondo",
"auth-server-url": "https://keycloak.toni714.de:8443",
"auth-server-url": "https://localhost:8080",
"ssl-required": "external",
"resource": "nodejs-api",
"credentials": {
"secret": "btdeoaq2mgtoa7SpCEL1phLYcw2gGhGp"
"secret": "devsecret"
},
"confidential-port": 0
}
+43 -21
View File
@@ -1,3 +1,4 @@
import express from "express";
import { inject, Injectable } from "../infrastructure/di/index.js";
import { ErrorStates } from "../infrastructure/errorStates.js";
import {
@@ -11,16 +12,22 @@ import { DatabaseService } from "./db/prisma.js";
export class MembersService {
private readonly database = inject(DatabaseService);
public async getMembers(): Promise<Member[]> {
const dbMembers = await this.database.doRequest(prisma =>
prisma.member.findMany(),
public async getMembers(request: express.Request): Promise<Member[]> {
const dbMembers = await this.database.doRequest(
async prisma => await prisma.member.findMany(),
request,
);
return dbMembers.map(mapDbMemberToMember);
}
public async getMemberById(memberId: string): Promise<Member> {
const member = await this.database.doRequest(prisma =>
prisma.member.findFirst({ where: { id: memberId } }),
public async getMemberById(
memberId: string,
request: express.Request,
): Promise<Member> {
const member = await this.database.doRequest(
async prisma =>
await prisma.member.findFirst({ where: { id: memberId } }),
request,
);
if (!member) {
@@ -32,36 +39,51 @@ export class MembersService {
return mapDbMemberToMember(member);
}
public async createMember(createArgs: MemberCreateArgs): Promise<Member> {
const newMember = await this.database.doRequest(prisma =>
prisma.member.create({ data: createArgs }),
public async createMember(
createArgs: MemberCreateArgs,
request: express.Request,
): Promise<Member> {
const newMember = await this.database.doRequest(
async prisma => await prisma.member.create({ data: createArgs }),
request,
);
return mapDbMemberToMember(newMember);
}
public async updateMember(member: Member): Promise<Member> {
public async updateMember(
member: Member,
request: express.Request,
): Promise<Member> {
const id = member.id;
if (!id) {
throw new Error("Member id is required for update", {
cause: ErrorStates.BAD_REQUEST,
});
}
const modifiedMember = await this.database.doRequest(prisma =>
prisma.member.update({
data: { ...member, id: id },
where: { id: id },
}),
const modifiedMember = await this.database.doRequest(
async prisma =>
await prisma.member.update({
data: { ...member, id: id },
where: { id: id },
}),
request,
);
return mapDbMemberToMember(modifiedMember);
}
public async scheduleDeletion(memberId: string, cancelDate: Date) {
await this.database.doRequest(prisma =>
prisma.member.update({
where: { id: memberId },
data: { kuendigungzum: cancelDate },
}),
public async scheduleDeletion(
memberId: string,
cancelDate: Date,
request: express.Request,
) {
await this.database.doRequest(
prisma =>
prisma.member.update({
where: { id: memberId },
data: { kuendigungzum: cancelDate },
}),
request,
);
}
}
+5 -6
View File
@@ -1,7 +1,6 @@
import { inject } from "../infrastructure/di/index.js";
import { Claim } from "../models/claim";
import { Topic } from "../models/topic.js";
import { User } from "../models/user.js";
import { Claim } from "../models/claim.js";
import { type User } from "../models/user.js";
import { KeycloakAdmin } from "./keycloak/admin/index.js";
export class UserService {
@@ -22,7 +21,7 @@ export class UserService {
return await this.keycloakAdmin.getUsers();
}
public async setSubscriptions(token: string, topics: Topic[]) {
throw new Error("Method not implemented.");
}
// public async setSubscriptions(token: string, topics: Topic[]) {
// throw new Error("Method not implemented.");
// }
}