diff --git a/bizmatch-server/.env.development b/bizmatch-server/.env.development deleted file mode 100644 index f254a52..0000000 --- a/bizmatch-server/.env.development +++ /dev/null @@ -1,4 +0,0 @@ -REALM=bizmatch-dev -usersURL=/admin/realms/bizmatch-dev/users -WEB_HOST=https://dev.bizmatch.net -STRIPE_WEBHOOK_SECRET=whsec_w2yvJY8qFMfO5wJgyNHCn6oYT7o2J5pS \ No newline at end of file diff --git a/bizmatch-server/.env.production b/bizmatch-server/.env.production deleted file mode 100644 index 79289c2..0000000 --- a/bizmatch-server/.env.production +++ /dev/null @@ -1,2 +0,0 @@ -REALM=bizmatch -WEB_HOST=https://www.bizmatch.net \ No newline at end of file diff --git a/bizmatch-server/Dockerfile b/bizmatch-server/Dockerfile new file mode 100644 index 0000000..985a1d3 --- /dev/null +++ b/bizmatch-server/Dockerfile @@ -0,0 +1,19 @@ +# Build Stage +FROM node:18-alpine AS build + +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +# Runtime Stage +FROM node:18-alpine + +WORKDIR /app +COPY --from=build /app/dist /app/dist +COPY --from=build /app/package*.json /app/ + +RUN npm install --production + +CMD ["node", "dist/main.js"] \ No newline at end of file diff --git a/bizmatch-server/drizzle.config.ts b/bizmatch-server/drizzle.config.ts index 46b9f86..f1b3dbb 100644 --- a/bizmatch-server/drizzle.config.ts +++ b/bizmatch-server/drizzle.config.ts @@ -3,7 +3,6 @@ export default defineConfig({ schema: './src/drizzle/schema.ts', out: './src/drizzle/migrations', dialect: 'postgresql', - // driver: 'pg', dbCredentials: { url: process.env.DATABASE_URL, }, diff --git a/bizmatch-server/src/drizzle/schema.ts b/bizmatch-server/src/drizzle/schema.ts index 8256179..54f877f 100644 --- a/bizmatch-server/src/drizzle/schema.ts +++ b/bizmatch-server/src/drizzle/schema.ts @@ -34,10 +34,6 @@ export const users = pgTable( subscriptionPlan: subscriptionTypeEnum('subscriptionPlan'), location: jsonb('location'), showInDirectory: boolean('showInDirectory').default(true), - // city: varchar('city', { length: 255 }), - // state: char('state', { length: 2 }), - // latitude: doublePrecision('latitude'), - // longitude: doublePrecision('longitude'), }, table => ({ locationUserCityStateIdx: index('idx_user_location_city_state').on( @@ -98,14 +94,6 @@ export const commercials = pgTable( created: timestamp('created'), updated: timestamp('updated'), location: jsonb('location'), - // city: varchar('city', { length: 255 }), - // state: char('state', { length: 2 }), - // zipCode: integer('zipCode'), - // county: varchar('county', { length: 255 }), - // street: varchar('street', { length: 255 }), - // housenumber: varchar('housenumber', { length: 10 }), - // latitude: doublePrecision('latitude'), - // longitude: doublePrecision('longitude'), }, table => ({ locationCommercialsCityStateIdx: index('idx_commercials_location_city_state').on( @@ -113,18 +101,7 @@ export const commercials = pgTable( ), }), ); -// export const geo = pgTable('geo', { -// id: uuid('id').primaryKey().defaultRandom().notNull(), -// country: varchar('country', { length: 255 }).default('us'), -// state: char('state', { length: 2 }), -// city: varchar('city', { length: 255 }), -// zipCode: integer('zipCode'), -// county: varchar('county', { length: 255 }), -// street: varchar('street', { length: 255 }), -// housenumber: varchar('housenumber', { length: 10 }), -// latitude: doublePrecision('latitude'), -// longitude: doublePrecision('longitude'), -// }); + export const listingEvents = pgTable('listing_events', { id: uuid('id').primaryKey().defaultRandom().notNull(), listingId: varchar('listing_id', { length: 255 }), // Assuming listings are referenced by UUID, adjust as necessary diff --git a/bizmatch-server/src/payment/payment.controller.ts b/bizmatch-server/src/payment/payment.controller.ts deleted file mode 100644 index f3486b4..0000000 --- a/bizmatch-server/src/payment/payment.controller.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Body, Controller, Get, HttpException, HttpStatus, Param, Post, Req, Res, UseGuards } from '@nestjs/common'; -import { Request, Response } from 'express'; -import { OptionalAuthGuard } from 'src/jwt-auth/optional-auth.guard'; -import { Checkout } from 'src/models/main.model'; -import Stripe from 'stripe'; -import { PaymentService } from './payment.service'; - -@Controller('payment') -export class PaymentController { - constructor(private readonly paymentService: PaymentService) {} - - // @Post() - // async createSubscription(@Body() subscriptionData: any) { - // return this.paymentService.createSubscription(subscriptionData); - // } - - // @UseGuards(AdminAuthGuard) - // @Get('user/all') - // async getAllStripeCustomer(): Promise { - // return await this.paymentService.getAllStripeCustomer(); - // } - - // @UseGuards(AdminAuthGuard) - // @Get('subscription/all') - // async getAllStripeSubscriptions(): Promise { - // return await this.paymentService.getAllStripeSubscriptions(); - // } - - // @UseGuards(AdminAuthGuard) - // @Get('paymentmethod/:email') - // async getStripePaymentMethods(@Param('email') email: string): Promise { - // return await this.paymentService.getStripePaymentMethod(email); - // } - - @UseGuards(OptionalAuthGuard) - @Post('create-checkout-session') - async createCheckoutSession(@Body() checkout: Checkout) { - return await this.paymentService.createCheckoutSession(checkout); - } - @Post('webhook') - async handleWebhook(@Req() req: Request, @Res() res: Response): Promise { - const signature = req.headers['stripe-signature'] as string; - - try { - // Konvertieren Sie den req.body Buffer in einen lesbaren String - const payload = req.body instanceof Buffer ? req.body.toString('utf8') : req.body; - const event = await this.paymentService.constructEvent(payload, signature); - // const event = await this.paymentService.constructEvent(req.body, signature); - - if (event.type === 'checkout.session.completed') { - await this.paymentService.handleCheckoutSessionCompleted(event.data.object as Stripe.Checkout.Session); - } - - res.status(200).send('Webhook received'); - } catch (error) { - console.error(`Webhook Error: ${error.message}`); - throw new HttpException('Webhook Error', HttpStatus.BAD_REQUEST); - } - } - - @UseGuards(OptionalAuthGuard) - @Get('subscriptions/:email') - async findSubscriptionsById(@Param('email') email: string): Promise { - return await this.paymentService.getSubscription(email); - } - /** - * Endpoint zum Löschen eines Stripe-Kunden. - * Beispiel: DELETE /stripe/customer/cus_12345 - */ - // @UseGuards(AdminAuthGuard) - // @Delete('customer/:id') - // @HttpCode(HttpStatus.NO_CONTENT) - // async deleteCustomer(@Param('id') customerId: string): Promise { - // await this.paymentService.deleteCustomerCompletely(customerId); - // } -} diff --git a/bizmatch-server/src/payment/payment.module.ts b/bizmatch-server/src/payment/payment.module.ts deleted file mode 100644 index 2239ea7..0000000 --- a/bizmatch-server/src/payment/payment.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Module } from '@nestjs/common'; -import { AuthModule } from '../auth/auth.module'; - -import { FirebaseAdminModule } from 'src/firebase-admin/firebase-admin.module'; -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,FirebaseAdminModule], - providers: [PaymentService, UserService, MailService, FileService, GeoService], - controllers: [PaymentController], -}) -export class PaymentModule {} diff --git a/bizmatch-server/src/payment/payment.service.ts b/bizmatch-server/src/payment/payment.service.ts deleted file mode 100644 index d626556..0000000 --- a/bizmatch-server/src/payment/payment.service.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { BadRequestException, Inject, Injectable, InternalServerErrorException } from '@nestjs/common'; -import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver'; -import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; -import Stripe from 'stripe'; -import { Logger } from 'winston'; -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; -} -@Injectable() -export class PaymentService { - private stripe: Stripe; - - constructor( - @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, - @Inject(PG_CONNECTION) private conn: NodePgDatabase, - private readonly userService: UserService, - private readonly mailService: MailService, - ) { - this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { - apiVersion: '2024-06-20', - }); - } - async createCheckoutSession(checkout: Checkout) { - try { - let customerId; - const existingCustomers = await this.stripe.customers.list({ - email: checkout.email, - limit: 1, - }); - if (existingCustomers.data.length > 0) { - // Kunde existiert - customerId = existingCustomers.data[0].id; - } else { - // Kunde existiert nicht, neuen Kunden erstellen - const newCustomer = await this.stripe.customers.create({ - email: checkout.email, - name: checkout.name, - shipping: { - name: checkout.name, - address: { - city: '', - state: '', - country: 'US', - }, - }, - }); - customerId = newCustomer.id; - } - const price = await this.stripe.prices.retrieve(checkout.priceId); - if (price.product) { - const product = await this.stripe.products.retrieve(price.product as string); - const session = await this.stripe.checkout.sessions.create({ - mode: 'subscription', - payment_method_types: ['card'], - line_items: [ - { - price: checkout.priceId, - quantity: 1, - }, - ], - success_url: `${process.env.WEB_HOST}/success`, - cancel_url: `${process.env.WEB_HOST}/pricing`, - customer: customerId, - shipping_address_collection: { - allowed_countries: ['US'], - }, - client_reference_id: btoa(checkout.name), - locale: 'en', - subscription_data: { - trial_end: Math.floor(new Date().setMonth(new Date().getMonth() + 3) / 1000), - metadata: { plan: product.name }, - }, - }); - return session; - } else { - return null; - } - } catch (e) { - throw new BadRequestException(`error during checkout: ${e}`); - } - } - async constructEvent(body: string | Buffer, signature: string) { - return this.stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!); - } - async handleCheckoutSessionCompleted(session: Stripe.Checkout.Session): Promise { - // try { - // const keycloakUsers = await this.authService.getUsers(); - // const keycloakUser = keycloakUsers.find(u => u.email === session.customer_details.email); - // const user = await this.userService.getUserByMail(session.customer_details.email, { - // userId: keycloakUser.id, - // firstname: keycloakUser.firstName, - // lastname: keycloakUser.lastName, - // username: keycloakUser.email, - // roles: [], - // }); - // user.subscriptionId = session.subscription as string; - // const subscription = await this.stripe.subscriptions.retrieve(user.subscriptionId); - // user.customerType = 'professional'; - // if (subscription.metadata['plan'] === 'Broker Plan') { - // user.customerSubType = '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.mailService.sendSubscriptionConfirmation(user); - // } catch (error) { - // this.logger.error(error); - // } - } - async getSubscription(email: string): Promise { - const existingCustomers = await this.stripe.customers.list({ - email: email, - limit: 1, - }); - if (existingCustomers.data.length > 0) { - const subscriptions = await this.stripe.subscriptions.list({ - customer: existingCustomers.data[0].id, - status: 'all', // Optional: Gibt Abos in allen Status zurück, wie 'active', 'canceled', etc. - limit: 20, // Optional: Begrenze die Anzahl der zurückgegebenen Abonnements - }); - return subscriptions.data.filter(s => s.status === 'active' || s.status === 'trialing'); - } else { - return []; - } - } - /** - * Ruft alle Stripe-Kunden ab, indem die Paginierung gehandhabt wird. - * @returns Ein Array von Stripe.Customer Objekten. - */ - async getAllStripeCustomer(): Promise { - const allCustomers: Stripe.Customer[] = []; - let hasMore = true; - let startingAfter: string | undefined = undefined; - - try { - while (hasMore) { - const response = await this.stripe.customers.list({ - limit: 100, // Maximale Anzahl pro Anfrage - starting_after: startingAfter, - }); - - allCustomers.push(...response.data); - hasMore = response.has_more; - - if (hasMore && response.data.length > 0) { - startingAfter = response.data[response.data.length - 1].id; - } - } - - return allCustomers; - } catch (error) { - console.error('Fehler beim Abrufen der Stripe-Kunden:', error); - throw new Error('Kunden konnten nicht abgerufen werden.'); - } - } - async getAllStripeSubscriptions(): Promise { - const allSubscriptions: Stripe.Subscription[] = []; - const response = await this.stripe.subscriptions.list({ - limit: 100, - }); - allSubscriptions.push(...response.data); - return allSubscriptions; - } - async getStripePaymentMethod(email: string): Promise { - const existingCustomers = await this.stripe.customers.list({ - email: email, - limit: 1, - }); - const allPayments: Stripe.PaymentMethod[] = []; - if (existingCustomers.data.length > 0) { - const response = await this.stripe.paymentMethods.list({ - customer: existingCustomers.data[0].id, - limit: 10, - }); - allPayments.push(...response.data); - } - return allPayments; - } - async deleteCustomerCompletely(customerId: string): Promise { - try { - // 1. Abonnements kündigen und löschen - const subscriptions = await this.stripe.subscriptions.list({ - customer: customerId, - limit: 100, - }); - - for (const subscription of subscriptions.data) { - await this.stripe.subscriptions.cancel(subscription.id); - this.logger.info(`Abonnement ${subscription.id} gelöscht.`); - } - - // 2. Zahlungsmethoden entfernen - const paymentMethods = await this.stripe.paymentMethods.list({ - customer: customerId, - type: 'card', - }); - - for (const paymentMethod of paymentMethods.data) { - await this.stripe.paymentMethods.detach(paymentMethod.id); - this.logger.info(`Zahlungsmethode ${paymentMethod.id} entfernt.`); - } - - // 4. Kunden löschen - await this.stripe.customers.del(customerId); - this.logger.info(`Kunde ${customerId} erfolgreich gelöscht.`); - } catch (error) { - this.logger.error(`Fehler beim Löschen des Kunden ${customerId}:`, error); - throw new InternalServerErrorException('Fehler beim Löschen des Stripe-Kunden.'); - } - } -} diff --git a/bizmatch/src/environments/environment.base.ts b/bizmatch/src/environments/environment.base.ts index 2f02d29..dcfd3fd 100644 --- a/bizmatch/src/environments/environment.base.ts +++ b/bizmatch/src/environments/environment.base.ts @@ -5,12 +5,6 @@ export const environment_base = { imageBaseUrl: 'https://dev.bizmatch.net', buildVersion: '', mailinfoUrl: 'https://dev.bizmatch.net', - keycloak: { - url: 'https://auth.bizmatch.net', - realm: 'bizmatch-dev', - clientId: 'bizmatch-dev', - redirectUri: 'https://dev.bizmatch.net', - }, ipinfo_token: '7029590fb91214', firebaseConfig: { apiKey: 'AIzaSyBqVutQqdgUzwD9tKiKJrJq2Q6rD1hNdzw', diff --git a/bizmatch/src/environments/environment.ts b/bizmatch/src/environments/environment.ts index d59ebd0..3bff2bd 100644 --- a/bizmatch/src/environments/environment.ts +++ b/bizmatch/src/environments/environment.ts @@ -3,7 +3,3 @@ import { environment_base } from './environment.base'; export const environment = environment_base; environment.mailinfoUrl = 'http://localhost:4200'; environment.imageBaseUrl = 'http://localhost:4200'; -environment.keycloak.clientId = 'dev'; -environment.keycloak.realm = 'dev'; -environment.keycloak.redirectUri = 'http://192.168.178.24:4200'; -// environment.keycloak.redirectUri = 'http://localhost:4200';