initial release

This commit is contained in:
Andreas Knuth 2024-02-29 10:23:41 -06:00
commit 5146c8e919
210 changed files with 11040 additions and 0 deletions

71
.gitignore vendored Normal file
View File

@ -0,0 +1,71 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
public
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# temp directory
.temp
.tmp
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
*.js
*.map
package-lock.json
*.jar
gitea
auth

View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}

22
bizmatch-server/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Nest Framework",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"start:debug",
"--",
"--inspect-brk"
],
"autoAttachChildProcesses": true,
"restart": true,
"sourceMaps": true,
"stopOnEntry": false,
"console": "integratedTerminal",
}
]
}

73
bizmatch-server/README.md Normal file
View File

@ -0,0 +1,73 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
## Installation
```bash
$ npm install
```
## Running the app
```bash
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
```
## Test
```bash
# unit tests
$ npm run test
# e2e tests
$ npm run test:e2e
# test coverage
$ npm run test:cov
```
## Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
## Stay in touch
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)
## License
Nest is [MIT licensed](LICENSE).

View File

@ -0,0 +1 @@
FT.CREATE listingsIndex ON JSON PREFIX 1 listings: SCHEMA $.location AS location TAG SORTABLE $.price AS price NUMERIC SORTABLE $.listingsCategory AS listingsCategory TAG SORTABLE $.type AS type TAG SORTABLE

View File

@ -0,0 +1,7 @@
/// <reference types="multer" />
import { FileService } from '../file/file.service.js';
export declare class AccountController {
private fileService;
constructor(fileService: FileService);
uploadFile(file: Express.Multer.File, id: string): void;
}

View File

@ -0,0 +1,2 @@
export declare class AccountService {
}

View File

@ -0,0 +1,6 @@
import { AppService } from './app.service.js';
export declare class AppController {
private readonly appService;
constructor(appService: AppService);
getHello(): string;
}

2
bizmatch-server/dist/app.module.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
export declare class AppModule {
}

3
bizmatch-server/dist/app.service.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
export declare class AppService {
getHello(): string;
}

View File

@ -0,0 +1,66 @@
[
{
"id":"1",
"userId":"1",
"listingsCategory": "business",
"title": "Industrial Service Company In Corpus Christi For Sale - 1954",
"summary": ["Asking price: $5,500,000","Sales revenue: $1,200,000","Net profit: $650,000"],
"description": ["This company services a wide variety of industries. Asking price includes Business and the Real Estate and is approx 30,000 sq ft with room for expansion including approx 5 acres. Absentee run business."],
"type": "2",
"location": "Texas",
"price":5500000,
"salesRevenue":1200000,
"cashFlow":650000,
"brokerLicencing":"TREC Broker #516788",
"established":1954,
"realEstateIncluded":true
},
{
"id":"2",
"userId":"1",
"listingsCategory": "business",
"title": "Coastal Bend Manufacturing Business Plastic Injection For Sale - 1950",
"summary": ["Asking price: $165,000","Sales revenue: Undisclosed","Net profit: Undisclosed"],
"description": [""],
"type": "12",
"location": "Texas",
"price":165000,
"salesRevenue":null,
"cashFlow":null,
"brokerLicencing":"TREC Broker #516788",
"established":1950,
"realEstateIncluded":false
},
{
"id":"3",
"userId":"1",
"listingsCategory": "business",
"title": "Corner Property On Everhart South-side Corpus Christi For Sale - 1944",
"summary": ["Asking price: $830,000","Sales revenue: Undisclosed","Net profit: Undisclosed"],
"description": [""],
"type": "3",
"location": "Texas",
"price":830000,
"salesRevenue":null,
"cashFlow":null,
"brokerLicencing":"TREC Broker #516788",
"established":1944,
"realEstateIncluded":false
},
{
"id":"4",
"userId":"1",
"listingsCategory": "business",
"title": "Corpus Christi Dessert Business For Sale - 1941",
"summary": ["Asking price: $124,900","Sales revenue: $225,000","Net profit: $50,000"],
"description": [""],
"type": "13",
"location": "Texas",
"price":830000,
"salesRevenue":225000,
"cashFlow":50000,
"brokerLicencing":"TREC Broker #516788",
"established":1941,
"realEstateIncluded":false
}
]

View File

@ -0,0 +1,14 @@
[{
"id":"1",
"userId":"e0811669-c7eb-4e5e-a699-e8334d5c5b01",
"level":"Business Broker",
"start":"2024-02-12T21:54:20.603Z",
"modified":"2024-02-12T21:54:20.603Z",
"end":"9999-02-12T21:54:20.603Z",
"status":"active",
"invoices":[{
"date":"2024-02-12T21:54:20.603Z",
"id":"C991853B99",
"price":0
}]
}]

View File

@ -0,0 +1,8 @@
/// <reference types="multer" />
export declare class FileService {
private subscriptions;
constructor();
private loadSubscriptions;
getSubscriptions(): any;
storeFile(file: Express.Multer.File, id: string): Promise<void>;
}

View File

@ -0,0 +1,13 @@
import { ListingsService } from './listings.service.js';
import { Logger } from 'winston';
export declare class ListingsController {
private readonly listingsService;
private readonly logger;
constructor(listingsService: ListingsService, logger: Logger);
findAll(): any;
findById(id: string): any;
find(criteria: any): any;
updateById(id: string, listing: any): void;
create(listing: any): void;
deleteById(id: string): void;
}

View File

@ -0,0 +1,13 @@
import { BusinessListing, InvestmentsListing, ListingCriteria, ProfessionalsBrokersListing } from '../models/main.model.js';
import { RedisService } from '../redis/redis.service.js';
import { Logger } from 'winston';
export declare class ListingsService {
private redisService;
private readonly logger;
constructor(redisService: RedisService, logger: Logger);
setListing(value: BusinessListing | ProfessionalsBrokersListing | InvestmentsListing, id?: string): Promise<void>;
getListingById(id: string): Promise<any>;
deleteListing(id: string): void;
getAllListings(start?: number, end?: number): Promise<any>;
find(criteria: ListingCriteria): Promise<any>;
}

View File

@ -0,0 +1,7 @@
import { MailService } from './mail.service.js';
import { MailInfo } from '../models/server.model.js';
export declare class MailController {
private mailService;
constructor(mailService: MailService);
sendEMail(id: string, mailInfo: MailInfo): any;
}

View File

@ -0,0 +1,2 @@
export declare class MailModule {
}

View File

@ -0,0 +1,9 @@
import { MailerService } from '@nestjs-modules/mailer';
import { AuthService } from '../auth/auth.service.js';
import { MailInfo } from '../models/server.model.js';
export declare class MailService {
private mailerService;
private authService;
constructor(mailerService: MailerService, authService: AuthService);
sendInquiry(userId: string, mailInfo: MailInfo): Promise<void>;
}

View File

@ -0,0 +1,5 @@
<p>Hey {{ name }},</p>
<p>You got an inquiry a</p>
<p>
{{inquiry}}
</p>

