update packages, using FirebaseAdminModule
This commit is contained in:
parent
521e799bff
commit
27242819e2
|
|
@ -5,7 +5,8 @@
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug Nest Framework",
|
"name": "Debug Nest Framework",
|
||||||
"runtimeExecutable": "npm",
|
//"runtimeExecutable": "npm",
|
||||||
|
"runtimeExecutable": "/home/aknuth/.nvm/versions/node/v22.14.0/bin/npm",
|
||||||
"runtimeArgs": ["run", "start:debug", "--", "--inspect-brk"],
|
"runtimeArgs": ["run", "start:debug", "--", "--inspect-brk"],
|
||||||
"autoAttachChildProcesses": true,
|
"autoAttachChildProcesses": true,
|
||||||
"restart": true,
|
"restart": true,
|
||||||
|
|
|
||||||
|
|
@ -26,32 +26,23 @@
|
||||||
"generateTypes": "tsx src/drizzle/generateTypes.ts src/drizzle/schema.ts src/models/db.model.ts"
|
"generateTypes": "tsx src/drizzle/generateTypes.ts src/drizzle/schema.ts src/models/db.model.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs-modules/mailer": "^1.10.3",
|
"@nestjs-modules/mailer": "^2.0.2",
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^11.0.11",
|
||||||
"@nestjs/config": "^3.2.0",
|
"@nestjs/config": "^4.0.0",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^11.0.11",
|
||||||
"@nestjs/jwt": "^10.2.0",
|
"@nestjs/platform-express": "^11.0.11",
|
||||||
"@nestjs/passport": "^10.0.3",
|
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
|
||||||
"@nestjs/serve-static": "^4.0.1",
|
|
||||||
"@types/stripe": "^8.0.417",
|
"@types/stripe": "^8.0.417",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"cls-hooked": "^4.2.2",
|
"cls-hooked": "^4.2.2",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
|
||||||
"dotenv-flow": "^4.1.0",
|
|
||||||
"drizzle-orm": "^0.32.0",
|
"drizzle-orm": "^0.32.0",
|
||||||
"firebase": "^11.3.1",
|
"firebase": "^11.3.1",
|
||||||
"firebase-admin": "^13.1.0",
|
"firebase-admin": "^13.1.0",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"groq-sdk": "^0.5.0",
|
"groq-sdk": "^0.5.0",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"jsonwebtoken": "^9.0.2",
|
|
||||||
"jwk-to-pem": "^2.0.6",
|
|
||||||
"jwks-rsa": "^3.1.0",
|
|
||||||
"ky": "^1.4.0",
|
|
||||||
"nest-winston": "^1.9.4",
|
"nest-winston": "^1.9.4",
|
||||||
"nestjs-cls": "^4.4.1",
|
"nestjs-cls": "^5.4.0",
|
||||||
"nodemailer": "^6.9.10",
|
"nodemailer": "^6.9.10",
|
||||||
"nodemailer-smtp-transport": "^2.7.4",
|
"nodemailer-smtp-transport": "^2.7.4",
|
||||||
"openai": "^4.52.6",
|
"openai": "^4.52.6",
|
||||||
|
|
@ -69,30 +60,20 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/parser": "^7.24.4",
|
"@babel/parser": "^7.24.4",
|
||||||
"@babel/traverse": "^7.24.1",
|
"@babel/traverse": "^7.24.1",
|
||||||
"@nestjs/cli": "^10.0.0",
|
"@nestjs/cli": "^11.0.5",
|
||||||
"@nestjs/schematics": "^10.0.0",
|
"@nestjs/schematics": "^11.0.1",
|
||||||
"@nestjs/testing": "^10.0.0",
|
"@nestjs/testing": "^11.0.11",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/jest": "^29.5.2",
|
|
||||||
"@types/jsonwebtoken": "^9.0.6",
|
|
||||||
"@types/jwk-to-pem": "^2.0.3",
|
|
||||||
"@types/multer": "^1.4.11",
|
"@types/multer": "^1.4.11",
|
||||||
"@types/node": "^20.11.19",
|
"@types/node": "^20.11.19",
|
||||||
"@types/nodemailer": "^6.4.14",
|
"@types/nodemailer": "^6.4.14",
|
||||||
"@types/passport-google-oauth20": "^2.0.14",
|
|
||||||
"@types/passport-jwt": "^4.0.1",
|
|
||||||
"@types/passport-local": "^1.0.38",
|
|
||||||
"@types/pg": "^8.11.5",
|
"@types/pg": "^8.11.5",
|
||||||
"@types/supertest": "^6.0.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
||||||
"@typescript-eslint/parser": "^6.0.0",
|
|
||||||
"commander": "^12.0.0",
|
"commander": "^12.0.0",
|
||||||
"drizzle-kit": "^0.23.0",
|
"drizzle-kit": "^0.23.0",
|
||||||
"esbuild-register": "^3.5.0",
|
"esbuild-register": "^3.5.0",
|
||||||
"eslint": "^8.42.0",
|
"eslint": "^8.42.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"jest": "^29.5.0",
|
|
||||||
"kysely-codegen": "^0.15.0",
|
"kysely-codegen": "^0.15.0",
|
||||||
"pg-to-ts": "^4.1.1",
|
"pg-to-ts": "^4.1.1",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
import { Controller, Get, Request, UseGuards } from '@nestjs/common';
|
import { Controller, Get, Request, UseGuards } from '@nestjs/common';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { AuthService } from './auth/auth.service';
|
|
||||||
import { AuthGuard } from './jwt-auth/auth.guard';
|
import { AuthGuard } from './jwt-auth/auth.guard';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly appService: AppService,
|
private readonly appService: AppService,
|
||||||
private authService: AuthService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
|
||||||
import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston';
|
import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston';
|
||||||
import * as winston from 'winston';
|
import * as winston from 'winston';
|
||||||
import { AiModule } from './ai/ai.module';
|
import { AiModule } from './ai/ai.module';
|
||||||
|
|
@ -13,32 +12,33 @@ import { ListingsModule } from './listings/listings.module';
|
||||||
import { LogController } from './log/log.controller';
|
import { LogController } from './log/log.controller';
|
||||||
import { LogModule } from './log/log.module';
|
import { LogModule } from './log/log.module';
|
||||||
|
|
||||||
import dotenvFlow from 'dotenv-flow';
|
|
||||||
import { EventModule } from './event/event.module';
|
import { EventModule } from './event/event.module';
|
||||||
import { MailModule } from './mail/mail.module';
|
import { MailModule } from './mail/mail.module';
|
||||||
|
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||||
import { ClsMiddleware, ClsModule } from 'nestjs-cls';
|
import { ClsMiddleware, ClsModule } from 'nestjs-cls';
|
||||||
|
import path from 'path';
|
||||||
import { LoggingInterceptor } from './interceptors/logging.interceptor';
|
import { LoggingInterceptor } from './interceptors/logging.interceptor';
|
||||||
import { UserInterceptor } from './interceptors/user.interceptor';
|
import { UserInterceptor } from './interceptors/user.interceptor';
|
||||||
import { RequestDurationMiddleware } from './request-duration/request-duration.middleware';
|
import { RequestDurationMiddleware } from './request-duration/request-duration.middleware';
|
||||||
import { SelectOptionsModule } from './select-options/select-options.module';
|
import { SelectOptionsModule } from './select-options/select-options.module';
|
||||||
import { UserModule } from './user/user.module';
|
import { UserModule } from './user/user.module';
|
||||||
|
import { FirebaseAdminModule } from './firebase-admin/firebase-admin.module';
|
||||||
|
|
||||||
//loadEnvFiles();
|
//loadEnvFiles();
|
||||||
dotenvFlow.config();
|
|
||||||
console.log('Loaded environment variables:');
|
console.log('Loaded environment variables:');
|
||||||
console.log(JSON.stringify(process.env, null, 2));
|
//console.log(JSON.stringify(process.env, null, 2));
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ClsModule.forRoot({
|
ClsModule.forRoot({
|
||||||
global: true, // Macht den ClsService global verfügbar
|
global: true, // Macht den ClsService global verfügbar
|
||||||
middleware: { mount: true }, // Registriert automatisch die ClsMiddleware
|
middleware: { mount: true }, // Registriert automatisch die ClsMiddleware
|
||||||
// setup: clsService => {
|
|
||||||
// // Optional: zusätzliche Setup-Logik
|
|
||||||
// },
|
|
||||||
}),
|
}),
|
||||||
ConfigModule.forRoot({ isGlobal: true }),
|
//ConfigModule.forRoot({ envFilePath: '.env' }),
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
envFilePath: [path.resolve(__dirname, '..', '.env')],
|
||||||
|
}),
|
||||||
MailModule,
|
MailModule,
|
||||||
AuthModule,
|
AuthModule,
|
||||||
WinstonModule.forRoot({
|
WinstonModule.forRoot({
|
||||||
|
|
@ -68,6 +68,7 @@ console.log(JSON.stringify(process.env, null, 2));
|
||||||
LogModule,
|
LogModule,
|
||||||
// PaymentModule,
|
// PaymentModule,
|
||||||
EventModule,
|
EventModule,
|
||||||
|
FirebaseAdminModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController, LogController],
|
controllers: [AppController, LogController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,12 @@
|
||||||
import { Body, Controller, Get, HttpException, HttpStatus, Param, Post, Put, UseGuards } from '@nestjs/common';
|
import { Body, Controller, HttpException, HttpStatus, Inject, Post } from '@nestjs/common';
|
||||||
import { AuthGuard } from 'src/jwt-auth/auth.guard';
|
import * as admin from 'firebase-admin';
|
||||||
import admin from 'src/jwt-auth/firebase-admin';
|
|
||||||
import { KeycloakUser } from 'src/models/main.model';
|
|
||||||
import { AuthService } from './auth.service';
|
|
||||||
|
|
||||||
@Controller('auth')
|
@Controller('auth')
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
constructor(private readonly authService: AuthService) {}
|
constructor(
|
||||||
|
@Inject('FIREBASE_ADMIN')
|
||||||
// @UseGuards(AdminAuthGuard)
|
private readonly firebaseAdmin: typeof admin,
|
||||||
// @Get()
|
) {}
|
||||||
// async getAccessToken(): Promise<any> {
|
|
||||||
// return await this.authService.getAccessToken();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @UseGuards(AdminAuthGuard)
|
|
||||||
// @Get('user/all')
|
|
||||||
// async getUsers(): Promise<any> {
|
|
||||||
// return await this.authService.getUsers();
|
|
||||||
// }
|
|
||||||
|
|
||||||
@UseGuards(AuthGuard)
|
|
||||||
@Get('users/:userid')
|
|
||||||
async getUser(@Param('userid') userId: string): Promise<any> {
|
|
||||||
return await this.authService.getUser(userId);
|
|
||||||
}
|
|
||||||
@UseGuards(AuthGuard)
|
|
||||||
@Put('users/:userid')
|
|
||||||
async updateKeycloakUser(@Body() keycloakUser: KeycloakUser): Promise<any> {
|
|
||||||
return await this.authService.updateKeycloakUser(keycloakUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('verify-email')
|
@Post('verify-email')
|
||||||
async verifyEmail(@Body('oobCode') oobCode: string, @Body('email') email: string) {
|
async verifyEmail(@Body('oobCode') oobCode: string, @Body('email') email: string) {
|
||||||
if (!oobCode || !email) {
|
if (!oobCode || !email) {
|
||||||
|
|
@ -39,7 +15,7 @@ export class AuthController {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Schritt 1: Hole den Benutzer anhand der E-Mail-Adresse
|
// Schritt 1: Hole den Benutzer anhand der E-Mail-Adresse
|
||||||
const userRecord = await admin.auth().getUserByEmail(email);
|
const userRecord = await this.firebaseAdmin.auth().getUserByEmail(email);
|
||||||
|
|
||||||
if (userRecord.emailVerified) {
|
if (userRecord.emailVerified) {
|
||||||
return { message: 'Email is already verified' };
|
return { message: 'Email is already verified' };
|
||||||
|
|
@ -48,7 +24,7 @@ export class AuthController {
|
||||||
// Schritt 2: Aktualisiere den Benutzerstatus
|
// Schritt 2: Aktualisiere den Benutzerstatus
|
||||||
// Hinweis: Wir können den oobCode nicht serverseitig validieren.
|
// Hinweis: Wir können den oobCode nicht serverseitig validieren.
|
||||||
// Wir nehmen an, dass der oobCode korrekt ist, da er von Firebase generiert wurde.
|
// Wir nehmen an, dass der oobCode korrekt ist, da er von Firebase generiert wurde.
|
||||||
await admin.auth().updateUser(userRecord.uid, {
|
await this.firebaseAdmin.auth().updateUser(userRecord.uid, {
|
||||||
emailVerified: true,
|
emailVerified: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -57,9 +33,5 @@ export class AuthController {
|
||||||
throw new HttpException(error.message || 'Failed to verify email', HttpStatus.BAD_REQUEST);
|
throw new HttpException(error.message || 'Failed to verify email', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// @UseGuards(AdminAuthGuard)
|
|
||||||
// @Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
|
|
||||||
// getLastLogin(@Param('userid') userId: string): any {
|
|
||||||
// return this.authService.getLastLogin(userId);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { AuthController } from './auth.controller';
|
import { AuthController } from './auth.controller';
|
||||||
import { AuthService } from './auth.service';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [PassportModule],
|
imports: [ConfigModule.forRoot({ envFilePath: '.env' }),FirebaseAdminModule],
|
||||||
providers: [AuthService],
|
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
exports: [AuthService],
|
exports: [],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { KeycloakUser } from 'src/models/main.model';
|
|
||||||
import urlcat from 'urlcat';
|
|
||||||
@Injectable()
|
|
||||||
export class AuthService {
|
|
||||||
public async getAccessToken() {
|
|
||||||
try {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
params.append('grant_type', 'password');
|
|
||||||
params.append('username', process.env.KEYCLOAK_ADMIN_USER);
|
|
||||||
params.append('password', process.env.KEYCLOAK_ADMIN_PASSWORD);
|
|
||||||
const URL = `${process.env.KEYCLOAK_HOST}${process.env.KEYCLOAK_TOKEN_URL}`;
|
|
||||||
|
|
||||||
const response = await fetch(URL, {
|
|
||||||
method: 'POST',
|
|
||||||
body: params.toString(),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
Authorization: process.env.KEYCLOAK_ADMIN_TOKEN,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
return (<any>data).access_token;
|
|
||||||
} catch (error) {
|
|
||||||
if (error.name === 'HTTPError') {
|
|
||||||
const errorJson = await error.response.json();
|
|
||||||
console.error('Fehlerantwort vom Server:', errorJson);
|
|
||||||
} else {
|
|
||||||
console.error('Allgemeiner Fehler:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getUsers(): Promise<KeycloakUser[]> {
|
|
||||||
const token = await this.getAccessToken();
|
|
||||||
const URL = `${process.env.KEYCLOAK_HOST}${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_USERS_URL}`;
|
|
||||||
const response = await fetch(URL, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
return data as KeycloakUser[];
|
|
||||||
}
|
|
||||||
public async getUser(userid: string): Promise<KeycloakUser> {
|
|
||||||
const token = await this.getAccessToken();
|
|
||||||
const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_USER_URL}`;
|
|
||||||
const URL = urlcat(process.env.KEYCLOAK_HOST, URLPATH, { userid });
|
|
||||||
const response = await fetch(URL, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
return data as KeycloakUser;
|
|
||||||
}
|
|
||||||
public async updateKeycloakUser(keycloakUser: KeycloakUser): Promise<void> {
|
|
||||||
const token = await this.getAccessToken();
|
|
||||||
const userid = keycloakUser.id;
|
|
||||||
const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_USER_URL}`;
|
|
||||||
const URL = urlcat(process.env.KEYCLOAK_HOST, URLPATH, { userid });
|
|
||||||
const response = await fetch(URL, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify(keycloakUser),
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// public async getLastLogin(userid: string) {
|
|
||||||
// const token = await this.getAccessToken();
|
|
||||||
// const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_LASTLOGIN_URL}`;
|
|
||||||
// const URL = urlcat(process.env.KEYCLOAK_HOST, URLPATH, { userid });
|
|
||||||
// const response = await ky
|
|
||||||
// .get(URL, {
|
|
||||||
// headers: {
|
|
||||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
// Authorization: `Bearer ${token}`,
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
// .json();
|
|
||||||
// return response;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||||
import { ClsService } from 'nestjs-cls';
|
import { ClsService } from 'nestjs-cls';
|
||||||
|
|
@ -9,12 +9,14 @@ import * as schema from './schema';
|
||||||
import { PG_CONNECTION } from './schema';
|
import { PG_CONNECTION } from './schema';
|
||||||
const { Pool } = pkg;
|
const { Pool } = pkg;
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: PG_CONNECTION,
|
provide: PG_CONNECTION,
|
||||||
inject: [ConfigService, WINSTON_MODULE_PROVIDER, ClsService],
|
inject: [ConfigService, WINSTON_MODULE_PROVIDER, ClsService],
|
||||||
useFactory: async (configService: ConfigService, logger: Logger, cls: ClsService) => {
|
useFactory: async (configService: ConfigService, logger: Logger, cls: ClsService) => {
|
||||||
const connectionString = configService.get<string>('DATABASE_URL');
|
const connectionString = configService.get<string>('DATABASE_URL');
|
||||||
|
console.log('--->',connectionString)
|
||||||
const pool = new Pool({
|
const pool = new Pool({
|
||||||
connectionString,
|
connectionString,
|
||||||
// ssl: true, // Falls benötigt
|
// ssl: true, // Falls benötigt
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dotenv/config';
|
|
||||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { Pool } from 'pg';
|
import { Pool } from 'pg';
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { DrizzleModule } from 'src/drizzle/drizzle.module';
|
import { DrizzleModule } from 'src/drizzle/drizzle.module';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { EventController } from './event.controller';
|
import { EventController } from './event.controller';
|
||||||
import { EventService } from './event.service';
|
import { EventService } from './event.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DrizzleModule],
|
imports: [DrizzleModule,FirebaseAdminModule],
|
||||||
controllers: [EventController],
|
controllers: [EventController],
|
||||||
providers: [EventService],
|
providers: [EventService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
import * as admin from 'firebase-admin';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: 'FIREBASE_ADMIN',
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: (configService: ConfigService) => {
|
||||||
|
const serviceAccount = {
|
||||||
|
projectId: configService.get<string>('FIREBASE_PROJECT_ID'),
|
||||||
|
clientEmail: configService.get<string>('FIREBASE_CLIENT_EMAIL'),
|
||||||
|
privateKey: configService.get<string>('FIREBASE_PRIVATE_KEY')?.replace(/\\n/g, '\n'),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!admin.apps.length) {
|
||||||
|
admin.initializeApp({
|
||||||
|
credential: admin.credential.cert(serviceAccount),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return admin;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
exports: ['FIREBASE_ADMIN'],
|
||||||
|
})
|
||||||
|
export class FirebaseAdminModule {}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { GeoController } from './geo.controller';
|
import { GeoController } from './geo.controller';
|
||||||
import { GeoService } from './geo.service';
|
import { GeoService } from './geo.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [FirebaseAdminModule],
|
||||||
controllers: [GeoController],
|
controllers: [GeoController],
|
||||||
providers: [GeoService],
|
providers: [GeoService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { FileService } from '../file/file.service';
|
import { FileService } from '../file/file.service';
|
||||||
import { ListingsModule } from '../listings/listings.module';
|
import { ListingsModule } from '../listings/listings.module';
|
||||||
import { SelectOptionsService } from '../select-options/select-options.service';
|
import { SelectOptionsService } from '../select-options/select-options.service';
|
||||||
|
|
@ -6,7 +7,7 @@ import { ImageController } from './image.controller';
|
||||||
import { ImageService } from './image.service';
|
import { ImageService } from './image.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ListingsModule],
|
imports: [ListingsModule,FirebaseAdminModule],
|
||||||
controllers: [ImageController],
|
controllers: [ImageController],
|
||||||
providers: [ImageService, FileService, SelectOptionsService],
|
providers: [ImageService, FileService, SelectOptionsService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
import admin from './firebase-admin';
|
import * as admin from 'firebase-admin';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthGuard implements CanActivate {
|
export class AuthGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
@Inject('FIREBASE_ADMIN')
|
||||||
|
private readonly firebaseAdmin: typeof admin,
|
||||||
|
) {}
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
const request = context.switchToHttp().getRequest<Request>();
|
const request = context.switchToHttp().getRequest<Request>();
|
||||||
const token = this.extractTokenFromHeader(request);
|
const token = this.extractTokenFromHeader(request);
|
||||||
|
|
@ -12,8 +17,8 @@ export class AuthGuard implements CanActivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decodedToken = await admin.auth().verifyIdToken(token);
|
const decodedToken = await this.firebaseAdmin.auth().verifyIdToken(token);
|
||||||
request['user'] = decodedToken; // Fügen Sie die Benutzerdaten dem Request-Objekt hinzu
|
request['user'] = decodedToken;
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new UnauthorizedException('Invalid token');
|
throw new UnauthorizedException('Invalid token');
|
||||||
|
|
@ -25,3 +30,27 @@ export class AuthGuard implements CanActivate {
|
||||||
return type === 'Bearer' ? token : undefined;
|
return type === 'Bearer' ? token : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @Injectable()
|
||||||
|
// export class AuthGuard implements CanActivate {
|
||||||
|
// async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
// const request = context.switchToHttp().getRequest<Request>();
|
||||||
|
// const token = this.extractTokenFromHeader(request);
|
||||||
|
|
||||||
|
// if (!token) {
|
||||||
|
// throw new UnauthorizedException('No token provided');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// const decodedToken = await admin.auth().verifyIdToken(token);
|
||||||
|
// request['user'] = decodedToken; // Fügen Sie die Benutzerdaten dem Request-Objekt hinzu
|
||||||
|
// return true;
|
||||||
|
// } catch (error) {
|
||||||
|
// throw new UnauthorizedException('Invalid token');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private extractTokenFromHeader(request: Request): string | undefined {
|
||||||
|
// const [type, token] = request.headers['authorization']?.split(' ') ?? [];
|
||||||
|
// return type === 'Bearer' ? token : undefined;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import * as admin from 'firebase-admin';
|
// import * as admin from 'firebase-admin';
|
||||||
import { ServiceAccount } from 'firebase-admin';
|
// import { ServiceAccount } from 'firebase-admin';
|
||||||
|
// console.log('--> '+process.env['FIREBASE_PROJECT_ID'])
|
||||||
|
// const serviceAccount: ServiceAccount = {
|
||||||
|
// projectId: process.env['FIREBASE_PROJECT_ID'],
|
||||||
|
// clientEmail: process.env['FIREBASE_CLIENT_EMAIL'],
|
||||||
|
// privateKey: process.env['FIREBASE_PRIVATE_KEY']?.replace(/\\n/g, '\n'), // Ersetzen Sie escaped newlines
|
||||||
|
// };
|
||||||
|
|
||||||
const serviceAccount: ServiceAccount = {
|
// if (!admin.apps.length) {
|
||||||
projectId: process.env['FIREBASE_PROJECT_ID'],
|
// admin.initializeApp({
|
||||||
clientEmail: process.env['FIREBASE_CLIENT_EMAIL'],
|
// credential: admin.credential.cert(serviceAccount),
|
||||||
privateKey: process.env['FIREBASE_PRIVATE_KEY']?.replace(/\\n/g, '\n'), // Ersetzen Sie escaped newlines
|
// });
|
||||||
};
|
// }
|
||||||
|
|
||||||
if (!admin.apps.length) {
|
// export default admin;
|
||||||
admin.initializeApp({
|
|
||||||
credential: admin.credential.cert(serviceAccount),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default admin;
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,30 @@
|
||||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
import { CanActivate, ExecutionContext, Inject, Injectable } from '@nestjs/common';
|
||||||
import admin from './firebase-admin';
|
import * as admin from 'firebase-admin';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OptionalAuthGuard implements CanActivate {
|
export class OptionalAuthGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
@Inject('FIREBASE_ADMIN')
|
||||||
|
private readonly firebaseAdmin: typeof admin,
|
||||||
|
) {}
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
const request = context.switchToHttp().getRequest<Request>();
|
const request = context.switchToHttp().getRequest<Request>();
|
||||||
const token = this.extractTokenFromHeader(request);
|
const token = this.extractTokenFromHeader(request);
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return true; // Kein Token vorhanden, aber Zugriff erlaubt
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decodedToken = await admin.auth().verifyIdToken(token);
|
const decodedToken = await this.firebaseAdmin.auth().verifyIdToken(token);
|
||||||
request['user'] = decodedToken; // Benutzerdaten zum Request hinzufügen, wenn Token gültig
|
request['user'] = decodedToken;
|
||||||
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Bei ungültigem Token wird kein Fehler geworfen, sondern einfach kein User gesetzt
|
//throw new UnauthorizedException('Invalid token');
|
||||||
request['user'] = null;
|
request['user'] = null;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // Zugriff wird immer erlaubt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractTokenFromHeader(request: Request): string | undefined {
|
private extractTokenFromHeader(request: Request): string | undefined {
|
||||||
|
|
@ -27,3 +32,29 @@ export class OptionalAuthGuard implements CanActivate {
|
||||||
return type === 'Bearer' ? token : undefined;
|
return type === 'Bearer' ? token : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @Injectable()
|
||||||
|
// export class OptionalAuthGuard implements CanActivate {
|
||||||
|
// async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
// const request = context.switchToHttp().getRequest<Request>();
|
||||||
|
// const token = this.extractTokenFromHeader(request);
|
||||||
|
|
||||||
|
// if (!token) {
|
||||||
|
// return true; // Kein Token vorhanden, aber Zugriff erlaubt
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// const decodedToken = await admin.auth().verifyIdToken(token);
|
||||||
|
// request['user'] = decodedToken; // Benutzerdaten zum Request hinzufügen, wenn Token gültig
|
||||||
|
// } catch (error) {
|
||||||
|
// // Bei ungültigem Token wird kein Fehler geworfen, sondern einfach kein User gesetzt
|
||||||
|
// request['user'] = null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return true; // Zugriff wird immer erlaubt
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private extractTokenFromHeader(request: Request): string | undefined {
|
||||||
|
// const [type, token] = request.headers['authorization']?.split(' ') ?? [];
|
||||||
|
// return type === 'Bearer' ? token : undefined;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import { Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
|
||||||
import { PassportStrategy } from '@nestjs/passport';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { passportJwtSecret } from 'jwks-rsa';
|
|
||||||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
||||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
||||||
import path from 'path';
|
|
||||||
import { Logger } from 'winston';
|
|
||||||
import { JwtPayload, JwtUser } from './models/main.model';
|
|
||||||
// const logger = winston.createLogger({
|
|
||||||
// transports: [new winston.transports.Console()],
|
|
||||||
// });
|
|
||||||
// const pemCache = new Map();
|
|
||||||
@Injectable()
|
|
||||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
||||||
constructor(
|
|
||||||
configService: ConfigService,
|
|
||||||
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
|
|
||||||
) {
|
|
||||||
const realm = configService.get<string>('REALM');
|
|
||||||
// const staticCerts = loadStaticCerts();
|
|
||||||
super({
|
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
||||||
ignoreExpiration: false,
|
|
||||||
secretOrKeyProvider: passportJwtSecret({
|
|
||||||
cache: true,
|
|
||||||
rateLimit: false,
|
|
||||||
// jwksRequestsPerMinute: 5,
|
|
||||||
jwksUri: `https://auth.bizmatch.net/realms/${realm}/protocol/openid-connect/certs`,
|
|
||||||
}),
|
|
||||||
audience: 'account', // Keycloak Client ID
|
|
||||||
authorize: '',
|
|
||||||
issuer: `https://auth.bizmatch.net/realms/${realm}`,
|
|
||||||
algorithms: ['RS256'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async validate(payload: JwtPayload): Promise<JwtUser> {
|
|
||||||
if (!payload) {
|
|
||||||
this.logger.error('Invalid payload');
|
|
||||||
throw new UnauthorizedException();
|
|
||||||
}
|
|
||||||
if (!payload.sub || !payload.preferred_username) {
|
|
||||||
this.logger.error('Missing required claims');
|
|
||||||
throw new UnauthorizedException();
|
|
||||||
}
|
|
||||||
const result = { userId: payload.sub, firstname: payload.given_name, lastname: payload.family_name, username: payload.preferred_username, roles: payload.realm_access?.roles };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function loadStaticCerts() {
|
|
||||||
const certsPath = path.join(__dirname, '../', 'assets', 'keycloak-certs.json');
|
|
||||||
const certsData = fs.readFileSync(certsPath, 'utf8');
|
|
||||||
return JSON.parse(certsData);
|
|
||||||
}
|
|
||||||
|
|
@ -103,7 +103,7 @@ export class BusinessListingService {
|
||||||
whereConditions.push(and(ilike(schema.users.firstname, `%${firstname}%`), ilike(schema.users.lastname, `%${lastname}%`)));
|
whereConditions.push(and(ilike(schema.users.firstname, `%${firstname}%`), ilike(schema.users.lastname, `%${lastname}%`)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!user?.roles?.includes('ADMIN') ?? false) {
|
if (!user?.roles?.includes('ADMIN')) {
|
||||||
whereConditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
|
whereConditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
|
||||||
}
|
}
|
||||||
whereConditions.push(and(eq(schema.users.customerType, 'professional'), eq(schema.users.customerSubType, 'broker')));
|
whereConditions.push(and(eq(schema.users.customerType, 'professional'), eq(schema.users.customerSubType, 'broker')));
|
||||||
|
|
@ -186,7 +186,7 @@ export class BusinessListingService {
|
||||||
|
|
||||||
async findBusinessesById(id: string, user: JwtUser): Promise<BusinessListing> {
|
async findBusinessesById(id: string, user: JwtUser): Promise<BusinessListing> {
|
||||||
const conditions = [];
|
const conditions = [];
|
||||||
if (!user?.roles?.includes('ADMIN') ?? false) {
|
if (!user?.roles?.includes('ADMIN')) {
|
||||||
conditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
|
conditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
|
||||||
}
|
}
|
||||||
conditions.push(sql`${businesses.id} = ${id}`);
|
conditions.push(sql`${businesses.id} = ${id}`);
|
||||||
|
|
@ -204,7 +204,7 @@ export class BusinessListingService {
|
||||||
async findBusinessesByEmail(email: string, user: JwtUser): Promise<BusinessListing[]> {
|
async findBusinessesByEmail(email: string, user: JwtUser): Promise<BusinessListing[]> {
|
||||||
const conditions = [];
|
const conditions = [];
|
||||||
conditions.push(eq(businesses.email, email));
|
conditions.push(eq(businesses.email, email));
|
||||||
if (email !== user?.username && (!user?.roles?.includes('ADMIN') ?? false)) {
|
if (email !== user?.username && (!user?.roles?.includes('ADMIN'))) {
|
||||||
conditions.push(ne(businesses.draft, true));
|
conditions.push(ne(businesses.draft, true));
|
||||||
}
|
}
|
||||||
const listings = (await this.conn
|
const listings = (await this.conn
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export class CommercialPropertyService {
|
||||||
if (criteria.title) {
|
if (criteria.title) {
|
||||||
whereConditions.push(or(ilike(schema.commercials.title, `%${criteria.title}%`), ilike(schema.commercials.description, `%${criteria.title}%`)));
|
whereConditions.push(or(ilike(schema.commercials.title, `%${criteria.title}%`), ilike(schema.commercials.description, `%${criteria.title}%`)));
|
||||||
}
|
}
|
||||||
if (!user?.roles?.includes('ADMIN') ?? false) {
|
if (!user?.roles?.includes('ADMIN')) {
|
||||||
whereConditions.push(or(eq(commercials.email, user?.username), ne(commercials.draft, true)));
|
whereConditions.push(or(eq(commercials.email, user?.username), ne(commercials.draft, true)));
|
||||||
}
|
}
|
||||||
// whereConditions.push(and(eq(schema.users.customerType, 'professional')));
|
// whereConditions.push(and(eq(schema.users.customerType, 'professional')));
|
||||||
|
|
@ -113,7 +113,7 @@ export class CommercialPropertyService {
|
||||||
// #### Find by ID ########################################
|
// #### Find by ID ########################################
|
||||||
async findCommercialPropertiesById(id: string, user: JwtUser): Promise<CommercialPropertyListing> {
|
async findCommercialPropertiesById(id: string, user: JwtUser): Promise<CommercialPropertyListing> {
|
||||||
const conditions = [];
|
const conditions = [];
|
||||||
if (!user?.roles?.includes('ADMIN') ?? false) {
|
if (!user?.roles?.includes('ADMIN')) {
|
||||||
conditions.push(or(eq(commercials.email, user?.username), ne(commercials.draft, true)));
|
conditions.push(or(eq(commercials.email, user?.username), ne(commercials.draft, true)));
|
||||||
}
|
}
|
||||||
conditions.push(sql`${commercials.id} = ${id}`);
|
conditions.push(sql`${commercials.id} = ${id}`);
|
||||||
|
|
@ -132,7 +132,7 @@ export class CommercialPropertyService {
|
||||||
async findCommercialPropertiesByEmail(email: string, user: JwtUser): Promise<CommercialPropertyListing[]> {
|
async findCommercialPropertiesByEmail(email: string, user: JwtUser): Promise<CommercialPropertyListing[]> {
|
||||||
const conditions = [];
|
const conditions = [];
|
||||||
conditions.push(eq(commercials.email, email));
|
conditions.push(eq(commercials.email, email));
|
||||||
if (email !== user?.username && (!user?.roles?.includes('ADMIN') ?? false)) {
|
if (email !== user?.username && (!user?.roles?.includes('ADMIN'))) {
|
||||||
conditions.push(ne(commercials.draft, true));
|
conditions.push(ne(commercials.draft, true));
|
||||||
}
|
}
|
||||||
const listings = (await this.conn
|
const listings = (await this.conn
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { BrokerListingsController } from './broker-listings.controller';
|
||||||
import { BusinessListingsController } from './business-listings.controller';
|
import { BusinessListingsController } from './business-listings.controller';
|
||||||
import { CommercialPropertyListingsController } from './commercial-property-listings.controller';
|
import { CommercialPropertyListingsController } from './commercial-property-listings.controller';
|
||||||
|
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { GeoModule } from '../geo/geo.module';
|
import { GeoModule } from '../geo/geo.module';
|
||||||
import { GeoService } from '../geo/geo.service';
|
import { GeoService } from '../geo/geo.service';
|
||||||
import { BusinessListingService } from './business-listing.service';
|
import { BusinessListingService } from './business-listing.service';
|
||||||
|
|
@ -14,7 +15,7 @@ import { CommercialPropertyService } from './commercial-property.service';
|
||||||
import { UnknownListingsController } from './unknown-listings.controller';
|
import { UnknownListingsController } from './unknown-listings.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DrizzleModule, AuthModule, GeoModule],
|
imports: [DrizzleModule, AuthModule, GeoModule,FirebaseAdminModule],
|
||||||
controllers: [BusinessListingsController, CommercialPropertyListingsController, UnknownListingsController, BrokerListingsController],
|
controllers: [BusinessListingsController, CommercialPropertyListingsController, UnknownListingsController, BrokerListingsController],
|
||||||
providers: [BusinessListingService, CommercialPropertyService, FileService, UserService, BusinessListingService, CommercialPropertyService, GeoService],
|
providers: [BusinessListingService, CommercialPropertyService, FileService, UserService, BusinessListingService, CommercialPropertyService, GeoService],
|
||||||
exports: [BusinessListingService, CommercialPropertyService],
|
exports: [BusinessListingService, CommercialPropertyService],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { LogController } from './log.controller';
|
import { LogController } from './log.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [FirebaseAdminModule],
|
||||||
controllers: [LogController],
|
controllers: [LogController],
|
||||||
})
|
})
|
||||||
export class LogModule {}
|
export class LogModule {}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { MailerModule } from '@nestjs-modules/mailer';
|
||||||
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
|
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { DrizzleModule } from '../drizzle/drizzle.module';
|
import { DrizzleModule } from '../drizzle/drizzle.module';
|
||||||
import { FileService } from '../file/file.service';
|
import { FileService } from '../file/file.service';
|
||||||
import { GeoModule } from '../geo/geo.module';
|
import { GeoModule } from '../geo/geo.module';
|
||||||
|
|
@ -18,6 +19,7 @@ import { MailService } from './mail.service';
|
||||||
DrizzleModule,
|
DrizzleModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
GeoModule,
|
GeoModule,
|
||||||
|
FirebaseAdminModule,
|
||||||
// ConfigModule.forFeature(mailConfig),
|
// ConfigModule.forFeature(mailConfig),
|
||||||
// MailerModule.forRoot({
|
// MailerModule.forRoot({
|
||||||
// transport: {
|
// transport: {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { LoggerService } from '@nestjs/common';
|
import { LoggerService } from '@nestjs/common';
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import bodyParser from 'body-parser';
|
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
|
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
|
@ -12,7 +11,7 @@ async function bootstrap() {
|
||||||
// const logger = app.get<Logger>(WINSTON_MODULE_NEST_PROVIDER);
|
// const logger = app.get<Logger>(WINSTON_MODULE_NEST_PROVIDER);
|
||||||
const logger = app.get<LoggerService>(WINSTON_MODULE_NEST_PROVIDER);
|
const logger = app.get<LoggerService>(WINSTON_MODULE_NEST_PROVIDER);
|
||||||
app.useLogger(logger);
|
app.useLogger(logger);
|
||||||
app.use('/bizmatch/payment/webhook', bodyParser.raw({ type: 'application/json' }));
|
//app.use('/bizmatch/payment/webhook', bodyParser.raw({ type: 'application/json' }));
|
||||||
app.setGlobalPrefix('bizmatch');
|
app.setGlobalPrefix('bizmatch');
|
||||||
|
|
||||||
app.enableCors({
|
app.enableCors({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { AuthModule } from '../auth/auth.module';
|
import { AuthModule } from '../auth/auth.module';
|
||||||
import { AuthService } from '../auth/auth.service';
|
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { DrizzleModule } from '../drizzle/drizzle.module';
|
import { DrizzleModule } from '../drizzle/drizzle.module';
|
||||||
import { FileService } from '../file/file.service';
|
import { FileService } from '../file/file.service';
|
||||||
import { GeoService } from '../geo/geo.service';
|
import { GeoService } from '../geo/geo.service';
|
||||||
|
|
@ -12,8 +13,8 @@ import { PaymentController } from './payment.controller';
|
||||||
import { PaymentService } from './payment.service';
|
import { PaymentService } from './payment.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DrizzleModule, UserModule, MailModule, AuthModule],
|
imports: [DrizzleModule, UserModule, MailModule, AuthModule,FirebaseAdminModule],
|
||||||
providers: [PaymentService, UserService, MailService, FileService, GeoService, AuthService],
|
providers: [PaymentService, UserService, MailService, FileService, GeoService],
|
||||||
controllers: [PaymentController],
|
controllers: [PaymentController],
|
||||||
})
|
})
|
||||||
export class PaymentModule {}
|
export class PaymentModule {}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver';
|
||||||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||||
import Stripe from 'stripe';
|
import Stripe from 'stripe';
|
||||||
import { Logger } from 'winston';
|
import { Logger } from 'winston';
|
||||||
import { AuthService } from '../auth/auth.service';
|
|
||||||
import * as schema from '../drizzle/schema';
|
import * as schema from '../drizzle/schema';
|
||||||
import { PG_CONNECTION } from '../drizzle/schema';
|
import { PG_CONNECTION } from '../drizzle/schema';
|
||||||
import { MailService } from '../mail/mail.service';
|
import { MailService } from '../mail/mail.service';
|
||||||
|
|
@ -22,7 +21,6 @@ export class PaymentService {
|
||||||
@Inject(PG_CONNECTION) private conn: NodePgDatabase<typeof schema>,
|
@Inject(PG_CONNECTION) private conn: NodePgDatabase<typeof schema>,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly mailService: MailService,
|
private readonly mailService: MailService,
|
||||||
private readonly authService: AuthService,
|
|
||||||
) {
|
) {
|
||||||
this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
||||||
apiVersion: '2024-06-20',
|
apiVersion: '2024-06-20',
|
||||||
|
|
@ -91,28 +89,28 @@ export class PaymentService {
|
||||||
return this.stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
|
return this.stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
|
||||||
}
|
}
|
||||||
async handleCheckoutSessionCompleted(session: Stripe.Checkout.Session): Promise<void> {
|
async handleCheckoutSessionCompleted(session: Stripe.Checkout.Session): Promise<void> {
|
||||||
try {
|
// try {
|
||||||
const keycloakUsers = await this.authService.getUsers();
|
// const keycloakUsers = await this.authService.getUsers();
|
||||||
const keycloakUser = keycloakUsers.find(u => u.email === session.customer_details.email);
|
// const keycloakUser = keycloakUsers.find(u => u.email === session.customer_details.email);
|
||||||
const user = await this.userService.getUserByMail(session.customer_details.email, {
|
// const user = await this.userService.getUserByMail(session.customer_details.email, {
|
||||||
userId: keycloakUser.id,
|
// userId: keycloakUser.id,
|
||||||
firstname: keycloakUser.firstName,
|
// firstname: keycloakUser.firstName,
|
||||||
lastname: keycloakUser.lastName,
|
// lastname: keycloakUser.lastName,
|
||||||
username: keycloakUser.email,
|
// username: keycloakUser.email,
|
||||||
roles: [],
|
// roles: [],
|
||||||
});
|
// });
|
||||||
user.subscriptionId = session.subscription as string;
|
// user.subscriptionId = session.subscription as string;
|
||||||
const subscription = await this.stripe.subscriptions.retrieve(user.subscriptionId);
|
// const subscription = await this.stripe.subscriptions.retrieve(user.subscriptionId);
|
||||||
user.customerType = 'professional';
|
// user.customerType = 'professional';
|
||||||
if (subscription.metadata['plan'] === 'Broker Plan') {
|
// if (subscription.metadata['plan'] === 'Broker Plan') {
|
||||||
user.customerSubType = 'broker';
|
// user.customerSubType = 'broker';
|
||||||
}
|
// }
|
||||||
user.subscriptionPlan = subscription.metadata['plan'] === 'Broker Plan' ? 'broker' : 'professional'; //session.metadata['subscriptionPlan'] as 'free' | 'professional' | 'broker';
|
// user.subscriptionPlan = subscription.metadata['plan'] === 'Broker Plan' ? 'broker' : 'professional'; //session.metadata['subscriptionPlan'] as 'free' | 'professional' | 'broker';
|
||||||
await this.userService.saveUser(user, false);
|
// await this.userService.saveUser(user, false);
|
||||||
await this.mailService.sendSubscriptionConfirmation(user);
|
// await this.mailService.sendSubscriptionConfirmation(user);
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
this.logger.error(error);
|
// this.logger.error(error);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
async getSubscription(email: string): Promise<Stripe.Subscription[]> {
|
async getSubscription(email: string): Promise<Stripe.Subscription[]> {
|
||||||
const existingCustomers = await this.stripe.customers.list({
|
const existingCustomers = await this.stripe.customers.list({
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FirebaseAdminModule } from '../firebase-admin/firebase-admin.module';
|
||||||
import { SelectOptionsController } from './select-options.controller';
|
import { SelectOptionsController } from './select-options.controller';
|
||||||
import { SelectOptionsService } from './select-options.service';
|
import { SelectOptionsService } from './select-options.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [FirebaseAdminModule],
|
||||||
controllers: [SelectOptionsController],
|
controllers: [SelectOptionsController],
|
||||||
providers: [SelectOptionsService],
|
providers: [SelectOptionsService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module';
|
||||||
import { DrizzleModule } from '../drizzle/drizzle.module';
|
import { DrizzleModule } from '../drizzle/drizzle.module';
|
||||||
import { FileService } from '../file/file.service';
|
import { FileService } from '../file/file.service';
|
||||||
import { GeoModule } from '../geo/geo.module';
|
import { GeoModule } from '../geo/geo.module';
|
||||||
|
|
@ -7,7 +8,7 @@ import { UserController } from './user.controller';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DrizzleModule, GeoModule],
|
imports: [DrizzleModule, GeoModule,FirebaseAdminModule],
|
||||||
controllers: [UserController],
|
controllers: [UserController],
|
||||||
providers: [UserService, FileService, GeoService],
|
providers: [UserService, FileService, GeoService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ export class DetailsBusinessListingComponent extends BaseDetailsComponent {
|
||||||
this.validationMessagesService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten
|
this.validationMessagesService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten
|
||||||
}
|
}
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
return isAdmin(this.keycloakUser.email); //this.keycloakService.getUserRoles(true).includes('ADMIN');
|
return isAdmin(this.keycloakUser?.email); //this.keycloakService.getUserRoles(true).includes('ADMIN');
|
||||||
}
|
}
|
||||||
async mail() {
|
async mail() {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ export class DetailsCommercialPropertyListingComponent extends BaseDetailsCompon
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
return isAdmin(this.keycloakUser.email);
|
return isAdmin(this.keycloakUser?.email);
|
||||||
}
|
}
|
||||||
async mail() {
|
async mail() {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}@else{
|
}@else{
|
||||||
<app-validated-select [disabled]="user.customerType === 'professional'" label="Customer Type" name="customerType" [(ngModel)]="user.customerType" [options]="customerTypeOptions"></app-validated-select>
|
<app-validated-select label="Customer Type" name="customerType" [(ngModel)]="user.customerType" [options]="customerTypeOptions"></app-validated-select>
|
||||||
} @if (isProfessional){
|
} @if (isProfessional){
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
<label for="customerSubType" class="block text-sm font-medium text-gray-700">Professional Type</label>
|
<label for="customerSubType" class="block text-sm font-medium text-gray-700">Professional Type</label>
|
||||||
|
|
@ -86,7 +86,7 @@
|
||||||
<option *ngFor="let subType of customerSubTypes" [value]="subType">{{ subType | titlecase }}</option>
|
<option *ngFor="let subType of customerSubTypes" [value]="subType">{{ subType | titlecase }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div> -->
|
</div> -->
|
||||||
<app-validated-select [disabled]="user.customerSubType === 'broker'" label="Professional Type" name="customerSubType" [(ngModel)]="user.customerSubType" [options]="customerSubTypeOptions"></app-validated-select>
|
<app-validated-select label="Professional Type" name="customerSubType" [(ngModel)]="user.customerSubType" [options]="customerSubTypeOptions"></app-validated-select>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@if (isProfessional){
|
@if (isProfessional){
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,32 @@ export class AuthService {
|
||||||
|
|
||||||
// Registrierung mit Email und Passwort
|
// Registrierung mit Email und Passwort
|
||||||
async registerWithEmail(email: string, password: string): Promise<UserCredential> {
|
async registerWithEmail(email: string, password: string): Promise<UserCredential> {
|
||||||
|
// Bestimmen der aktuellen Umgebung/Domain für die Verifizierungs-URL
|
||||||
|
let verificationUrl = '';
|
||||||
|
|
||||||
|
// Prüfen der aktuellen Umgebung basierend auf dem Host
|
||||||
|
const currentHost = window.location.hostname;
|
||||||
|
|
||||||
|
if (currentHost.includes('localhost')) {
|
||||||
|
verificationUrl = 'http://localhost:4200/email-authorized';
|
||||||
|
} else if (currentHost.includes('dev.bizmatch.net')) {
|
||||||
|
verificationUrl = 'https://dev.bizmatch.net/email-authorized';
|
||||||
|
} else {
|
||||||
|
verificationUrl = 'https://www.bizmatch.net/email-authorized';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionCode-Einstellungen mit der dynamischen URL
|
||||||
|
const actionCodeSettings = {
|
||||||
|
url: `${verificationUrl}?email=${email}`,
|
||||||
|
handleCodeInApp: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Benutzer erstellen
|
||||||
const userCredential = await createUserWithEmailAndPassword(this.auth, email, password);
|
const userCredential = await createUserWithEmailAndPassword(this.auth, email, password);
|
||||||
|
|
||||||
// E-Mail-Verifizierung senden
|
// E-Mail-Verifizierung mit den angepassten ActionCode-Einstellungen senden
|
||||||
if (userCredential.user) {
|
if (userCredential.user) {
|
||||||
await sendEmailVerification(userCredential.user);
|
await sendEmailVerification(userCredential.user, actionCodeSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token, RefreshToken und ggf. photoURL speichern
|
// Token, RefreshToken und ggf. photoURL speichern
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue