Umstellung auf nodeclassic

This commit is contained in:
2024-09-04 14:56:24 +02:00
parent c5577969c8
commit d8429f9b4a
47 changed files with 330 additions and 508 deletions

View File

@@ -1,5 +1,5 @@
import { Body, Controller, Post } from '@nestjs/common';
import { AiService } from './ai.service.js';
import { AiService } from './ai.service';
@Controller('ai')
export class AiController {

View File

@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { AiController } from './ai.controller.js';
import { AiService } from './ai.service.js';
import { AiController } from './ai.controller';
import { AiService } from './ai.service';
@Module({
controllers: [AiController],

View File

@@ -1,7 +1,7 @@
import { Controller, Get, Request, UseGuards } from '@nestjs/common';
import { AppService } from './app.service.js';
import { AuthService } from './auth/auth.service.js';
import { JwtAuthGuard } from './jwt-auth/jwt-auth.guard.js';
import { AppService } from './app.service';
import { AuthService } from './auth/auth.service';
import { JwtAuthGuard } from './jwt-auth/jwt-auth.guard';
@Controller()
export class AppController {

View File

@@ -5,22 +5,23 @@ import * as dotenv from 'dotenv';
import fs from 'fs-extra';
import { WinstonModule, utilities as nestWinstonModuleUtilities } from 'nest-winston';
import * as winston from 'winston';
import { AiModule } from './ai/ai.module.js';
import { AppController } from './app.controller.js';
import { AppService } from './app.service.js';
import { AuthModule } from './auth/auth.module.js';
import { FileService } from './file/file.service.js';
import { GeoModule } from './geo/geo.module.js';
import { ImageModule } from './image/image.module.js';
import { ListingsModule } from './listings/listings.module.js';
import { LogController } from './log/log.controller.js';
import { LogModule } from './log/log.module.js';
import { AiModule } from './ai/ai.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { FileService } from './file/file.service';
import { GeoModule } from './geo/geo.module';
import { ImageModule } from './image/image.module';
import { ListingsModule } from './listings/listings.module';
import { LogController } from './log/log.controller';
import { LogModule } from './log/log.module';
import { MailModule } from './mail/mail.module.js';
import { PaymentModule } from './payment/payment.module.js';
import { RequestDurationMiddleware } from './request-duration/request-duration.middleware.js';
import { SelectOptionsModule } from './select-options/select-options.module.js';
import { UserModule } from './user/user.module.js';
import { JwtStrategy } from './jwt.strategy';
import { MailModule } from './mail/mail.module';
import { PaymentModule } from './payment/payment.module';
import { RequestDurationMiddleware } from './request-duration/request-duration.middleware';
import { SelectOptionsModule } from './select-options/select-options.module';
import { UserModule } from './user/user.module';
// const __filename = fileURLToPath(import.meta.url);
// const __dirname = path.dirname(__filename);
@@ -86,7 +87,7 @@ loadEnvFiles();
PaymentModule,
],
controllers: [AppController, LogController],
providers: [AppService, FileService],
providers: [AppService, FileService, JwtStrategy],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {

View File

@@ -0,0 +1,30 @@
{
"keys": [
{
"kid": "0NxHr10meEVrGYmGlWz_WHiTPxbuNaU6vmShQYWFBh8",
"kty": "RSA",
"alg": "RSA-OAEP",
"use": "enc",
"n": "7hzWTnW6WOrZQmeZ26fD5Fu0NvxiQP8pVfesK9MXO4R1gjGlPViGWCdUKrG9Ux6h9X6SXHOWPWZmbfmjNeK7kQOjYPS_06GQ3X19tFikdWoufZMTpAb6p9CENsIbpzX9c1JZRs1xSJ9B505NjLVp29WzhugQfQR2ctv4nLZYmo1ojGjUQMGPNO_4bMqzO_luBQGEAqnRojZzxHVp-ruNyR9DmQbPbUULrOOXfGjCeAYukZ-5UHl6pngk8b6NKdGq6E_qxNsZVStWxbeGAG5UhxSl6oaGL8R0fP9JiAtlWfubJsCtibk712MaMb59JEdr_f3R3pXN7He8brS3smPgcQ",
"e": "AQAB",
"x5c": [
"MIIClTCCAX0CBgGN9oQZDTANBgkqhkiG9w0BAQsFADAOMQwwCgYDVQQDDANkZXYwHhcNMjQwMjI5MjAxNjA4WhcNMzQwMjI4MjAxNzQ4WjAOMQwwCgYDVQQDDANkZXYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDuHNZOdbpY6tlCZ5nbp8PkW7Q2/GJA/ylV96wr0xc7hHWCMaU9WIZYJ1Qqsb1THqH1fpJcc5Y9ZmZt+aM14ruRA6Ng9L/ToZDdfX20WKR1ai59kxOkBvqn0IQ2whunNf1zUllGzXFIn0HnTk2MtWnb1bOG6BB9BHZy2/ictliajWiMaNRAwY807/hsyrM7+W4FAYQCqdGiNnPEdWn6u43JH0OZBs9tRQus45d8aMJ4Bi6Rn7lQeXqmeCTxvo0p0aroT+rE2xlVK1bFt4YAblSHFKXqhoYvxHR8/0mIC2VZ+5smwK2JuTvXYxoxvn0kR2v9/dHelc3sd7xutLeyY+BxAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAL5CFk/T8Thoi6yNRg7CSiWuehCwwzC+FfsoVQNkcq2loZYgWjO34b9fXysT0xXLJOAnw0+xvwAhbVdBwTathQb2PJST5Ei6RGIOsT2gfE91Je3BGpXnsNNDja0be1bS/uN07aa3MshkgVBOYVDe2FoK7g4zSgViMXLEzGpRdio9mIrH3KADdEAFrhiNClu19gefONT86vUvIpSCS4XJ+nSUPbNkbhe9MlvZ8TRWFMoUzuZML6Xf+FbimAv1ZBk1NWobWPtyaDFF9Lgse7LHGiKPKvBHonVMbWYf7Lk8nGA7/90WVOX5Fd2LItH/13rPNlwbspAcz/nB2groa8/DrdE="
],
"x5t": "3ZyfzL7Gn0dcNq8H8X1L0uagQMI",
"x5t#S256": "Wwu30X3ZnchcXsJHJmOHT8BLOFCH6y2TpO3hyzojhdk"
},
{
"kid": "yAfIWlA3TFvR_h112X4sJHK0kog4_4xDLkRnJnzTv98",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"n": "xpYiq2XOtKV-xeLmFM-4sUWDpzw1UJlN9NXj833MZKsW_bwWixlsJTsB-2kfQ6mXUTbfxsuoZuWMZdQVpsWoKOPeK1Gsd8Gsoa0v2pv3uzPA8_SLqDrBNtIz9mDJc6jf-XkOdtAfPzW_aMf4TzThzIkEH5ptUde0gDKNd8je2lFo4loFJkLhOO2HZ7cLQcspXB_vNqpjAMED15GmGRizeTsA4IWC9WjGyziVvlbgQqC0MqCieT2r4dB0FZGWFwzlm-EhvyHu6G1Hw55jn5AcEHh5fke9XvTBzF6MmM_MQEDc9QWHj16ekVdQB7fxzBHbyLMr3ivQizcHAGYvemNhHw",
"e": "AQAB",
"x5c": [
"MIIClTCCAX0CBgGN9oQYYzANBgkqhkiG9w0BAQsFADAOMQwwCgYDVQQDDANkZXYwHhcNMjQwMjI5MjAxNjA4WhcNMzQwMjI4MjAxNzQ4WjAOMQwwCgYDVQQDDANkZXYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGliKrZc60pX7F4uYUz7ixRYOnPDVQmU301ePzfcxkqxb9vBaLGWwlOwH7aR9DqZdRNt/Gy6hm5Yxl1BWmxago494rUax3wayhrS/am/e7M8Dz9IuoOsE20jP2YMlzqN/5eQ520B8/Nb9ox/hPNOHMiQQfmm1R17SAMo13yN7aUWjiWgUmQuE47YdntwtByylcH+82qmMAwQPXkaYZGLN5OwDghYL1aMbLOJW+VuBCoLQyoKJ5Pavh0HQVkZYXDOWb4SG/Ie7obUfDnmOfkBwQeHl+R71e9MHMXoyYz8xAQNz1BYePXp6RV1AHt/HMEdvIsyveK9CLNwcAZi96Y2EfAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABQaqejZ5iWybWeiK0j9iKTn5DNr8LFXdJNRk+odI5TwCtaVDTCQRrF1KKT6F6RmzQyc6xyKojtnI1mKjs+Wo8vYE483pDgoGkv7UquKeQAWbXRajbkpGKasIux7m0MgDhPGKtxoha3kI2Yi2dOFYGdRuqv35/ZD+9nfHfk03fylrf5saroOYBGW6RRpdygB14zQ5ZbXin6gVJSBuJWMiWpxzAB05llZVaHOJ7kO+402YV2/l2TJm0bc883HZuIKxh11PI20lZop9ZwctVtmwf2iFfMfQgQ5wZpV/1gEMynVypxe6OY7biQyIERX6oEFWmZIOrnytSawLyy5gCFrStY="
],
"x5t": "L27m4VtyyHlrajDI_47_mmRSP08",
"x5t#S256": "KOcIpGLNb4ZGg_G2jc6ieZC_86-QQjoaSsMDoV0RWZg"
}
]
}

View File

@@ -1,6 +1,6 @@
import { Controller, Get, Param, UseGuards } from '@nestjs/common';
import { AdminAuthGuard } from '../jwt-auth/admin-auth.guard.js';
import { AuthService } from './auth.service.js';
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AdminAuthGuard } from '../jwt-auth/admin-auth.guard';
import { AuthService } from './auth.service';
@Controller('auth')
export class AuthController {
@@ -18,15 +18,15 @@ export class AuthController {
return this.authService.getUsers();
}
@UseGuards(AdminAuthGuard)
@Get('user/:userid')
getUser(@Param('userid') userId: string): any {
return this.authService.getUser(userId);
}
// @UseGuards(AdminAuthGuard)
// @Get('user/:userid')
// getUser(@Param('userid') userId: string): any {
// return this.authService.getUser(userId);
// }
@UseGuards(AdminAuthGuard)
@Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
getLastLogin(@Param('userid') userId: string): any {
return this.authService.getLastLogin(userId);
}
// @UseGuards(AdminAuthGuard)
// @Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
// getLastLogin(@Param('userid') userId: string): any {
// return this.authService.getLastLogin(userId);
// }
}

View File

@@ -1,12 +1,11 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from '../jwt.strategy.js';
import { AuthController } from './auth.controller.js';
import { AuthService } from './auth.service.js';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
@Module({
imports: [PassportModule],
providers: [AuthService, JwtStrategy],
providers: [AuthService],
controllers: [AuthController],
exports: [AuthService],
})

View File

@@ -1,7 +1,5 @@
import { Injectable } from '@nestjs/common';
import ky from 'ky';
import { KeycloakUser } from 'src/models/main.model';
import urlcat from 'urlcat';
@Injectable()
export class AuthService {
@@ -13,16 +11,19 @@ export class AuthService {
params.append('password', process.env.KEYCLOAK_ADMIN_PASSWORD);
const URL = `${process.env.KEYCLOAK_HOST}${process.env.KEYCLOAK_TOKEN_URL}`;
const response = await ky
.post(URL, {
body: params.toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: process.env.KEYCLOAK_ADMIN_TOKEN,
},
})
.json();
return (<any>response).access_token;
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();
@@ -36,43 +37,46 @@ export class AuthService {
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 ky
.get(URL, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Bearer ${token}`,
},
})
.json();
return response as KeycloakUser[];
}
public async getUser(userid: string) {
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 ky
.get(URL, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Bearer ${token}`,
},
})
.json();
return response;
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) {
// 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 ky
// .get(URL, {
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded',
// Authorization: `Bearer ${token}`,
// },
// })
// .json();
// return response;
// }
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;
}
// 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;
// }
}

View File

@@ -1,11 +1,10 @@
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { drizzle } from 'drizzle-orm/node-postgres';
import pkg from 'pg';
import * as schema from './schema';
import { PG_CONNECTION } from './schema';
const { Pool } = pkg;
import * as schema from './schema.js';
import { ConfigService } from '@nestjs/config';
import { jsonb, varchar } from 'drizzle-orm/pg-core';
import { PG_CONNECTION } from './schema.js';
@Module({
providers: [
{
@@ -18,7 +17,7 @@ import { PG_CONNECTION } from './schema.js';
// ssl: true,
});
return drizzle(pool, { schema, logger:true });
return drizzle(pool, { schema, logger: true });
},
},
],