1
bizmatch-server/dist/main.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,126 @@
export interface KeyValue {
name: string;
value: string;
}
export interface KeyValueStyle {
name: string;
value: string;
icon: string;
bgColorClass: string;
textColorClass: string;
}
export type SelectOption<T = number> = {
value: T;
label: string;
};
export interface Listing {
id: string;
userId: string;
title: string;
description: Array<string>;
location: string;
favoritesForUser: Array<string>;
hideImage?: boolean;
created: Date;
updated: Date;
}
export interface BusinessListing extends Listing {
listingsCategory: 'business';
summary: Array<string>;
type: string;
price?: number;
realEstateIncluded?: boolean;
salesRevenue?: number;
cashFlow?: number;
netProfit?: number;
inventory?: string;
employees?: number;
established?: number;
reasonForSale?: string;
brokerLicencing?: string;
internals?: string;
}
export interface ProfessionalsBrokersListing extends Listing {
listingsCategory: 'professionals_brokers';
summary: string;
address?: string;
email?: string;
website?: string;
category?: 'Professionals' | 'Broker';
}
export interface InvestmentsListing extends Listing {
listingsCategory: 'investment';
email?: string;
website?: string;
phoneNumber?: string;
}
export type ListingType = BusinessListing | ProfessionalsBrokersListing | InvestmentsListing;
export interface ListingCriteria {
type: string;
location: string;
minPrice: string;
maxPrice: string;
realEstateChecked: boolean;
listingsCategory: 'business' | 'professionals_brokers' | 'investment';
category: 'professional|broker';
}
export interface User {
id: string;
username: string;
firstname: string;
lastname: string;
email: string;
}
export interface Subscription {
id: string;
userId: string;
level: string;
start: Date;
modified: Date;
end: Date;
status: string;
invoices: Array<Invoice>;
}
export interface Invoice {
id: string;
date: Date;
price: number;
}
export interface JwtToken {
exp: number;
iat: number;
auth_time: number;
jti: string;
iss: string;
aud: string;
sub: string;
typ: string;
azp: string;
nonce: string;
session_state: string;
acr: string;
realm_access: Realmaccess;
resource_access: Resourceaccess;
scope: string;
sid: string;
email_verified: boolean;
name: string;
preferred_username: string;
given_name: string;
family_name: string;
email: string;
user_id: string;
}
interface Resourceaccess {
account: Realmaccess;
}
interface Realmaccess {
roles: string[];
}
export interface PageEvent {
first: number;
rows: number;
page: number;
pageCount: number;
}
export {};

View File

@ -0,0 +1,129 @@
export interface KeyValue {
name: string;
value: string;
}
export interface KeyValueStyle {
name: string;
value: string;
icon:string;
bgColorClass:string;
textColorClass:string;
}
export type SelectOption<T = number> = {
value: T;
label: string;
};
export interface Listing {
id: string;
userId: string;
title: string;
description: Array<string>;
location: string;//enum
favoritesForUser:Array<string>;
hideImage?:boolean;
created:Date;
updated:Date;
}
export interface BusinessListing extends Listing {
listingsCategory: 'business'; //enum
summary: Array<string>;
type: string; //enum
price?: number;
realEstateIncluded?: boolean;
salesRevenue?: number;
cashFlow?: number;
netProfit?: number;
inventory?: string;
employees?: number;
established?: number;
reasonForSale?: string;
brokerLicencing?: string;
internals?: string;
}
export interface ProfessionalsBrokersListing extends Listing {
listingsCategory: 'professionals_brokers'; //enum
summary: string;
address?: string;
email?: string;
website?: string;
category?: 'Professionals' | 'Broker';
}
export interface InvestmentsListing extends Listing {
listingsCategory: 'investment'; //enum
email?: string;
website?: string;
phoneNumber?: string;
}
export type ListingType =
| BusinessListing
| ProfessionalsBrokersListing
| InvestmentsListing;
export interface ListingCriteria {
type:string,
location:string,
minPrice:string,
maxPrice:string,
realEstateChecked:boolean,
listingsCategory:'business'|'professionals_brokers'|'investment',
category:'professional|broker'
}
export interface User {
id: string;
username: string;
firstname: string;
lastname: string;
email: string;
}
export interface Subscription {
id: string;
userId:string
level: string;
start: Date;
modified: Date;
end: Date;
status: string;
invoices: Array<Invoice>;
}
export interface Invoice {
id: string,
date: Date,
price: number
}
export interface JwtToken {
exp: number;
iat: number;
auth_time: number;
jti: string;
iss: string;
aud: string;
sub: string;
typ: string;
azp: string;
nonce: string;
session_state: string;
acr: string;
realm_access: Realmaccess;
resource_access: Resourceaccess;
scope: string;
sid: string;
email_verified: boolean;
name: string;
preferred_username: string;
given_name: string;
family_name: string;
email: string;
user_id: string;
}
interface Resourceaccess {
account: Realmaccess;
}
interface Realmaccess {
roles: string[];
}
export interface PageEvent {
first: number;
rows: number;
page: number;
pageCount: number;
}

View File

@ -0,0 +1,11 @@
export interface MailInfo {
sender: Sender;
userId: string;
}
export interface Sender {
name: string;
email: string;
phoneNumber: string;
state: string;
comments: string;
}

View File

@ -0,0 +1,5 @@
import { RedisService } from './redis.service.js';
export declare class RedisController {
private redisService;
constructor(redisService: RedisService);
}

View File

@ -0,0 +1,2 @@
export declare class RedisModule {
}

View File

@ -0,0 +1,11 @@
export declare const LISTINGS = "LISTINGS";
export declare const SUBSCRIPTIONS = "SUBSCRIPTIONS";
export declare const USERS = "USERS";
export declare class RedisService {
private redis;
setJson(id: string, value: any): Promise<void>;
delete(id: string): Promise<void>;
getJson(id: string, prefix: string): Promise<any>;
getId(prefix: 'LISTINGS' | 'SUBSCRIPTIONS' | 'USERS'): Promise<string>;
search(prefix: 'LISTINGS' | 'SUBSCRIPTIONS' | 'USERS', clause: string): Promise<any>;
}

View File

@ -0,0 +1,6 @@
import { SelectOptionsService } from './select-options.service.js';
export declare class SelectOptionsController {
private selectOptionsService;
constructor(selectOptionsService: SelectOptionsService);
getSelectOption(): any;
}

View File

@ -0,0 +1,10 @@
import { KeyValue, KeyValueStyle } from '../models/main.model.js';
export declare class SelectOptionsService {
constructor();
typesOfBusiness: Array<KeyValueStyle>;
prices: Array<KeyValue>;
listingCategories: Array<KeyValue>;
categories: Array<KeyValueStyle>;
private usStates;
locations: Array<any>;
}

View File

@ -0,0 +1,6 @@
import { FileService } from '../file/file.service.js';
export declare class SubscriptionsController {
private readonly fileService;
constructor(fileService: FileService);
findAll(): any;
}

