finalize migration (yay)
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Query,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
} from "@tsoa/runtime";
|
||||
import express from "express";
|
||||
import { Claim } from "../dtos/claim.js";
|
||||
import type { Member, MemberCreateArgs } from "../dtos/member.js";
|
||||
import type { MemberCreateArgs, MemberDto } from "../dtos/member.js";
|
||||
import { inject } from "../infrastructure/di/index.js";
|
||||
import { ErrorStates } from "../infrastructure/errorStates.js";
|
||||
import { KC_SECURITY_NAME } from "../services/keycloak/user/index.js";
|
||||
@@ -28,7 +29,7 @@ export class MembersContoller extends Controller {
|
||||
@Get()
|
||||
public async getMembers(
|
||||
@Request() request: express.Request,
|
||||
): Promise<Member[]> {
|
||||
): Promise<MemberDto[]> {
|
||||
return await this.membersService.getMembers(request);
|
||||
}
|
||||
|
||||
@@ -39,7 +40,7 @@ export class MembersContoller extends Controller {
|
||||
public async getMember(
|
||||
@Path() memberId: string,
|
||||
@Request() request: express.Request,
|
||||
): Promise<Member> {
|
||||
): Promise<MemberDto> {
|
||||
try {
|
||||
const foundMember = await this.membersService.getMemberById(
|
||||
memberId,
|
||||
@@ -64,7 +65,7 @@ export class MembersContoller extends Controller {
|
||||
public async createMember(
|
||||
@Body() createArgs: MemberCreateArgs,
|
||||
@Request() request: express.Request,
|
||||
): Promise<Member> {
|
||||
): Promise<MemberDto> {
|
||||
return await this.membersService.createMember(createArgs, request);
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ export class MembersContoller extends Controller {
|
||||
@Response(404, "Member not found")
|
||||
@Put()
|
||||
public async updateMember(
|
||||
@Body() member: Member,
|
||||
@Body() member: MemberDto,
|
||||
@Request() request: express.Request,
|
||||
): Promise<void> {
|
||||
try {
|
||||
@@ -97,7 +98,7 @@ export class MembersContoller extends Controller {
|
||||
@Delete("{memberId}")
|
||||
public async scheduleDeletion(
|
||||
@Path() memberId: string,
|
||||
@Body() cancelDate: Date,
|
||||
@Query() cancelDate: Date,
|
||||
@Request() request: express.Request,
|
||||
) {
|
||||
await this.membersService.scheduleDeletion(
|
||||
|
||||
@@ -1,27 +1,39 @@
|
||||
import { type MemberModel as DbMember } from "../generated/prisma/models.js";
|
||||
|
||||
export interface Member {
|
||||
export interface MemberDto {
|
||||
id: string | null;
|
||||
vorname: string | null;
|
||||
nachname: string | null;
|
||||
geburtsdatum: Date | null;
|
||||
geburtsdatum: string | null;
|
||||
geburtsort: string | null;
|
||||
geschlecht: string | null;
|
||||
passnummer: string | null;
|
||||
uvertrag: boolean | null;
|
||||
verein: boolean | null;
|
||||
graduierung: string | null;
|
||||
letztePruefung: Date | null;
|
||||
letztePruefung: string | null;
|
||||
kontakt: string | null;
|
||||
kuendigungzum: Date | null;
|
||||
loeschenam: Date | null;
|
||||
kuendigungzum: string | null;
|
||||
marker: boolean | null;
|
||||
}
|
||||
|
||||
export type MemberCreateArgs = Omit<Member, "id" | "loeschenam">;
|
||||
export class MemberCreateArgs implements Omit<MemberDto, "id"> {
|
||||
vorname!: string | null;
|
||||
nachname!: string | null;
|
||||
geburtsdatum!: string | null;
|
||||
geburtsort!: string | null;
|
||||
geschlecht!: string | null;
|
||||
passnummer!: string | null;
|
||||
verein!: boolean | null;
|
||||
graduierung!: string | null;
|
||||
letztePruefung!: string | null;
|
||||
kontakt!: string | null;
|
||||
kuendigungzum!: string | null;
|
||||
marker!: boolean | null;
|
||||
}
|
||||
|
||||
export function mapDbMemberToMember(dbMember: DbMember): Member {
|
||||
export function mapDbMemberToMember(dbMember: DbMember): MemberDto {
|
||||
return {
|
||||
geburtsdatum: dbMember.geburtsdatum,
|
||||
geburtsdatum: dbMember.geburtsdatum?.toDateString() ?? null,
|
||||
id: dbMember.id,
|
||||
nachname: dbMember.nachname,
|
||||
geburtsort: dbMember.geburtsort,
|
||||
@@ -29,11 +41,34 @@ export function mapDbMemberToMember(dbMember: DbMember): Member {
|
||||
graduierung: dbMember.graduierung,
|
||||
vorname: dbMember.vorname,
|
||||
kontakt: dbMember.kontakt,
|
||||
kuendigungzum: dbMember.kuendigungzum,
|
||||
letztePruefung: dbMember.letztePruefung,
|
||||
kuendigungzum: dbMember.kuendigungzum?.toDateString() ?? null,
|
||||
letztePruefung: dbMember.letztePruefung?.toDateString() ?? null,
|
||||
passnummer: dbMember.passnummer,
|
||||
uvertrag: dbMember.uvertrag,
|
||||
verein: dbMember.verein,
|
||||
loeschenam: new Date(), //TODO
|
||||
marker: dbMember.marker,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapMemberDtoToDbMember(member: MemberDto): DbMember {
|
||||
return {
|
||||
id: member.id!,
|
||||
vorname: member.vorname,
|
||||
nachname: member.nachname,
|
||||
geburtsdatum: member.geburtsdatum
|
||||
? new Date(member.geburtsdatum)
|
||||
: null,
|
||||
geburtsort: member.geburtsort,
|
||||
geschlecht: member.geschlecht,
|
||||
passnummer: member.passnummer,
|
||||
verein: member.verein,
|
||||
graduierung: member.graduierung,
|
||||
letztePruefung: member.letztePruefung
|
||||
? new Date(member.letztePruefung)
|
||||
: null,
|
||||
kontakt: member.kontakt,
|
||||
kuendigungzum: member.kuendigungzum
|
||||
? new Date(member.kuendigungzum)
|
||||
: null,
|
||||
marker: member.marker,
|
||||
};
|
||||
}
|
||||
|
||||
+94
-48
@@ -1,67 +1,113 @@
|
||||
import constants from "constants";
|
||||
import cors from "cors";
|
||||
import express, {
|
||||
type NextFunction,
|
||||
type Request,
|
||||
type Response,
|
||||
} from "express";
|
||||
import fs from "fs";
|
||||
import https from "https";
|
||||
import { RegisterRoutes } from "./generated/routes.js";
|
||||
import { inject } from "./infrastructure/di/injector.js";
|
||||
import { sessionHandler } from "./infrastructure/sessionHandler.js";
|
||||
import { EnvironmentService } from "./services/environmentService.js";
|
||||
import { keycloak } from "./services/keycloak/user/index.js";
|
||||
import { KeycloakUser } from "./services/keycloak/user/keycloak-user.js";
|
||||
// import helmet from "helmet";
|
||||
// TODO import http2 from 'http2';
|
||||
|
||||
const app = express();
|
||||
async function run() {
|
||||
const app = express();
|
||||
const keycloakUser = inject(KeycloakUser);
|
||||
|
||||
app.use(sessionHandler);
|
||||
app.use(keycloak.middleware());
|
||||
//TODO app.use(helmet.hsts()); this and other helmets
|
||||
app.use(
|
||||
cors({
|
||||
origin: [
|
||||
"https://taekwondo-chemnitz.toni714.de",
|
||||
"https://tcc-1-ev-intern.web.app",
|
||||
"http://localhost:4200",
|
||||
"https://localhost:4200",
|
||||
"http://localhost:8080",
|
||||
],
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
||||
//TODO reevaluate
|
||||
}),
|
||||
);
|
||||
app.use(sessionHandler);
|
||||
app.use(await keycloakUser.middleware());
|
||||
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json());
|
||||
app.use(
|
||||
cors({
|
||||
origin: [
|
||||
"https://taekwondo-chemnitz.toni714.de",
|
||||
"https://tcc-1-ev-intern.web.app",
|
||||
"http://localhost:4200",
|
||||
"https://localhost:4200",
|
||||
"http://localhost:3000",
|
||||
"http://localhost:8080",
|
||||
],
|
||||
//TODO reevaluate
|
||||
}),
|
||||
);
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json());
|
||||
|
||||
// const dbService = inject(DatabaseService);
|
||||
// app.use(async (req, res, next) => {
|
||||
// await dbService.createTransaction(async prisma => {
|
||||
// (req as any).transaction = prisma;
|
||||
// return new Promise<void>((resolve, reject) => {
|
||||
// res.on("finish", resolve);
|
||||
// res.on("close", resolve);
|
||||
// res.on("error", reject);
|
||||
// next();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// const dbService = inject(DatabaseService);
|
||||
// app.use(async (req, res, next) => {
|
||||
// await dbService.createTransaction(async prisma => {
|
||||
// (req as any).transaction = prisma;
|
||||
// return new Promise<void>((resolve, reject) => {
|
||||
// res.on("finish", resolve);
|
||||
// res.on("close", resolve);
|
||||
// res.on("error", reject);
|
||||
// next();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
RegisterRoutes(app);
|
||||
RegisterRoutes(app);
|
||||
|
||||
const environment = inject(EnvironmentService);
|
||||
// wants to be last
|
||||
app.use((err: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
||||
res.status(500);
|
||||
res.send(JSON.stringify(err));
|
||||
throw err;
|
||||
});
|
||||
const environment = inject(EnvironmentService);
|
||||
// wants to be last
|
||||
app.use(
|
||||
(err: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
||||
console.dir(err);
|
||||
const ex = JSON.stringify(err);
|
||||
res.header("Content-Length", `${ex.length}`);
|
||||
res.status(500).send(ex);
|
||||
throw err;
|
||||
},
|
||||
);
|
||||
|
||||
if (environment.isDev()) {
|
||||
//TODO create self-signed for localhost
|
||||
const port = 3000;
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running at http://localhost:${port}`);
|
||||
});
|
||||
} else {
|
||||
//TODO start with HTTPS in production
|
||||
if (environment.isDev()) {
|
||||
//TODO create self-signed for localhost
|
||||
const port = 3000;
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running at http://localhost:${port}`);
|
||||
});
|
||||
} else {
|
||||
//TODO start with HTTPS in production
|
||||
const port = 5443;
|
||||
const SSL_CERT_PATH = process.env["SSL_CERT_PATH"];
|
||||
const SSL_KEY_PATH = process.env["SSL_KEY_PATH"];
|
||||
const SSL_KEY_PASSWORD = process.env["SSL_KEY_PASSWORD"];
|
||||
if (!SSL_CERT_PATH || !SSL_KEY_PATH || !SSL_KEY_PASSWORD) {
|
||||
throw new Error("Missing SSL configuration");
|
||||
}
|
||||
|
||||
const sslOptions: https.ServerOptions = {
|
||||
cert: fs.readFileSync(SSL_CERT_PATH),
|
||||
key: fs.readFileSync(SSL_KEY_PATH),
|
||||
passphrase: SSL_KEY_PASSWORD,
|
||||
minVersion: "TLSv1.3",
|
||||
maxVersion: "TLSv1.3",
|
||||
ecdhCurve: "X25519:prime256v1:secp384r1",
|
||||
honorCipherOrder: false,
|
||||
secureOptions:
|
||||
constants.SSL_OP_NO_TLSv1 |
|
||||
constants.SSL_OP_NO_TLSv1_1 |
|
||||
constants.SSL_OP_NO_TLSv1_2 |
|
||||
constants.SSL_OP_NO_SSLv2 |
|
||||
constants.SSL_OP_NO_SSLv3,
|
||||
};
|
||||
https.createServer(sslOptions, app).listen(port, () => {
|
||||
console.log(`Server is running on port ${port}`);
|
||||
});
|
||||
|
||||
// const h2SslOptions={};
|
||||
// http2.createServer(h2SslOptions, app).listen(port, ()=>{
|
||||
// console.log(`HTTP/2 server is running on port ${port}`);
|
||||
// })
|
||||
}
|
||||
|
||||
console.log("done");
|
||||
}
|
||||
|
||||
console.log("done");
|
||||
run();
|
||||
|
||||
@@ -1,39 +1,30 @@
|
||||
import { type Request, type RequestHandler } from "express";
|
||||
import { type Request, type Response } from "express";
|
||||
|
||||
import { KC_SECURITY_NAME, keycloak } from "../services/keycloak/user/index.js";
|
||||
import { inject } from "../infrastructure/di/index.js";
|
||||
import {
|
||||
KC_SECURITY_NAME,
|
||||
KeycloakUser,
|
||||
} from "../services/keycloak/user/index.js";
|
||||
|
||||
function promisifyMiddleware(
|
||||
request: Request,
|
||||
middleware: RequestHandler,
|
||||
response?: Response,
|
||||
): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
middleware(request, response || ({} as any), (next_result: any) => {
|
||||
console.dir(next_result);
|
||||
next_result instanceof Error
|
||||
? reject(next_result)
|
||||
: resolve(next_result);
|
||||
});
|
||||
});
|
||||
}
|
||||
const keycloak = inject(KeycloakUser);
|
||||
|
||||
async function doKeycloakAuth(
|
||||
request: Request,
|
||||
roles?: string[],
|
||||
response?: Response,
|
||||
): Promise<any> {
|
||||
if (roles && roles.length > 0) {
|
||||
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"));
|
||||
}
|
||||
if (!roles || roles.length < 1) {
|
||||
roles = ["default-roles-taekwondo"];
|
||||
}
|
||||
const allowed = await keycloak.checkRoles(
|
||||
roles,
|
||||
request,
|
||||
response ?? ({} as any),
|
||||
);
|
||||
if (allowed) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return await promisifyMiddleware(request, keycloak.protect(), response);
|
||||
return Promise.reject(httpError(403, "Forbidden"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ export class DatabaseService {
|
||||
private readonly prismaClient: ExtendedClient;
|
||||
|
||||
public constructor() {
|
||||
const dbUser = process.env["TKD_DB_USER"];
|
||||
const dbPassword = process.env["TKD_DB_PASSWORD"];
|
||||
const dbHost = process.env["TKD_DB_HOST"];
|
||||
const dbUser = process.env["TKD_DB_USER"]!;
|
||||
const dbPassword = process.env["TKD_DB_PASSWORD"]!;
|
||||
const dbHost = process.env["TKD_DB_HOST"]!;
|
||||
|
||||
const connectionString = `postgresql://${dbUser}:${dbPassword}@${dbHost}:5432/taekwondo?schema=public`;
|
||||
|
||||
|
||||
@@ -1,23 +1,43 @@
|
||||
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 type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation.js";
|
||||
import { Claim } from "../../../dtos/claim.js";
|
||||
import { type User } from "../../../dtos/user.js";
|
||||
import { inject } from "../../../infrastructure/di/index.js";
|
||||
import { EnvironmentService } from "../../environmentService.js";
|
||||
|
||||
@Injectable()
|
||||
export class KeycloakAdmin {
|
||||
private readonly kcAdminClient: Promise<KeycloakAdminClient>;
|
||||
private readonly environment = inject(EnvironmentService);
|
||||
private readonly config = this.getConfig();
|
||||
|
||||
private async getConfig() {
|
||||
if (this.environment.isDev()) {
|
||||
const config = await import("./nodejs-api.dev.json", {
|
||||
with: { type: "json" },
|
||||
});
|
||||
return config.default;
|
||||
} else {
|
||||
const config = await import("./nodejs-api.prod.json", {
|
||||
with: { type: "json" },
|
||||
});
|
||||
return config.default;
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.kcAdminClient = new Promise(async resolve => {
|
||||
const config = await this.config;
|
||||
const client = new KeycloakAdminClient({
|
||||
baseUrl: kcClientConfig.baseUrl,
|
||||
baseUrl: config["auth-server-url"],
|
||||
realmName: "taekwondo",
|
||||
});
|
||||
|
||||
await client.auth({
|
||||
...kcClientConfig,
|
||||
clientSecret: config.credentials.secret,
|
||||
clientId: config.resource,
|
||||
grantType: "client_credentials",
|
||||
});
|
||||
resolve(client);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"realm": "taekwondo",
|
||||
"auth-server-url": "http://localhost:8080/",
|
||||
"ssl-required": "external",
|
||||
"resource": "nodejs-api",
|
||||
"credentials": {
|
||||
"secret": "devsecret"
|
||||
},
|
||||
"confidential-port": 0
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"clientId": "nodejs-api",
|
||||
"name": "NodejsApi",
|
||||
"description": "",
|
||||
"rootUrl": "http://localhost:3000",
|
||||
"adminUrl": "http://localhost:3000",
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"surrogateAuthRequired": false,
|
||||
"enabled": true,
|
||||
"alwaysDisplayInConsole": false,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "devsecret",
|
||||
"redirectUris": ["http://localhost:3000/*"],
|
||||
"webOrigins": ["http://localhost:3000"],
|
||||
"notBefore": 0,
|
||||
"bearerOnly": false,
|
||||
"consentRequired": false,
|
||||
"standardFlowEnabled": false,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": false,
|
||||
"serviceAccountsEnabled": true,
|
||||
"publicClient": false,
|
||||
"frontchannelLogout": true,
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"realm_client": "false",
|
||||
"oidc.ciba.grant.enabled": "false",
|
||||
"client.secret.creation.time": "1762463686",
|
||||
"backchannel.logout.session.required": "true",
|
||||
"standard.token.exchange.enabled": "true",
|
||||
"oauth2.device.authorization.grant.enabled": "false",
|
||||
"pkce.code.challenge.method": "S256",
|
||||
"backchannel.logout.revoke.offline.tokens": "false",
|
||||
"dpop.bound.access.tokens": "false"
|
||||
},
|
||||
"authenticationFlowBindingOverrides": {},
|
||||
"fullScopeAllowed": true,
|
||||
"nodeReRegistrationTimeout": -1,
|
||||
"defaultClientScopes": [
|
||||
"service_account",
|
||||
"web-origins",
|
||||
"acr",
|
||||
"roles",
|
||||
"profile",
|
||||
"basic",
|
||||
"email"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"address",
|
||||
"phone",
|
||||
"organization",
|
||||
"offline_access",
|
||||
"microprofile-jwt"
|
||||
],
|
||||
"access": {
|
||||
"view": true,
|
||||
"configure": true,
|
||||
"manage": true
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,52 @@
|
||||
import { type Request, type RequestHandler, type Response } from "express";
|
||||
import KeycloakConnect from "keycloak-connect";
|
||||
import { inject } from "../../../infrastructure/di/index.js";
|
||||
import { Injectable } from "../../../infrastructure/di/injectable-decorator.js";
|
||||
import { sessionStore } from "../../../infrastructure/sessionHandler.js";
|
||||
import keycloakConfig from "./keycloak.json" with { type: "json" };
|
||||
import { EnvironmentService } from "../../environmentService.js";
|
||||
//TODO transform into service and load config based on environment (see keycloak-admin)
|
||||
|
||||
export const KC_SECURITY_NAME = "bearerAuth";
|
||||
|
||||
export const keycloak = new KeycloakConnect(
|
||||
{ store: sessionStore },
|
||||
keycloakConfig,
|
||||
);
|
||||
export const kcUserConfig = keycloakConfig;
|
||||
@Injectable()
|
||||
export class KeycloakUser {
|
||||
private readonly environment = inject(EnvironmentService);
|
||||
private readonly keycloakConnect: Promise<KeycloakConnect.Keycloak>;
|
||||
|
||||
private async getConfig() {
|
||||
if (this.environment.isDev()) {
|
||||
const config = await import("./keycloak.dev.json", {
|
||||
with: { type: "json" },
|
||||
});
|
||||
return config.default;
|
||||
} else {
|
||||
const config = await import("./keycloak.prod.json", {
|
||||
with: { type: "json" },
|
||||
});
|
||||
return config.default;
|
||||
}
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
this.keycloakConnect = new Promise(async resolve => {
|
||||
const config = await this.getConfig();
|
||||
const client = new KeycloakConnect({ store: sessionStore }, config);
|
||||
resolve(client);
|
||||
});
|
||||
}
|
||||
|
||||
public async checkRoles(
|
||||
roles: string[],
|
||||
request: Request,
|
||||
response: Response,
|
||||
) {
|
||||
const client = await this.keycloakConnect;
|
||||
const grant = await client.getGrant(request, response ?? ({} as any));
|
||||
return roles.every(role => grant.access_token?.hasRealmRole(role));
|
||||
}
|
||||
|
||||
public async middleware(): Promise<RequestHandler[]> {
|
||||
const client = await this.keycloakConnect;
|
||||
return client.middleware();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import express from "express";
|
||||
import {
|
||||
type Member,
|
||||
type MemberCreateArgs,
|
||||
type MemberDto,
|
||||
mapDbMemberToMember,
|
||||
} from "../dtos/member.js";
|
||||
import { inject, Injectable } from "../infrastructure/di/index.js";
|
||||
@@ -12,7 +12,7 @@ import { DatabaseService } from "./db/prisma.js";
|
||||
export class MembersService {
|
||||
private readonly database = inject(DatabaseService);
|
||||
|
||||
public async getMembers(request: express.Request): Promise<Member[]> {
|
||||
public async getMembers(request: express.Request): Promise<MemberDto[]> {
|
||||
const dbMembers = await this.database.doRequest(
|
||||
async prisma => await prisma.member.findMany(),
|
||||
request,
|
||||
@@ -23,7 +23,7 @@ export class MembersService {
|
||||
public async getMemberById(
|
||||
memberId: string,
|
||||
request: express.Request,
|
||||
): Promise<Member> {
|
||||
): Promise<MemberDto> {
|
||||
const member = await this.database.doRequest(
|
||||
async prisma =>
|
||||
await prisma.member.findFirst({ where: { id: memberId } }),
|
||||
@@ -42,11 +42,11 @@ export class MembersService {
|
||||
public async createMember(
|
||||
createArgs: MemberCreateArgs,
|
||||
request: express.Request,
|
||||
): Promise<Member> {
|
||||
const x: MemberCreateArgs = {
|
||||
...createArgs,
|
||||
geburtsdatum: createArgs.geburtsdatum ?? null,
|
||||
};
|
||||
): Promise<MemberDto> {
|
||||
// const x: MemberCreateArgs = {
|
||||
// ...createArgs,
|
||||
// geburtsdatum: createArgs.geburtsdatum ?? null,
|
||||
// };
|
||||
const newMember = await this.database.doRequest(
|
||||
async prisma => await prisma.member.create({ data: createArgs }),
|
||||
request,
|
||||
@@ -55,15 +55,16 @@ export class MembersService {
|
||||
}
|
||||
|
||||
public async updateMember(
|
||||
member: Member,
|
||||
member: MemberDto,
|
||||
request: express.Request,
|
||||
): Promise<Member> {
|
||||
): Promise<MemberDto> {
|
||||
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(
|
||||
async prisma =>
|
||||
await prisma.member.update({
|
||||
|
||||
Reference in New Issue
Block a user