View File

@@ -7,15 +7,15 @@ import { join } from 'path';
import pkg from 'pg';
import { rimraf } from 'rimraf';
import sharp from 'sharp';
import { BusinessListingService } from 'src/listings/business-listing.service.js';
import { CommercialPropertyService } from 'src/listings/commercial-property.service.js';
import { Geo } from 'src/models/server.model.js';
import { BusinessListingService } from 'src/listings/business-listing.service';
import { CommercialPropertyService } from 'src/listings/commercial-property.service';
import { Geo } from 'src/models/server.model';
import winston from 'winston';
import { User, UserData } from '../models/db.model.js';
import { createDefaultBusinessListing, createDefaultCommercialPropertyListing, createDefaultUser, emailToDirName, KeyValueStyle } from '../models/main.model.js';
import { SelectOptionsService } from '../select-options/select-options.service.js';
import { convertUserToDrizzleUser } from '../utils.js';
import * as schema from './schema.js';
import { User, UserData } from '../models/db.model';
import { createDefaultBusinessListing, createDefaultCommercialPropertyListing, createDefaultUser, emailToDirName, KeyValueStyle } from '../models/main.model';
import { SelectOptionsService } from '../select-options/select-options.service';
import { convertUserToDrizzleUser } from '../utils';
import * as schema from './schema';
interface PropertyImportListing {
id: string;
userId: string;

View File

@@ -1,7 +1,7 @@
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/node-postgres';
import pkg from 'pg';
import * as schema from './schema.js';
import * as schema from './schema';
const { Pool } = pkg;
const connectionString = process.env.DATABASE_URL;
const pool = new Pool({ connectionString });

View File

@@ -2,7 +2,7 @@ const fs = require('fs');
const path = require('path');
// Angenommen, du hast eine Datei `databaseModels.js` mit deinen pgTable-Definitionen
const { users } = require('./schema.js');
const { users } = require('./schema');
function generateTypeScriptInterface(tableDefinition, tableName) {
let interfaceString = `export interface ${tableName} {\n`;

View File

@@ -2,13 +2,10 @@ import { Inject, Injectable } from '@nestjs/common';
import { readFileSync } from 'fs';
import fs from 'fs-extra';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import path, { join } from 'path';
import { join } from 'path';
import sharp from 'sharp';
import { fileURLToPath } from 'url';
import { Logger } from 'winston';
import { ImageProperty, Subscription } from '../models/main.model.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import { ImageProperty, Subscription } from '../models/main.model';
@Injectable()
export class FileService {

View File

@@ -1,6 +1,6 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { CountyRequest } from 'src/models/server.model.js';
import { GeoService } from './geo.service.js';
import { CountyRequest } from 'src/models/server.model';
import { GeoService } from './geo.service';
@Controller('geo')
export class GeoController {

View File

@@ -1,9 +1,9 @@
import { Module } from '@nestjs/common';
import { GeoController } from './geo.controller.js';
import { GeoService } from './geo.service.js';
import { GeoController } from './geo.controller';
import { GeoService } from './geo.service';
@Module({
controllers: [GeoController],
providers: [GeoService]
providers: [GeoService],
})
export class GeoModule {}

View File

@@ -1,12 +1,11 @@
import { Injectable } from '@nestjs/common';
import { readFileSync } from 'fs';
import path, { join } from 'path';
import { CityAndStateResult, CountyResult, GeoResult } from 'src/models/main.model.js';
import { fileURLToPath } from 'url';
import { City, CountyData, Geo, State } from '../models/server.model.js';
import { join } from 'path';
import { CityAndStateResult, CountyResult, GeoResult } from 'src/models/main.model';
import { City, CountyData, Geo, State } from '../models/server.model';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// const __filename = fileURLToPath(import.meta.url);
// const __dirname = path.dirname(__filename);
@Injectable()
export class GeoService {
@@ -24,7 +23,7 @@ export class GeoService {
this.counties = JSON.parse(rawCountiesData);
}
findCountiesStartingWith(prefix: string, states?: string[]) {
let results: CountyResult[] = [];
const results: CountyResult[] = [];
let idCounter = 1;
this.counties.forEach(stateData => {

View File

@@ -2,9 +2,9 @@ import { Controller, Delete, Inject, Param, Post, UploadedFile, UseInterceptors
import { FileInterceptor } from '@nestjs/platform-express';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { FileService } from '../file/file.service.js';
import { CommercialPropertyService } from '../listings/commercial-property.service.js';
import { SelectOptionsService } from '../select-options/select-options.service.js';
import { FileService } from '../file/file.service';
import { CommercialPropertyService } from '../listings/commercial-property.service';
import { SelectOptionsService } from '../select-options/select-options.service';
@Controller('image')
export class ImageController {

View File

@@ -1,9 +1,9 @@
import { Module } from '@nestjs/common';
import { FileService } from '../file/file.service.js';
import { ListingsModule } from '../listings/listings.module.js';
import { SelectOptionsService } from '../select-options/select-options.service.js';
import { ImageController } from './image.controller.js';
import { ImageService } from './image.service.js';
import { FileService } from '../file/file.service';
import { ListingsModule } from '../listings/listings.module';
import { SelectOptionsService } from '../select-options/select-options.service';
import { ImageController } from './image.controller';
import { ImageService } from './image.service';
@Module({
imports: [ListingsModule],

View File

@@ -1,11 +1,17 @@
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(
@@ -13,22 +19,44 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
@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: true,
jwksRequestsPerMinute: 5,
rateLimit: false,
// jwksRequestsPerMinute: 5,
jwksUri: `https://auth.bizmatch.net/realms/${realm}/protocol/openid-connect/certs`,
}),
// cache: true, // Enable caching of validated tokens
// cacheTTL: 60 * 60 * 1000, // 1 hour cache TTL
// secretOrKeyProvider: (request, rawJwtToken, done) => {
// const start = Date.now();
// const decodedToken = jwt.decode(rawJwtToken, { complete: true });
// const kid = decodedToken?.header?.kid;
// if (pemCache.has(kid)) {
// this.logger.info(`Using cached PEM for kid ${kid}`);
// return done(null, pemCache.get(kid));
// }
// const key = staticCerts.keys.find(k => k.kid === kid);
// if (!key) {
// this.logger.error(`No matching key found for kid: ${kid}`);
// return done(new Error('No matching key found'), null);
// }
// const publicKey = jwkToPem(key);
// pemCache.set(kid, publicKey);
// done(null, publicKey);
// this.logger.info(`Total JWT verification time: ${Date.now() - start}ms`);
// },
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');
@@ -43,3 +71,8 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
return result;
}
}
export function loadStaticCerts() {
const certsPath = path.join(__dirname, '../', 'assets', 'keycloak-certs.json');
const certsData = fs.readFileSync(certsPath, 'utf8');
return JSON.parse(certsData);
}

View File

@@ -1,8 +1,8 @@
import { Body, Controller, Inject, Post } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { UserListingCriteria } from 'src/models/main.model.js';
import { UserListingCriteria } from 'src/models/main.model';
import { Logger } from 'winston';
import { UserService } from '../user/user.service.js';
import { UserService } from '../user/user.service';
@Controller('listings/professionals_brokers')
export class BrokerListingsController {

View File

@@ -4,13 +4,13 @@ import { NodePgDatabase } from 'drizzle-orm/node-postgres';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { ZodError } from 'zod';
import * as schema from '../drizzle/schema.js';
import { businesses, PG_CONNECTION } from '../drizzle/schema.js';
import { FileService } from '../file/file.service.js';
import { GeoService } from '../geo/geo.service.js';
import { BusinessListing, BusinessListingSchema } from '../models/db.model.js';
import { BusinessListingCriteria, emailToDirName, JwtUser } from '../models/main.model.js';
import { convertBusinessToDrizzleBusiness, convertDrizzleBusinessToBusiness, getDistanceQuery, splitName } from '../utils.js';
import * as schema from '../drizzle/schema';
import { businesses, PG_CONNECTION } from '../drizzle/schema';
import { FileService } from '../file/file.service';
import { GeoService } from '../geo/geo.service';
import { BusinessListing, BusinessListingSchema } from '../models/db.model';
import { BusinessListingCriteria, JwtUser } from '../models/main.model';
import { convertBusinessToDrizzleBusiness, convertDrizzleBusinessToBusiness, getDistanceQuery, splitName } from '../utils';
@Injectable()
export class BusinessListingService {
@@ -162,7 +162,7 @@ export class BusinessListingService {
conditions.push(or(eq(businesses.email, user?.username), ne(businesses.draft, true)));
}
conditions.push(sql`${businesses.id} = ${id}`);
let result = await this.conn
const result = await this.conn
.select()
.from(businesses)
.where(and(...conditions));
@@ -175,7 +175,7 @@ export class BusinessListingService {
async findBusinessesByEmail(email: string, user: JwtUser): Promise<BusinessListing[]> {
const conditions = [];
conditions.push(eq(businesses.imageName, emailToDirName(email)));
conditions.push(eq(businesses.email, email));
if (email !== user?.username && (!user?.roles?.includes('ADMIN') ?? false)) {
conditions.push(ne(businesses.draft, true));
}
@@ -199,7 +199,7 @@ export class BusinessListingService {
try {
data.created = data.created ? (typeof data.created === 'string' ? new Date(data.created) : data.created) : new Date();
data.updated = new Date();
const validatedBusinessListing = BusinessListingSchema.parse(data);
BusinessListingSchema.parse(data);
const convertedBusinessListing = convertBusinessToDrizzleBusiness(data);
delete convertedBusinessListing.id;
const [createdListing] = await this.conn.insert(businesses).values(convertedBusinessListing).returning();
@@ -222,7 +222,7 @@ export class BusinessListingService {
try {
data.updated = new Date();
data.created = data.created ? (typeof data.created === 'string' ? new Date(data.created) : data.created) : new Date();
const validatedBusinessListing = BusinessListingSchema.parse(data);
BusinessListingSchema.parse(data);
const convertedBusinessListing = convertBusinessToDrizzleBusiness(data);
const [updateListing] = await this.conn.update(businesses).set(convertedBusinessListing).where(eq(businesses.id, id)).returning();
return convertDrizzleBusinessToBusiness(updateListing);

View File

@@ -1,11 +1,11 @@
import { Body, Controller, Delete, Get, Inject, Param, Post, Put, Request, UseGuards } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard.js';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
import { BusinessListing } from '../models/db.model.js';
import { BusinessListingCriteria, JwtUser } from '../models/main.model.js';
import { BusinessListingService } from './business-listing.service.js';
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard';
import { BusinessListing } from '../models/db.model';
import { BusinessListingCriteria, JwtUser } from '../models/main.model';
import { BusinessListingService } from './business-listing.service';
@Controller('listings/business')
export class BusinessListingsController {

View File

@@ -1,12 +1,12 @@
import { Body, Controller, Delete, Get, Inject, Param, Post, Put, Request, UseGuards } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { FileService } from '../file/file.service.js';
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard.js';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
import { FileService } from '../file/file.service';
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard';
import { CommercialPropertyListing } from '../models/db.model';
import { CommercialPropertyListingCriteria, JwtUser } from '../models/main.model.js';
import { CommercialPropertyService } from './commercial-property.service.js';
import { CommercialPropertyListingCriteria, JwtUser } from '../models/main.model';
import { CommercialPropertyService } from './commercial-property.service';
@Controller('listings/commercialProperty')
export class CommercialPropertyListingsController {

View File

@@ -4,13 +4,13 @@ import { NodePgDatabase } from 'drizzle-orm/node-postgres';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { ZodError } from 'zod';
import * as schema from '../drizzle/schema.js';
import { commercials, PG_CONNECTION } from '../drizzle/schema.js';
import { FileService } from '../file/file.service.js';
import { GeoService } from '../geo/geo.service.js';
import { CommercialPropertyListing, CommercialPropertyListingSchema } from '../models/db.model.js';
import { CommercialPropertyListingCriteria, emailToDirName, JwtUser } from '../models/main.model.js';
import { convertCommercialToDrizzleCommercial, convertDrizzleBusinessToBusiness, convertDrizzleCommercialToCommercial, getDistanceQuery } from '../utils.js';
import * as schema from '../drizzle/schema';
import { commercials, PG_CONNECTION } from '../drizzle/schema';
import { FileService } from '../file/file.service';
import { GeoService } from '../geo/geo.service';
import { CommercialPropertyListing, CommercialPropertyListingSchema } from '../models/db.model';
import { CommercialPropertyListingCriteria, JwtUser } from '../models/main.model';
import { convertCommercialToDrizzleCommercial, convertDrizzleBusinessToBusiness, convertDrizzleCommercialToCommercial, getDistanceQuery } from '../utils';
@Injectable()
export class CommercialPropertyService {
@@ -99,7 +99,7 @@ export class CommercialPropertyService {
conditions.push(or(eq(commercials.email, user?.username), ne(commercials.draft, true)));
}
conditions.push(sql`${commercials.id} = ${id}`);
let result = await this.conn
const result = await this.conn
.select()
.from(commercials)
.where(and(...conditions));
@@ -113,7 +113,7 @@ export class CommercialPropertyService {
// #### Find by User EMail ########################################
async findCommercialPropertiesByEmail(email: string, user: JwtUser): Promise<CommercialPropertyListing[]> {
const conditions = [];
conditions.push(eq(commercials.imagePath, emailToDirName(email)));
conditions.push(eq(commercials.email, email));
if (email !== user?.username && (!user?.roles?.includes('ADMIN') ?? false)) {
conditions.push(ne(commercials.draft, true));
}
@@ -144,7 +144,7 @@ export class CommercialPropertyService {
try {
data.created = data.created ? (typeof data.created === 'string' ? new Date(data.created) : data.created) : new Date();
data.updated = new Date();
const validatedCommercialPropertyListing = CommercialPropertyListingSchema.parse(data);
CommercialPropertyListingSchema.parse(data);
const convertedCommercialPropertyListing = convertCommercialToDrizzleCommercial(data);
delete convertedCommercialPropertyListing.id;
const [createdListing] = await this.conn.insert(commercials).values(convertedCommercialPropertyListing).returning();
@@ -167,9 +167,9 @@ export class CommercialPropertyService {
try {
data.updated = new Date();
data.created = data.created ? (typeof data.created === 'string' ? new Date(data.created) : data.created) : new Date();
const validatedCommercialPropertyListing = CommercialPropertyListingSchema.parse(data);
CommercialPropertyListingSchema.parse(data);
const imageOrder = await this.fileService.getPropertyImages(data.imagePath, String(data.serialId));
let difference = imageOrder.filter(x => !data.imageOrder.includes(x)).concat(data.imageOrder.filter(x => !imageOrder.includes(x)));
const difference = imageOrder.filter(x => !data.imageOrder.includes(x)).concat(data.imageOrder.filter(x => !imageOrder.includes(x)));
if (difference.length > 0) {
this.logger.warn(`changes between image directory and imageOrder in listing ${data.serialId}: ${difference.join(',')}`);
data.imageOrder = imageOrder;

View File

@@ -1,17 +1,17 @@
import { Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module.js';
import { DrizzleModule } from '../drizzle/drizzle.module.js';
import { FileService } from '../file/file.service.js';
import { UserService } from '../user/user.service.js';
import { BrokerListingsController } from './broker-listings.controller.js';
import { BusinessListingsController } from './business-listings.controller.js';
import { CommercialPropertyListingsController } from './commercial-property-listings.controller.js';
import { AuthModule } from '../auth/auth.module';
import { DrizzleModule } from '../drizzle/drizzle.module';
import { FileService } from '../file/file.service';
import { UserService } from '../user/user.service';
import { BrokerListingsController } from './broker-listings.controller';
import { BusinessListingsController } from './business-listings.controller';
import { CommercialPropertyListingsController } from './commercial-property-listings.controller';
import { GeoModule } from '../geo/geo.module.js';
import { GeoService } from '../geo/geo.service.js';
import { BusinessListingService } from './business-listing.service.js';
import { CommercialPropertyService } from './commercial-property.service.js';
import { UnknownListingsController } from './unknown-listings.controller.js';
import { GeoModule } from '../geo/geo.module';
import { GeoService } from '../geo/geo.service';
import { BusinessListingService } from './business-listing.service';
import { CommercialPropertyService } from './commercial-property.service';
import { UnknownListingsController } from './unknown-listings.controller';
@Module({
imports: [DrizzleModule, AuthModule, GeoModule],

View File

@@ -1,9 +1,9 @@
import { Controller, Get, Inject, Param, Request, UseGuards } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
import { BusinessListingService } from './business-listing.service.js';
import { CommercialPropertyService } from './commercial-property.service.js';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard';
import { BusinessListingService } from './business-listing.service';
import { CommercialPropertyService } from './commercial-property.service';
@Controller('listings/undefined')
export class UnknownListingsController {

View File

@@ -1,8 +1,8 @@
import { Body, Controller, Inject, Post, Request, UseGuards } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
import { LogMessage } from '../models/main.model.js';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard';
import { LogMessage } from '../models/main.model';
@Controller('log')
export class LogController {
constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) {}

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { LogController } from './log.controller.js';
import { LogController } from './log.controller';
@Module({
controllers: [LogController],

View File

@@ -1,7 +1,7 @@
import { Body, Controller, Post } from '@nestjs/common';
import { ShareByEMail, User } from 'src/models/db.model';
import { ErrorResponse, MailInfo } from '../models/main.model';
import { MailService } from './mail.service.js';
import { MailService } from './mail.service';
@Controller('mail')
export class MailController {

View File

@@ -1,22 +1,18 @@
import { MailerModule } from '@nestjs-modules/mailer';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter.js';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { Module } from '@nestjs/common';
import path, { join } from 'path';
import { fileURLToPath } from 'url';
import { DrizzleModule } from '../drizzle/drizzle.module.js';
import { FileService } from '../file/file.service.js';
import { GeoModule } from '../geo/geo.module.js';
import { GeoService } from '../geo/geo.service.js';
import { UserModule } from '../user/user.module.js';
import { UserService } from '../user/user.service.js';
import { MailController } from './mail.controller.js';
import { MailService } from './mail.service.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const user = process.env.AMAZON_USER;
const password = process.env.AMAZON_PASSWORD;
console.log('Amazon User:', process.env.AMAZON_USER);
console.log('Amazon Password:', process.env.AMAZON_PASSWORD);
import { join } from 'path';
import { DrizzleModule } from '../drizzle/drizzle.module';
import { FileService } from '../file/file.service';
import { GeoModule } from '../geo/geo.module';
import { GeoService } from '../geo/geo.service';
import { UserModule } from '../user/user.module';
import { UserService } from '../user/user.service';
import { MailController } from './mail.controller';
import { MailService } from './mail.service';
// const __filename = fileURLToPath(import.meta.url);
// const __dirname = path.dirname(__filename);
@Module({
imports: [
DrizzleModule,

View File

@@ -1,13 +1,12 @@
import { MailerService } from '@nestjs-modules/mailer';
import { BadRequestException, Injectable } from '@nestjs/common';
import path, { join } from 'path';
import { fileURLToPath } from 'url';
import { join } from 'path';
import { ZodError } from 'zod';
import { SenderSchema, ShareByEMail, ShareByEMailSchema, User } from '../models/db.model.js';
import { ErrorResponse, MailInfo, isEmpty } from '../models/main.model.js';
import { UserService } from '../user/user.service.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import { SenderSchema, ShareByEMail, ShareByEMailSchema, User } from '../models/db.model';
import { ErrorResponse, MailInfo, isEmpty } from '../models/main.model';
import { UserService } from '../user/user.service';
// const __filename = fileURLToPath(import.meta.url);
// const __dirname = path.dirname(__filename);
@Injectable()
export class MailService {

View File

@@ -1,10 +1,10 @@
import { NestFactory } from '@nestjs/core';
import bodyParser from 'body-parser';
import express from 'express';
import { AppModule } from './app.module.js';
import { AppModule } from './app.module';
async function bootstrap() {
const server = express();
express();
const app = await NestFactory.create(AppModule);
app.use('/bizmatch/payment/webhook', bodyParser.raw({ type: 'application/json' }));
app.setGlobalPrefix('bizmatch');

View File

@@ -1,6 +1,6 @@
import Stripe from 'stripe';
import { BusinessListing, CommercialPropertyListing, Sender, User } from './db.model.js';
import { State } from './server.model.js';
import { BusinessListing, CommercialPropertyListing, Sender, User } from './db.model';
import { State } from './server.model';
export interface StatesResult {
state: string;

View File

@@ -1,8 +1,8 @@
import { Body, Controller, Get, HttpException, HttpStatus, Param, Post, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';
import { Checkout } from 'src/models/main.model.js';
import { Checkout } from 'src/models/main.model';
import Stripe from 'stripe';
import { PaymentService } from './payment.service.js';
import { PaymentService } from './payment.service';
@Controller('payment')
export class PaymentController {

View File

@@ -1,15 +1,15 @@
import { Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module.js';
import { AuthService } from '../auth/auth.service.js';
import { DrizzleModule } from '../drizzle/drizzle.module.js';
import { FileService } from '../file/file.service.js';
import { GeoService } from '../geo/geo.service.js';
import { MailModule } from '../mail/mail.module.js';
import { MailService } from '../mail/mail.service.js';
import { UserModule } from '../user/user.module.js';
import { UserService } from '../user/user.service.js';
import { PaymentController } from './payment.controller.js';
import { PaymentService } from './payment.service.js';
import { AuthModule } from '../auth/auth.module';
import { AuthService } from '../auth/auth.service';
import { DrizzleModule } from '../drizzle/drizzle.module';
import { FileService } from '../file/file.service';
import { GeoService } from '../geo/geo.service';
import { MailModule } from '../mail/mail.module';
import { MailService } from '../mail/mail.service';
import { UserModule } from '../user/user.module';
import { UserService } from '../user/user.service';
import { PaymentController } from './payment.controller';
import { PaymentService } from './payment.service';
@Module({
imports: [DrizzleModule, UserModule, MailModule, AuthModule],

View File

@@ -1,14 +1,14 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver.js';
import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import Stripe from 'stripe';
import { Logger } from 'winston';
import { AuthService } from '../auth/auth.service.js';
import * as schema from '../drizzle/schema.js';
import { PG_CONNECTION } from '../drizzle/schema.js';
import { MailService } from '../mail/mail.service.js';
import { Checkout } from '../models/main.model.js';
import { UserService } from '../user/user.service.js';
import { AuthService } from '../auth/auth.service';
import * as schema from '../drizzle/schema';
import { PG_CONNECTION } from '../drizzle/schema';
import { MailService } from '../mail/mail.service';
import { Checkout } from '../models/main.model';
import { UserService } from '../user/user.service';
export interface BillingAddress {
country: string;
state: string;

View File

@@ -1,5 +1,5 @@
import { Controller, Get } from '@nestjs/common';
import { SelectOptionsService } from './select-options.service.js';
import { SelectOptionsService } from './select-options.service';
@Controller('select-options')
export class SelectOptionsController {

View File

@@ -1,9 +1,9 @@
import { Module } from '@nestjs/common';
import { SelectOptionsController } from './select-options.controller.js';
import { SelectOptionsService } from './select-options.service.js';
import { SelectOptionsController } from './select-options.controller';
import { SelectOptionsService } from './select-options.service';
@Module({
controllers: [SelectOptionsController],
providers: [SelectOptionsService]
})
controllers: [SelectOptionsController],
providers: [SelectOptionsService],
})
export class SelectOptionsModule {}

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import { ImageType, KeyValue, KeyValueStyle } from '../models/main.model.js';
import { ImageType, KeyValue, KeyValueStyle } from '../models/main.model';
@Injectable()
export class SelectOptionsService {

View File

@@ -2,12 +2,12 @@ import { BadRequestException, Body, Controller, Get, Inject, Param, Post, Query,
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { ZodError } from 'zod';
import { FileService } from '../file/file.service.js';
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard.js';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard.js';
import { FileService } from '../file/file.service';
import { JwtAuthGuard } from '../jwt-auth/jwt-auth.guard';
import { OptionalJwtAuthGuard } from '../jwt-auth/optional-jwt-auth.guard';
import { User } from '../models/db.model';
import { JwtUser, Subscription, UserListingCriteria } from '../models/main.model.js';
import { UserService } from './user.service.js';
import { JwtUser, Subscription, UserListingCriteria } from '../models/main.model';
import { UserService } from './user.service';
@Controller('user')
export class UserController {

View File

@@ -1,10 +1,10 @@
import { Module } from '@nestjs/common';
import { DrizzleModule } from '../drizzle/drizzle.module.js';
import { FileService } from '../file/file.service.js';
import { GeoModule } from '../geo/geo.module.js';
import { GeoService } from '../geo/geo.service.js';
import { UserController } from './user.controller.js';
import { UserService } from './user.service.js';
import { DrizzleModule } from '../drizzle/drizzle.module';
import { FileService } from '../file/file.service';
import { GeoModule } from '../geo/geo.module';
import { GeoService } from '../geo/geo.service';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
imports: [DrizzleModule, GeoModule],

View File

@@ -1,15 +1,15 @@
import { Inject, Injectable } from '@nestjs/common';
import { and, count, eq, ilike, inArray, or, SQL, sql } from 'drizzle-orm';
import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver.js';
import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import * as schema from '../drizzle/schema.js';
import { customerSubTypeEnum, PG_CONNECTION } from '../drizzle/schema.js';
import { FileService } from '../file/file.service.js';
import { GeoService } from '../geo/geo.service.js';
import { User, UserSchema } from '../models/db.model.js';
import { createDefaultUser, emailToDirName, JwtUser, UserListingCriteria } from '../models/main.model.js';
import { convertDrizzleUserToUser, convertUserToDrizzleUser, getDistanceQuery, splitName } from '../utils.js';
import * as schema from '../drizzle/schema';
import { customerSubTypeEnum, PG_CONNECTION } from '../drizzle/schema';
import { FileService } from '../file/file.service';
import { GeoService } from '../geo/geo.service';
import { User, UserSchema } from '../models/db.model';
import { createDefaultUser, emailToDirName, JwtUser, UserListingCriteria } from '../models/main.model';
import { convertDrizzleUserToUser, convertUserToDrizzleUser, getDistanceQuery, splitName } from '../utils';
type CustomerSubType = (typeof customerSubTypeEnum.enumValues)[number];
@Injectable()

View File

@@ -1,6 +1,6 @@
import { sql } from 'drizzle-orm';
import { businesses, commercials, users } from './drizzle/schema.js';
import { BusinessListing, CommercialPropertyListing, User } from './models/db.model.js';
import { businesses, commercials, users } from './drizzle/schema';
import { BusinessListing, CommercialPropertyListing, User } from './models/db.model';
export const EARTH_RADIUS_KM = 6371; // Erdradius in Kilometern
export const EARTH_RADIUS_MILES = 3959; // Erdradius in Meilen
export function convertStringToNullUndefined(value) {