File diff suppressed because one or more lines are too long

1
bizmatch-server/dist/utils.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare function convertStringToNullUndefined(value: any): any;

View File

@ -0,0 +1,10 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true,
"assets": ["assets/**/*","**/*.hbs"],
"watchAssets": true
}
}

View File

@ -0,0 +1,92 @@
{
"name": "bizmatch-server",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"type": "module",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs-modules/mailer": "^1.10.3",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.0",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/serve-static": "^4.0.1",
"handlebars": "^4.7.8",
"ioredis": "^5.3.2",
"ky": "^1.2.0",
"nest-winston": "^1.9.4",
"nodemailer": "^6.9.10",
"nodemailer-smtp-transport": "^2.7.4",
"passport": "^0.7.0",
"passport-google-oauth20": "^2.0.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"urlcat": "^3.1.0",
"winston": "^3.11.0"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/multer": "^1.4.11",
"@types/node": "^20.11.19",
"@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/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

View File

@ -0,0 +1,14 @@
import { Controller, Param, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { FileService } from '../file/file.service.js';
@Controller('account')
export class AccountController {
constructor(private fileService:FileService){}
@Post('uploadPhoto/:id')
@UseInterceptors(FileInterceptor('file'),)
uploadFile(@UploadedFile() file: Express.Multer.File,@Param('id') id:string) {
this.fileService.storeFile(file,id);
}
}

View File

@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class AccountService {}

View File

@ -0,0 +1,12 @@
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service.js';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}

View File

@ -0,0 +1,51 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller.js';
import { AppService } from './app.service.js';
import { ListingsController } from './listings/listings.controller.js';
import { FileService } from './file/file.service.js';
import { AuthService } from './auth/auth.service.js';
import { AuthController } from './auth/auth.controller.js';
import { ConfigModule } from '@nestjs/config';
import { SelectOptionsController } from './select-options/select-options.controller.js';
import { SelectOptionsService } from './select-options/select-options.service.js';
import { SubscriptionsController } from './subscriptions/subscriptions.controller.js';
import { RedisModule } from './redis/redis.module.js';
import { ListingsService } from './listings/listings.service.js';
import { AccountController } from './account/account.controller.js';
import { AccountService } from './account/account.service.js';
import { ServeStaticModule } from '@nestjs/serve-static';
import path, { join } from 'path';
import { fileURLToPath } from 'url';
import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import { MailModule } from './mail/mail.module.js';
import { AuthModule } from './auth/auth.module.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@Module({
imports: [ConfigModule.forRoot(), RedisModule, MailModule, AuthModule,
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public'), // `public` ist das Verzeichnis, wo Ihre statischen Dateien liegen
}),
WinstonModule.forRoot({
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.ms(),
nestWinstonModuleUtilities.format.nestLike('Bizmatch', {
colors: true,
prettyPrint: true,
}),
),
}),
// other transports...
],
// other options
})
],
controllers: [AppController, ListingsController, SelectOptionsController, SubscriptionsController, AccountController],
providers: [AppService, FileService, SelectOptionsService, ListingsService, AccountService],
})
export class AppModule {}

View File

@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}

View File

@ -0,0 +1,66 @@
[
{
"id":"1",
"userId":"1",
"listingsCategory": "business",
"title": "Industrial Service Company In Corpus Christi For Sale - 1954",
"summary": ["Asking price: $5,500,000","Sales revenue: $1,200,000","Net profit: $650,000"],
"description": ["This company services a wide variety of industries. Asking price includes Business and the Real Estate and is approx 30,000 sq ft with room for expansion including approx 5 acres. Absentee run business."],
"type": "2",
"location": "Texas",
"price":5500000,
"salesRevenue":1200000,
"cashFlow":650000,
"brokerLicencing":"TREC Broker #516788",
"established":1954,
"realEstateIncluded":true
},
{
"id":"2",
"userId":"1",
"listingsCategory": "business",
"title": "Coastal Bend Manufacturing Business Plastic Injection For Sale - 1950",
"summary": ["Asking price: $165,000","Sales revenue: Undisclosed","Net profit: Undisclosed"],
"description": [""],
"type": "12",
"location": "Texas",
"price":165000,
"salesRevenue":null,
"cashFlow":null,
"brokerLicencing":"TREC Broker #516788",
"established":1950,
"realEstateIncluded":false
},
{
"id":"3",
"userId":"1",
"listingsCategory": "business",
"title": "Corner Property On Everhart South-side Corpus Christi For Sale - 1944",
"summary": ["Asking price: $830,000","Sales revenue: Undisclosed","Net profit: Undisclosed"],
"description": [""],
"type": "3",
"location": "Texas",
"price":830000,
"salesRevenue":null,
"cashFlow":null,
"brokerLicencing":"TREC Broker #516788",
"established":1944,
"realEstateIncluded":false
},
{
"id":"4",
"userId":"1",
"listingsCategory": "business",
"title": "Corpus Christi Dessert Business For Sale - 1941",
"summary": ["Asking price: $124,900","Sales revenue: $225,000","Net profit: $50,000"],
"description": [""],
"type": "13",
"location": "Texas",
"price":830000,
"salesRevenue":225000,
"cashFlow":50000,
"brokerLicencing":"TREC Broker #516788",
"established":1941,
"realEstateIncluded":false
}
]

View File

@ -0,0 +1,14 @@
[{
"id":"1",
"userId":"e0811669-c7eb-4e5e-a699-e8334d5c5b01",
"level":"Business Broker",
"start":"2024-02-12T21:54:20.603Z",
"modified":"2024-02-12T21:54:20.603Z",
"end":"9999-02-12T21:54:20.603Z",
"status":"active",
"invoices":[{
"date":"2024-02-12T21:54:20.603Z",
"id":"C991853B99",
"price":0
}]
}]

View File

@ -0,0 +1,29 @@
import { Injectable } from '@nestjs/common';
import { fstat, readFileSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
import path from 'path';
import fs from 'fs-extra';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@Injectable()
export class FileService {
private subscriptions: any;
constructor() {
this.loadSubscriptions();
}
private loadSubscriptions(): void {
const filePath = join(__dirname,'..', 'assets', 'subscriptions.json');
const rawData = readFileSync(filePath, 'utf8');
this.subscriptions = JSON.parse(rawData);
}
getSubscriptions() {
return this.subscriptions
}
async storeFile(file: Express.Multer.File,id: string){
const suffix = file.mimetype.includes('png')?'png':'jpg'
await fs.outputFile(`./public/profile_${id}`,file.buffer);
}
}

View File

@ -0,0 +1,59 @@
import { Body, Controller, Delete, Get, Inject, Param, Post, Put } from '@nestjs/common';
import { FileService } from '../file/file.service.js';
import { convertStringToNullUndefined } from '../utils.js';
import { RedisService } from '../redis/redis.service.js';
import { ListingsService } from './listings.service.js';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
@Controller('listings')
export class ListingsController {
// private readonly logger = new Logger(ListingsController.name);
constructor(private readonly listingsService:ListingsService,@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) {
}
@Get()
findAll(): any {
return this.listingsService.getAllListings();
}
@Get(':id')
findById(@Param('id') id:string): any {
return this.listingsService.getListingById(id);
}
// @Get(':type/:location/:minPrice/:maxPrice/:realEstateChecked')
// find(@Param('type') type:string,@Param('location') location:string,@Param('minPrice') minPrice:string,@Param('maxPrice') maxPrice:string,@Param('realEstateChecked') realEstateChecked:boolean): any {
// return this.listingsService.find(type,location,minPrice,maxPrice,realEstateChecked);
// }
@Post('search')
find(@Body() criteria: any): any {
return this.listingsService.find(criteria);
}
/**
* @param listing updates a new listing
*/
@Put(':id')
updateById(@Param('id') id:string, @Body() listing: any){
this.logger.info(`Update by ID: ${id}`);
this.listingsService.setListing(listing,id)
}
/**
* @param listing creates a new listing
*/
@Post()
create(@Body() listing: any){
this.logger.info(`Create Listing`);
this.listingsService.setListing(listing)
}
/**
* @param id deletes a listing
*/
@Delete(':id')
deleteById(@Param('id') id:string){
this.listingsService.deleteListing(id)
}
}

View File

@ -0,0 +1,86 @@
import { Inject, Injectable } from '@nestjs/common';
import {
BusinessListing,
InvestmentsListing,
ListingCriteria,
ProfessionalsBrokersListing,
} from '../models/main.model.js';
import { LISTINGS, RedisService } from '../redis/redis.service.js';
import { convertStringToNullUndefined } from '../utils.js';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
@Injectable()
export class ListingsService {
// private readonly logger = new Logger(ListingsService.name);
constructor(private redisService: RedisService,@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) {}
async setListing(
value: BusinessListing | ProfessionalsBrokersListing | InvestmentsListing,
id?: string,
) {
if (!id) {
id = await this.redisService.getId(LISTINGS);
value.id = id;
this.logger.info(`No ID - creating new one:${id}`)
} else {
this.logger.info(`ID available:${id}`)
}
this.redisService.setJson(id, value);
}
async getListingById(id: string) {
return await this.redisService.getJson(id, LISTINGS);
}
deleteListing(id: string){
this.redisService.delete(id);
this.logger.info(`delete listing with ID:${id}`)
}
async getAllListings(start?: number, end?: number) {
const searchResult = await this.redisService.search(LISTINGS, '*');
const listings = searchResult.slice(1).reduce((acc, item, index, array) => {
// Jedes zweite Element (beginnend mit dem ersten) ist ein JSON-String des Listings
if (index % 2 === 1) {
try {
const listing = JSON.parse(item[1]); // Parsen des JSON-Strings
acc.push(listing);
} catch (error) {
console.error('Fehler beim Parsen des JSON-Strings: ', error);
}
}
return acc;
}, []);
return listings;
}
//criteria.type,criteria.location,criteria.minPrice,criteria.maxPrice,criteria.realEstateChecked,criteria.listingsCategory
//async find(type:string,location:string,minPrice:string,maxPrice:string,realEstateChecked:boolean,listingsCategory:string): Promise<any> {
async find(criteria:ListingCriteria): Promise<any> {
let listings = await this.getAllListings();
listings=listings.filter(l=>l.listingsCategory===criteria.listingsCategory);
if (convertStringToNullUndefined(criteria.type)){
console.log(criteria.type);
listings=listings.filter(l=>l.type===criteria.type);
}
if (convertStringToNullUndefined(criteria.location)){
console.log(criteria.location);
listings=listings.filter(l=>l.location===criteria.location);
}
if (convertStringToNullUndefined(criteria.minPrice)){
console.log(criteria.minPrice);
listings=listings.filter(l=>l.price>=Number(criteria.minPrice));
}
if (convertStringToNullUndefined(criteria.maxPrice)){
console.log(criteria.maxPrice);
listings=listings.filter(l=>l.price<=Number(criteria.maxPrice));
}
if (convertStringToNullUndefined(criteria.realEstateChecked)){
console.log(criteria.realEstateChecked);
listings=listings.filter(l=>l.realEstateIncluded);
}
if (convertStringToNullUndefined(criteria.category)){
console.log(criteria.category);
listings=listings.filter(l=>l.category===criteria.category);
}
return listings
}
}

View File

@ -0,0 +1,14 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { MailService } from './mail.service.js';
import { MailInfo } from '../models/server.model.js';
@Controller('mail')
export class MailController {
constructor(private mailService:MailService){
}
@Post(':id')
sendEMail(@Param('id') id:string,@Body() mailInfo: MailInfo): any {
return this.mailService.sendInquiry(id,mailInfo);
}
}

View File

@ -0,0 +1,40 @@
import { Module } from '@nestjs/common';
import { MailService } from './mail.service.js';
import { MailController } from './mail.controller.js';
import { MailerModule } from '@nestjs-modules/mailer';
import path, { join } from 'path';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter.js';
import { fileURLToPath } from 'url';
import { AuthModule } from '../auth/auth.module.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@Module({
imports: [AuthModule,
MailerModule.forRoot({
// transport: 'smtps://user@example.com:topsecret@smtp.example.com',
// or
transport: {
host: 'smtp.gmail.com',
secure: true,
auth: {
user: 'andreas.knuth@gmail.com',
pass: 'ksnh xjae dqbv xana',
},
},
defaults: {
from: '"No Reply" <noreply@example.com>',
},
template: {
dir: join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(), // or new PugAdapter() or new EjsAdapter()
options: {
strict: true,
},
},
}),
],
providers: [MailService],
controllers: [MailController]
})
export class MailModule {}

View File

@ -0,0 +1,24 @@
import { MailerService } from '@nestjs-modules/mailer';
import { Injectable } from '@nestjs/common';
import { AuthService } from '../auth/auth.service.js';
import { MailInfo } from '../models/server.model.js';
import { User } from 'src/models/main.model.js';
@Injectable()
export class MailService {
constructor(private mailerService: MailerService, private authService:AuthService) {}
async sendInquiry(userId:string,mailInfo: MailInfo) {
const user = await this.authService.getUser(userId) as User;
await this.mailerService.sendMail({
to: user.email,
from: '"Bizmatch Team" <info@bizmatch.net>', // override default from
subject: `Inquiry from ${mailInfo.sender.name}`,
template: './inquiry', // `.hbs` extension is appended automatically
context: { // ✏️ filling curly brackets with content
name: user.firstname,
inquiry:mailInfo.sender.comments
},
});
}
}

View File

@ -0,0 +1,5 @@
<p>Hey {{ name }},</p>
<p>You got an inquiry a</p>
<p>
{{inquiry}}
</p>

View File

@ -0,0 +1,15 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module.js';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('bizmatch');
app.enableCors({
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
allowedHeaders: 'Content-Type, Accept',
});
//origin: 'http://localhost:4200',
await app.listen(3000);
}
bootstrap();

View File

View File

@ -0,0 +1,11 @@
export interface MailInfo {
sender:Sender;
userId:string;
}
export interface Sender {
name:string;
email:string;
phoneNumber:string;
state:string;
comments:string;
}

View File

@ -0,0 +1,18 @@
import { Body, Controller, Get, HttpStatus, Param, Post, Res } from '@nestjs/common';
import { Response } from 'express';
import { RedisService } from './redis.service.js';
@Controller('redis')
export class RedisController {
constructor(private redisService:RedisService){}
// @Get(':id')
// getById(@Param('id') id:string){
// return this.redisService.getListingById(id);
// }
// @Post(':id')
// updateById(@Body() listing: any){
// this.redisService.setListing(listing);
// }
}

View File

@ -0,0 +1,16 @@
// redis.module.ts
import { Module } from '@nestjs/common';
@Module({
providers: [RedisService],
exports: [RedisService],
controllers: [RedisController],
})
export class RedisModule {}
// redis.service.ts
import { Injectable } from '@nestjs/common';
import { RedisService } from './redis.service.js';
import { RedisController } from './redis.controller.js';

View File

@ -0,0 +1,39 @@
// redis.service.ts
import { Injectable } from '@nestjs/common';
import { Redis } from 'ioredis';
import { BusinessListing, InvestmentsListing,ProfessionalsBrokersListing } from '../models/main.model.js';
export const LISTINGS = 'LISTINGS';
export const SUBSCRIPTIONS = 'SUBSCRIPTIONS';
export const USERS = 'USERS'
@Injectable()
export class RedisService {
private redis = new Redis(); // Verbindungsparameter nach Bedarf anpassen
// ######################################
// general methods
// ######################################
async setJson(id: string, value: any): Promise<void> {
await this.redis.call("JSON.SET", `${LISTINGS}:${id}`, "$", JSON.stringify(value));
}
async delete(id: string): Promise<void> {
await this.redis.del(`${LISTINGS}:${id}`);
}
async getJson(id: string, prefix:string): Promise<any> {
const result:string = await this.redis.call("JSON.GET", `${prefix}:${id}`) as string;
return JSON.parse(result);
}
async getId(prefix:'LISTINGS'|'SUBSCRIPTIONS'|'USERS'):Promise<string>{
const counter = await this.redis.call("INCR",`${prefix}_ID_COUNTER`) as number;
return counter.toString().padStart(15, '0')
}
async search(prefix:'LISTINGS'|'SUBSCRIPTIONS'|'USERS',clause:string):Promise<any>{
const result = await this.redis.call(`FT.SEARCH`, `${prefix}_INDEX`, `${clause}`, 'LIMIT', 0, 200);
return result;
}
}

View File

@ -0,0 +1,17 @@
import { Controller, Get } from '@nestjs/common';
import { SelectOptionsService } from './select-options.service.js';
@Controller('select-options')
export class SelectOptionsController {
constructor(private selectOptionsService:SelectOptionsService){}
@Get()
getSelectOption():any{
return {
typesOfBusiness:this.selectOptionsService.typesOfBusiness,
prices:this.selectOptionsService.prices,
listingCategories:this.selectOptionsService.listingCategories,
categories:this.selectOptionsService.categories,
locations:this.selectOptionsService.locations,
}
}
}

View File

@ -0,0 +1,102 @@
import { Injectable } from '@nestjs/common';
import { KeyValue, KeyValueStyle } from '../models/main.model.js';
@Injectable()
export class SelectOptionsService {
constructor() { }
public typesOfBusiness: Array<KeyValueStyle> = [
{ name: 'Automotive', value: '1', icon:'fa-solid fa-car',bgColorClass:'bg-green-100',textColorClass:'text-green-600' },
{ name: 'Industrial Services', value: '2', icon:'fa-solid fa-industry',bgColorClass:'bg-yellow-100',textColorClass:'text-yellow-600'},
{ name: 'Real Estate', value: '3' , icon:'pi pi-building',bgColorClass:'bg-blue-100',textColorClass:'text-blue-600'},
{ name: 'Uncategorized', value: '4' , icon:'pi pi-question',bgColorClass:'bg-cyan-100',textColorClass:'text-cyan-600'},
{ name: 'Retail', value: '5' , icon:'fa-solid fa-money-bill-wave',bgColorClass:'bg-pink-100',textColorClass:'text-pink-600'},
{ name: 'Oilfield SVE and MFG.', value: '6' , icon:'fa-solid fa-oil-well',bgColorClass:'bg-indigo-100',textColorClass:'text-indigo-600'},
{ name: 'Service', value: '7' , icon:'fa-solid fa-umbrella',bgColorClass:'bg-teal-100',textColorClass:'text-teal-600'},
{ name: 'Advertising', value: '8' , icon:'fa-solid fa-rectangle-ad',bgColorClass:'bg-orange-100',textColorClass:'text-orange-600'},
{ name: 'Agriculture', value: '9' , icon:'fa-solid fa-wheat-awn',bgColorClass:'bg-bluegray-100',textColorClass:'text-bluegray-600'},
{ name: 'Franchise', value: '10' , icon:'pi pi-star',bgColorClass:'bg-purple-100',textColorClass:'text-purple-600'},
{ name: 'Professional', value: '11' , icon:'fa-solid fa-user-gear',bgColorClass:'bg-gray-100',textColorClass:'text-gray-600'},
{ name: 'Manufacturing', value: '12' , icon:'fa-solid fa-industry',bgColorClass:'bg-red-100',textColorClass:'text-red-600'},
{ name: 'Food and Restaurant', value: '13' , icon:'fa-solid fa-utensils',bgColorClass:'bg-primary-100',textColorClass:'text-primary-600'},
];
public prices: Array<KeyValue> = [
{ name: '$100K', value: '100000' },
{ name: '$250K', value: '250000' },
{ name: '$500K', value: '500000' },
{ name: '$1M', value: '1000000' },
{ name: '$5M', value: '5000000' },
];
public listingCategories: Array<KeyValue> = [
{ name: 'Business', value: 'business' },
{ name: 'Professionals/Brokers Directory', value: 'professionals_brokers' },
{ name: 'Investment Property', value: 'investment' },
]
public categories: Array<KeyValueStyle> = [
{ name: 'Broker', value: 'broker', icon:'pi-image',bgColorClass:'bg-green-100',textColorClass:'text-green-600' },
{ name: 'Professional', value: 'professional', icon:'pi-globe',bgColorClass:'bg-yellow-100',textColorClass:'text-yellow-600' },
]
private usStates = [
{ name: 'ALABAMA', abbreviation: 'AL'},
{ name: 'ALASKA', abbreviation: 'AK'},
{ name: 'AMERICAN SAMOA', abbreviation: 'AS'},
{ name: 'ARIZONA', abbreviation: 'AZ'},
{ name: 'ARKANSAS', abbreviation: 'AR'},
{ name: 'CALIFORNIA', abbreviation: 'CA'},
{ name: 'COLORADO', abbreviation: 'CO'},
{ name: 'CONNECTICUT', abbreviation: 'CT'},
{ name: 'DELAWARE', abbreviation: 'DE'},
{ name: 'DISTRICT OF COLUMBIA', abbreviation: 'DC'},
{ name: 'FEDERATED STATES OF MICRONESIA', abbreviation: 'FM'},
{ name: 'FLORIDA', abbreviation: 'FL'},
{ name: 'GEORGIA', abbreviation: 'GA'},
{ name: 'GUAM', abbreviation: 'GU'},
{ name: 'HAWAII', abbreviation: 'HI'},
{ name: 'IDAHO', abbreviation: 'ID'},
{ name: 'ILLINOIS', abbreviation: 'IL'},
{ name: 'INDIANA', abbreviation: 'IN'},
{ name: 'IOWA', abbreviation: 'IA'},
{ name: 'KANSAS', abbreviation: 'KS'},
{ name: 'KENTUCKY', abbreviation: 'KY'},
{ name: 'LOUISIANA', abbreviation: 'LA'},
{ name: 'MAINE', abbreviation: 'ME'},
{ name: 'MARSHALL ISLANDS', abbreviation: 'MH'},
{ name: 'MARYLAND', abbreviation: 'MD'},
{ name: 'MASSACHUSETTS', abbreviation: 'MA'},
{ name: 'MICHIGAN', abbreviation: 'MI'},
{ name: 'MINNESOTA', abbreviation: 'MN'},
{ name: 'MISSISSIPPI', abbreviation: 'MS'},
{ name: 'MISSOURI', abbreviation: 'MO'},
{ name: 'MONTANA', abbreviation: 'MT'},
{ name: 'NEBRASKA', abbreviation: 'NE'},
{ name: 'NEVADA', abbreviation: 'NV'},
{ name: 'NEW HAMPSHIRE', abbreviation: 'NH'},
{ name: 'NEW JERSEY', abbreviation: 'NJ'},
{ name: 'NEW MEXICO', abbreviation: 'NM'},
{ name: 'NEW YORK', abbreviation: 'NY'},
{ name: 'NORTH CAROLINA', abbreviation: 'NC'},
{ name: 'NORTH DAKOTA', abbreviation: 'ND'},
{ name: 'NORTHERN MARIANA ISLANDS', abbreviation: 'MP'},
{ name: 'OHIO', abbreviation: 'OH'},
{ name: 'OKLAHOMA', abbreviation: 'OK'},
{ name: 'OREGON', abbreviation: 'OR'},
{ name: 'PALAU', abbreviation: 'PW'},
{ name: 'PENNSYLVANIA', abbreviation: 'PA'},
{ name: 'PUERTO RICO', abbreviation: 'PR'},
{ name: 'RHODE ISLAND', abbreviation: 'RI'},
{ name: 'SOUTH CAROLINA', abbreviation: 'SC'},
{ name: 'SOUTH DAKOTA', abbreviation: 'SD'},
{ name: 'TENNESSEE', abbreviation: 'TN'},
{ name: 'TEXAS', abbreviation: 'TX'},
{ name: 'UTAH', abbreviation: 'UT'},
{ name: 'VERMONT', abbreviation: 'VT'},
{ name: 'VIRGIN ISLANDS', abbreviation: 'VI'},
{ name: 'VIRGINIA', abbreviation: 'VA'},
{ name: 'WASHINGTON', abbreviation: 'WA'},
{ name: 'WEST VIRGINIA', abbreviation: 'WV'},
{ name: 'WISCONSIN', abbreviation: 'WI'},
{ name: 'WYOMING', abbreviation: 'WY' }
]
public locations:Array<any> = [...this.usStates.map(state=>({name:state.name, value:state.abbreviation}))].concat({name:'CANADA',value:"CA"});
}

View File

@ -0,0 +1,12 @@
import { Controller, Get } from '@nestjs/common';
import { FileService } from '../file/file.service.js';
@Controller('subscriptions')
export class SubscriptionsController {
constructor(private readonly fileService: FileService){}
@Get()
findAll(): any {
return this.fileService.getSubscriptions();
}
}

View File

@ -0,0 +1,13 @@
export function convertStringToNullUndefined(value) {
// Konvertiert den Wert zu Kleinbuchstaben für eine case-insensitive Überprüfung
const lowerCaseValue = typeof value === 'boolean' ? value : value?.toLowerCase();
if (lowerCaseValue === 'null') {
return null;
} else if (lowerCaseValue === 'undefined') {
return undefined;
}
// Gibt den Originalwert zurück, wenn es sich nicht um 'null' oder 'undefined' handelt
return value;
}

View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ES2021",
"module": "Node16",
"moduleResolution": "Node16",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,331 @@
{
"hash": "67af9537",
"configHash": "34f84833",
"lockfileHash": "c6a666e0",
"browserHash": "ac877f75",
"optimized": {
"@angular/common": {
"src": "../../../../../node_modules/@angular/common/fesm2022/common.mjs",
"file": "@angular_common.js",
"fileHash": "28f818f0",
"needsInterop": false
},
"@angular/common/http": {
"src": "../../../../../node_modules/@angular/common/fesm2022/http.mjs",
"file": "@angular_common_http.js",
"fileHash": "3e7d92bd",
"needsInterop": false
},
"@angular/core": {
"src": "../../../../../node_modules/@angular/core/fesm2022/core.mjs",
"file": "@angular_core.js",
"fileHash": "accc9b8c",
"needsInterop": false
},
"@angular/forms": {
"src": "../../../../../node_modules/@angular/forms/fesm2022/forms.mjs",
"file": "@angular_forms.js",
"fileHash": "928647a5",
"needsInterop": false
},
"@angular/platform-browser": {
"src": "../../../../../node_modules/@angular/platform-browser/fesm2022/platform-browser.mjs",
"file": "@angular_platform-browser.js",
"fileHash": "9b924e7c",
"needsInterop": false
},
"@angular/platform-browser/animations": {
"src": "../../../../../node_modules/@angular/platform-browser/fesm2022/animations.mjs",
"file": "@angular_platform-browser_animations.js",
"fileHash": "7495a616",
"needsInterop": false
},
"@angular/router": {
"src": "../../../../../node_modules/@angular/router/fesm2022/router.mjs",
"file": "@angular_router.js",
"fileHash": "735c693a",
"needsInterop": false
},
"@fortawesome/angular-fontawesome": {
"src": "../../../../../node_modules/@fortawesome/angular-fontawesome/fesm2022/angular-fontawesome.mjs",
"file": "@fortawesome_angular-fontawesome.js",
"fileHash": "0cf8f8a4",
"needsInterop": false
},
"@fortawesome/free-regular-svg-icons": {
"src": "../../../../../node_modules/@fortawesome/free-regular-svg-icons/index.mjs",
"file": "@fortawesome_free-regular-svg-icons.js",
"fileHash": "a6d77e90",
"needsInterop": false
},
"@fortawesome/free-solid-svg-icons": {
"src": "../../../../../node_modules/@fortawesome/free-solid-svg-icons/index.mjs",
"file": "@fortawesome_free-solid-svg-icons.js",
"fileHash": "248c3041",
"needsInterop": false
},
"browser-bunyan": {
"src": "../../../../../node_modules/browser-bunyan/lib/index.m.js",
"file": "browser-bunyan.js",
"fileHash": "3556293f",
"needsInterop": false
},
"jwt-decode": {
"src": "../../../../../node_modules/jwt-decode/build/esm/index.js",
"file": "jwt-decode.js",
"fileHash": "31be6951",
"needsInterop": false
},
"keycloak-js": {
"src": "../../../../../node_modules/keycloak-js/dist/keycloak.mjs",
"file": "keycloak-js.js",
"fileHash": "a0ad62ab",
"needsInterop": false
},
"on-change": {
"src": "../../../../../node_modules/on-change/index.js",
"file": "on-change.js",
"fileHash": "78a0866f",
"needsInterop": false
},
"primeng/api": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-api.mjs",
"file": "primeng_api.js",
"fileHash": "4db75e0f",
"needsInterop": false
},
"primeng/button": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-button.mjs",
"file": "primeng_button.js",
"fileHash": "1190de19",
"needsInterop": false
},
"primeng/checkbox": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-checkbox.mjs",
"file": "primeng_checkbox.js",
"fileHash": "9193d0d3",
"needsInterop": false
},
"primeng/chip": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-chip.mjs",
"file": "primeng_chip.js",
"fileHash": "d481740a",
"needsInterop": false
},
"primeng/confirmdialog": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-confirmdialog.mjs",
"file": "primeng_confirmdialog.js",
"fileHash": "27802851",
"needsInterop": false
},
"primeng/confirmpopup": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-confirmpopup.mjs",
"file": "primeng_confirmpopup.js",
"fileHash": "07fa7368",
"needsInterop": false
},
"primeng/divider": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-divider.mjs",
"file": "primeng_divider.js",
"fileHash": "d9ac7514",
"needsInterop": false
},
"primeng/dropdown": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-dropdown.mjs",
"file": "primeng_dropdown.js",
"fileHash": "a52c3507",
"needsInterop": false
},
"primeng/fileupload": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-fileupload.mjs",
"file": "primeng_fileupload.js",
"fileHash": "57b31a6c",
"needsInterop": false
},
"primeng/inputnumber": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-inputnumber.mjs",
"file": "primeng_inputnumber.js",
"fileHash": "2c9bde1c",
"needsInterop": false
},
"primeng/inputtext": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-inputtext.mjs",
"file": "primeng_inputtext.js",
"fileHash": "b03c8c78",
"needsInterop": false
},
"primeng/inputtextarea": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-inputtextarea.mjs",
"file": "primeng_inputtextarea.js",
"fileHash": "890a3704",
"needsInterop": false
},
"primeng/menubar": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-menubar.mjs",
"file": "primeng_menubar.js",
"fileHash": "573b8558",
"needsInterop": false
},
"primeng/overlaypanel": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-overlaypanel.mjs",
"file": "primeng_overlaypanel.js",
"fileHash": "cbfd82db",
"needsInterop": false
},
"primeng/paginator": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-paginator.mjs",
"file": "primeng_paginator.js",
"fileHash": "f1a55a1a",
"needsInterop": false
},
"primeng/progressspinner": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-progressspinner.mjs",
"file": "primeng_progressspinner.js",
"fileHash": "f063f0c5",
"needsInterop": false
},
"primeng/ripple": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-ripple.mjs",
"file": "primeng_ripple.js",
"fileHash": "97e2f125",
"needsInterop": false
},
"primeng/styleclass": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-styleclass.mjs",
"file": "primeng_styleclass.js",
"fileHash": "37c3b954",
"needsInterop": false
},
"primeng/table": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-table.mjs",
"file": "primeng_table.js",
"fileHash": "7aeb3809",
"needsInterop": false
},
"primeng/tabmenu": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-tabmenu.mjs",
"file": "primeng_tabmenu.js",
"fileHash": "19fb3789",
"needsInterop": false
},
"primeng/toast": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-toast.mjs",
"file": "primeng_toast.js",
"fileHash": "68ec89d2",
"needsInterop": false
},
"primeng/togglebutton": {
"src": "../../../../../node_modules/primeng/fesm2022/primeng-togglebutton.mjs",
"file": "primeng_togglebutton.js",
"fileHash": "522ccb3c",
"needsInterop": false
},
"rxjs": {
"src": "../../../../../node_modules/rxjs/dist/esm5/index.js",
"file": "rxjs.js",
"fileHash": "823e3e71",
"needsInterop": false
},
"rxjs/operators": {
"src": "../../../../../node_modules/rxjs/dist/esm5/operators/index.js",
"file": "rxjs_operators.js",
"fileHash": "b5e6296c",
"needsInterop": false
}
},
"chunks": {
"chunk-I7D7PQME": {
"file": "chunk-I7D7PQME.js"
},
"chunk-KMR4QVQU": {
"file": "chunk-KMR4QVQU.js"
},
"chunk-IU2G34K3": {
"file": "chunk-IU2G34K3.js"
},
"chunk-VYYSRRQP": {
"file": "chunk-VYYSRRQP.js"
},
"chunk-SRY2GXMH": {
"file": "chunk-SRY2GXMH.js"
},
"chunk-2HEVCKUT": {
"file": "chunk-2HEVCKUT.js"
},
"chunk-FLWDL4KY": {
"file": "chunk-FLWDL4KY.js"
},
"chunk-B3BEBK2H": {
"file": "chunk-B3BEBK2H.js"
},
"chunk-7NEKFKVF": {
"file": "chunk-7NEKFKVF.js"
},
"chunk-RKMPS52T": {
"file": "chunk-RKMPS52T.js"
},
"chunk-2QWPUIZJ": {
"file": "chunk-2QWPUIZJ.js"
},
"chunk-XGK4THRG": {
"file": "chunk-XGK4THRG.js"
},
"chunk-DFUOJE3F": {
"file": "chunk-DFUOJE3F.js"
},
"chunk-NBIWWQDH": {
"file": "chunk-NBIWWQDH.js"
},
"chunk-6M7HYOYM": {
"file": "chunk-6M7HYOYM.js"
},
"chunk-3SQF7L7O": {
"file": "chunk-3SQF7L7O.js"
},
"chunk-MI5BQO2G": {
"file": "chunk-MI5BQO2G.js"
},
"chunk-BH46VVEZ": {
"file": "chunk-BH46VVEZ.js"
},
"chunk-KAUMDUK6": {
"file": "chunk-KAUMDUK6.js"
},
"chunk-6ZBHNYAL": {
"file": "chunk-6ZBHNYAL.js"
},
"chunk-SLXWKEKP": {
"file": "chunk-SLXWKEKP.js"
},
"chunk-O5UWSVSE": {
"file": "chunk-O5UWSVSE.js"
},
"chunk-ESXUKNGR": {
"file": "chunk-ESXUKNGR.js"
},
"chunk-SVLVPO4L": {
"file": "chunk-SVLVPO4L.js"
},
"chunk-MDVT4WFW": {
"file": "chunk-MDVT4WFW.js"
},
"chunk-UANYWW5J": {
"file": "chunk-UANYWW5J.js"
},
"chunk-3Q7TKPWY": {
"file": "chunk-3Q7TKPWY.js"
},
"chunk-SG3BCSKH": {
"file": "chunk-SG3BCSKH.js"
},
"chunk-SAVXX6OM": {
"file": "chunk-SAVXX6OM.js"
},
"chunk-PQ7O3X3G": {
"file": "chunk-PQ7O3X3G.js"
},
"chunk-ASLTLD6L": {
"file": "chunk-ASLTLD6L.js"
}
}
}

View File

@ -0,0 +1,3 @@
{
"type": "module"
}

16
bizmatch/.editorconfig Normal file
View File

@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

45
bizmatch/.eslintrc.json Normal file
View File

@ -0,0 +1,45 @@
{
"env": {
"es2021": true,
"browser": true
},
"extends": [
"airbnb-base",
"airbnb-typescript",
"plugin:@typescript-eslint/recommended",
"eslint-config-prettier",
"plugin:cypress/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module",
"project": ["./tsconfig.json"]
},
"plugins": ["@typescript-eslint"],
"rules": {
"import/no-unresolved": ["off"],
"import/prefer-default-export": ["off"],
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": ["error"],
"@typescript-eslint/lines-between-class-members": ["off"],
"no-param-reassign": ["off"],
"max-classes-per-file": ["off"],
"no-shadow": ["off"],
"class-methods-use-this": ["off"],
"react/jsx-filename-extension": ["off"],
"import/no-cycle": ["off"],
"radix": ["off"],
"no-promise-executor-return": ["off"],
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "enumMember",
"format": ["UPPER_CASE", "PascalCase"]
}
],
"no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"],
"spaced-comment": ["off"],
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }]
}
}

4
bizmatch/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"]
}

20
bizmatch/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,20 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
}
]
}

42
bizmatch/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
},
{
"type": "npm",
"script": "test",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
}
]
}

27
bizmatch/README.md Normal file
View File

@ -0,0 +1,27 @@
# Bizmatch
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.1.2.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

116
bizmatch/angular.json Normal file
View File

@ -0,0 +1,116 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"bizmatch": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss",
"skipTests": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/bizmatch",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
},
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
],
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "bizmatch:build:production"
},
"development": {
"buildTarget": "bizmatch:build:development"
}
},
"defaultConfiguration": "development",
"options": {"proxyConfig": "proxy.conf.json"}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "bizmatch:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
},
"cli": {
"analytics": false
}
}

108
bizmatch/angular_copy.json Normal file
View File

@ -0,0 +1,108 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"bizmatch": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss",
"skipTests": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/bizmatch",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": [],
"server": "src/main.server.ts",
"prerender": true,
"ssr": {
"entry": "server.ts"
}
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "bizmatch:build:production"
},
"development": {
"buildTarget": "bizmatch:build:development"
}
},
"defaultConfiguration": "development",
"options": {"proxyConfig": "proxy.conf.json"}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "bizmatch:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
[
{
"id":"1",
"userId":"14a05316-cb85-4c67-86bc-4a2083ff6af7",
"listingsCategory": "business",
"title": "Industrial Service Company In Corpus Christi For Sale - 1954",
"summary": ["Asking price: $5,500,000","Sales revenue: $1,200,000","Net profit: $650,000"],
"description": ["This company services a wide variety of industries. Asking price includes Business and the Real Estate and is approx 30,000 sq ft with room for expansion including approx 5 acres. Absentee run business."],
"type": "Industrial Services",
"location": "Texas",
"price":5500000,
"salesRevenue":1200000,
"cashFlow":650000,
"brokerLicencing":"TREC Broker #516788",
"established":1954,
"realEstateIncluded":false,
"favoritesForUser":["e0811669-c7eb-4e5e-a699-e8334d5c5b01"]
},
{
"id":"2",
"userId":"e0811669-c7eb-4e5e-a699-e8334d5c5b01",
"listingsCategory": "business",
"title": "Coastal Bend Manufacturing Business Plastic Injection For Sale - 1950",
"summary": ["Asking price: $165,000","Sales revenue: Undisclosed","Net profit: Undisclosed"],
"description": [""],
"type": "Manufacturing",
"location": "Texas",
"price":165000,
"salesRevenue":null,
"cashFlow":null,
"brokerLicencing":"TREC Broker #516788",
"established":1950,
"realEstateIncluded":false,
"favoritesForUser":["828cc120-51e9-4baa-9a33-a82608fe66b4"]
},
{
"id":"3",
"userId":"e0811669-c7eb-4e5e-a699-e8334d5c5b01",
"listingsCategory": "business",
"title": "Corner Property On Everhart South-side Corpus Christi For Sale - 1944",
"summary": ["Asking price: $830,000","Sales revenue: Undisclosed","Net profit: Undisclosed"],
"description": [""],
"type": "Real Estate",
"location": "Texas",
"price":830000,
"salesRevenue":null,
"cashFlow":null,
"brokerLicencing":"TREC Broker #516788",
"established":1944,
"realEstateIncluded":false,
"favoritesForUser":[]
},
{
"id":"4",
"userId":"828cc120-51e9-4baa-9a33-a82608fe66b4",
"listingsCategory": "business",
"title": "Corpus Christi Dessert Business For Sale - 1941",
"summary": ["Asking price: $124,900","Sales revenue: $225,000","Net profit: $50,000"],
"description": [""],
"type": "Food and Restaurant",
"location": "Texas",
"price":830000,
"salesRevenue":225000,
"cashFlow":50000,
"brokerLicencing":"TREC Broker #516788",
"established":1941,
"realEstateIncluded":false,
"favoritesForUser":[]
}
]

View File

@ -0,0 +1,21 @@
{
"id":"1",
"firstname":"Andreas",
"lastname":"Knuth",
"email":"andreas.knuth@gmail.com",
"nickname":"aknuth",
"displayName":"Andreas Knuth",
"subscriptions":[{
"id":"1",
"level":"Business Broker",
"start":"2024-02-12T21:54:20.603Z",
"modified":"2024-02-12T21:54:20.603Z",
"end":"9999-02-12T21:54:20.603Z",
"status":"active",
"invoices":[{
"date":"2024-02-12T21:54:20.603Z",
"id":"C991853B99",
"price":0
}]
}]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,7 @@
<html>
<body>
<script>
parent.postMessage(location.href, location.origin);
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 48 KiB

Some files were not shown because too many files have changed in this diff Show More