cleanup + Property images
This commit is contained in:
1326
bizmatch-server/broker.json
Normal file
1326
bizmatch-server/broker.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
"drop": "drizzle-kit drop",
|
||||
"migrate": "tsx src/drizzle/migrate.ts",
|
||||
"import": "tsx src/drizzle/import.ts",
|
||||
"generateTypes":"tsx src/drizzle/generateTypes.ts src/drizzle/schema.ts src/models/db.model.ts"
|
||||
"generateTypes": "tsx src/drizzle/generateTypes.ts src/drizzle/schema.ts src/models/db.model.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs-modules/mailer": "^1.10.3",
|
||||
@@ -34,6 +34,7 @@
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/serve-static": "^4.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"drizzle-orm": "^0.30.8",
|
||||
"handlebars": "^4.7.8",
|
||||
@@ -80,6 +81,7 @@
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"kysely-codegen": "^0.15.0",
|
||||
"pg-to-ts": "^4.1.1",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^6.3.3",
|
||||
|
||||
@@ -31,7 +31,7 @@ const __dirname = path.dirname(__filename);
|
||||
@Module({
|
||||
imports: [ConfigModule.forRoot({isGlobal: true}), MailModule, AuthModule,
|
||||
ServeStaticModule.forRoot({
|
||||
rootPath: join(__dirname, '..', 'pictures'), // `public` ist das Verzeichnis, wo Ihre statischen Dateien liegen
|
||||
rootPath: join(__dirname, '../..', 'pictures'), // `public` ist das Verzeichnis, wo Ihre statischen Dateien liegen
|
||||
}),
|
||||
WinstonModule.forRoot({
|
||||
transports: [
|
||||
|
||||
@@ -25,8 +25,8 @@ const generatedUserData = []
|
||||
console.log(userData.length)
|
||||
for (const user of userData) {
|
||||
delete user.id
|
||||
user.licensedIn=user.licensedIn.map(l=>`${l['name']}|${l['value']}`)
|
||||
const u = await db.insert(schema.users).values(user).returning({ insertedId: schema.users.id });
|
||||
// console.log(`--> ${u[0].insertedId}`)
|
||||
generatedUserData.push(u[0].insertedId);
|
||||
}
|
||||
//Business Listings
|
||||
@@ -45,7 +45,10 @@ filePath = `./data/commercials.json`
|
||||
data = readFileSync(filePath, 'utf8');
|
||||
const commercialJsonData = JSON.parse(data) as CommercialPropertyListing[]; // Erwartet ein Array von Objekten
|
||||
for (const commercial of commercialJsonData) {
|
||||
const id = commercial.id;
|
||||
delete commercial.id
|
||||
commercial.imageOrder=['1.jpg'];
|
||||
commercial.imagePath=id
|
||||
commercial.created = getRandomDateWithinLastYear();
|
||||
commercial.userId = getRandomItem(generatedUserData);
|
||||
await db.insert(schema.commercials).values(commercial);
|
||||
|
||||
@@ -46,7 +46,7 @@ CREATE TABLE IF NOT EXISTS "commercials" (
|
||||
"website" varchar(255),
|
||||
"phoneNumber" varchar(255),
|
||||
"imageOrder" varchar(30)[],
|
||||
"imagePath" varchar(30)[],
|
||||
"imagePath" varchar(50),
|
||||
"created" timestamp,
|
||||
"updated" timestamp,
|
||||
"visits" integer,
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"id": "e8d0776a-ea8b-4c75-8a3a-e741620c4c4d",
|
||||
"id": "f6d421f9-2394-4a1c-9268-9e46285f0a41",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
@@ -300,7 +300,7 @@
|
||||
},
|
||||
"imagePath": {
|
||||
"name": "imagePath",
|
||||
"type": "varchar(30)[]",
|
||||
"type": "varchar(50)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1713791559934,
|
||||
"tag": "0000_safe_natasha_romanoff",
|
||||
"when": 1714913766996,
|
||||
"tag": "0000_third_spacker_dave",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -69,7 +69,7 @@ export const commercials = pgTable('commercials', {
|
||||
website: varchar('website', { length: 255 }),
|
||||
phoneNumber: varchar('phoneNumber', { length: 255 }),
|
||||
imageOrder:varchar('imageOrder',{length:30}).array(),
|
||||
imagePath:varchar('imagePath',{length:30}).array(),
|
||||
imagePath:varchar('imagePath',{length:50}),
|
||||
created: timestamp('created'),
|
||||
updated: timestamp('updated'),
|
||||
visits: integer('visits'),
|
||||
|
||||
@@ -56,14 +56,13 @@ export class FileService {
|
||||
return fs.existsSync(`./pictures/logo/${userId}.avif`)?true:false
|
||||
}
|
||||
|
||||
async getPropertyImages(listingId: string): Promise<ImageProperty[]> {
|
||||
const result: ImageProperty[] = []
|
||||
async getPropertyImages(listingId: string): Promise<string[]> {
|
||||
const result: string[] = []
|
||||
const directory = `./pictures/property/${listingId}`
|
||||
if (fs.existsSync(directory)) {
|
||||
const files = await fs.readdir(directory);
|
||||
files.forEach(f => {
|
||||
const image: ImageProperty = { name: f, id: '', code: '' };
|
||||
result.push(image)
|
||||
result.push(f)
|
||||
})
|
||||
return result;
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,8 @@ import { SelectOptionsService } from '../select-options/select-options.service.j
|
||||
import { ListingsService } from '../listings/listings.service.js';
|
||||
|
||||
import { Entity, EntityData } from 'redis-om';
|
||||
import { businesses, commercials } from 'src/drizzle/schema.js';
|
||||
import { CommercialPropertyListing } from 'src/models/db.model.js';
|
||||
|
||||
@Controller('image')
|
||||
export class ImageController {
|
||||
@@ -38,16 +40,16 @@ export class ImageController {
|
||||
|
||||
@Get(':id')
|
||||
async getPropertyImagesById(@Param('id') id:string): Promise<any> {
|
||||
// const result = await this.listingService.getCommercialPropertyListingById(id);
|
||||
// const listing = result as CommercialPropertyListing;
|
||||
// if (listing.imageOrder){
|
||||
// return listing.imageOrder
|
||||
// } else {
|
||||
// const imageOrder = await this.fileService.getPropertyImages(id);
|
||||
// listing.imageOrder=imageOrder;
|
||||
// this.listingService.saveListing(listing);
|
||||
// return imageOrder;
|
||||
// }
|
||||
const result = await this.listingService.findById(id,commercials);
|
||||
const listing = result as CommercialPropertyListing;
|
||||
if (listing.imageOrder){
|
||||
return listing.imageOrder
|
||||
} else {
|
||||
const imageOrder = await this.fileService.getPropertyImages(id);
|
||||
listing.imageOrder=imageOrder;
|
||||
this.listingService.updateListing(listing.id,listing,commercials);
|
||||
return imageOrder;
|
||||
}
|
||||
}
|
||||
@Get('profileImages/:userids')
|
||||
async getProfileImagesForUsers(@Param('userids') userids:string): Promise<any> {
|
||||
|
||||
@@ -42,6 +42,9 @@ export class BusinessListingsController {
|
||||
deleteById(@Param('id') id:string){
|
||||
this.listingsService.deleteListing(id,businesses)
|
||||
}
|
||||
|
||||
@Get('states/all')
|
||||
getStates(): any {
|
||||
return this.listingsService.getStates(businesses);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,9 @@ export class ListingsService {
|
||||
async deleteListing(id: string, table: typeof businesses | typeof commercials): Promise<void> {
|
||||
await this.conn.delete(table).where(eq(table.id, id));
|
||||
}
|
||||
|
||||
async getStates(table: typeof businesses | typeof commercials): Promise<any[]> {
|
||||
return await this.conn.select({state: table.state,count: sql<number>`count(${table.id})`.mapWith(Number)}).from(table).groupBy(sql`${table.state}`).orderBy(sql`count desc`);
|
||||
}
|
||||
// ##############################################################
|
||||
// Images for commercial Properties
|
||||
// ##############################################################
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module.js';
|
||||
|
||||
import * as express from 'express';
|
||||
import path, { join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
app.setGlobalPrefix('bizmatch');
|
||||
|
||||
@@ -64,10 +64,9 @@ export interface CommercialPropertyListing {
|
||||
website?: string;
|
||||
phoneNumber?: string;
|
||||
imageOrder?: string[];
|
||||
imagePath?: string[];
|
||||
imagePath?: string;
|
||||
created?: Date;
|
||||
updated?: Date;
|
||||
visits?: number;
|
||||
lastVisit?: Date;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,155 +1,163 @@
|
||||
import { BusinessListing, CommercialPropertyListing } from "./db.model";
|
||||
import { BusinessListing, CommercialPropertyListing, User } from './db.model';
|
||||
|
||||
export interface StatesResult {
|
||||
state: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface KeyValue {
|
||||
name: string;
|
||||
value: string;
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
export interface KeyValueRatio {
|
||||
label: string;
|
||||
value: number;
|
||||
label: string;
|
||||
value: number;
|
||||
}
|
||||
export interface KeyValueStyle {
|
||||
name: string;
|
||||
value: string;
|
||||
icon:string;
|
||||
bgColorClass:string;
|
||||
textColorClass:string;
|
||||
name: string;
|
||||
value: string;
|
||||
icon: string;
|
||||
bgColorClass: string;
|
||||
textColorClass: string;
|
||||
}
|
||||
export type SelectOption<T = number> = {
|
||||
value: T;
|
||||
label: string;
|
||||
value: T;
|
||||
label: string;
|
||||
};
|
||||
export type ImageType = {
|
||||
name:'propertyPicture'|'companyLogo'|'profile',upload:string,delete:string,
|
||||
}
|
||||
name: 'propertyPicture' | 'companyLogo' | 'profile';
|
||||
upload: string;
|
||||
delete: string;
|
||||
};
|
||||
export type ListingCategory = {
|
||||
name: 'business' | 'commercialProperty'
|
||||
}
|
||||
name: 'business' | 'commercialProperty';
|
||||
};
|
||||
|
||||
export type ListingType =
|
||||
| BusinessListing
|
||||
| CommercialPropertyListing;
|
||||
export type ListingType = BusinessListing | CommercialPropertyListing;
|
||||
|
||||
export type ResponseBusinessListingArray = {
|
||||
data:BusinessListing[],
|
||||
total:number
|
||||
}
|
||||
data: BusinessListing[];
|
||||
total: number;
|
||||
};
|
||||
export type ResponseBusinessListing = {
|
||||
data:BusinessListing
|
||||
}
|
||||
data: BusinessListing;
|
||||
};
|
||||
export type ResponseCommercialPropertyListingArray = {
|
||||
data:CommercialPropertyListing[],
|
||||
total:number
|
||||
}
|
||||
data: CommercialPropertyListing[];
|
||||
total: number;
|
||||
};
|
||||
export type ResponseCommercialPropertyListing = {
|
||||
data:CommercialPropertyListing
|
||||
}
|
||||
data: CommercialPropertyListing;
|
||||
};
|
||||
export type ResponseUsersArray = {
|
||||
data: User[];
|
||||
total: number;
|
||||
};
|
||||
export interface ListingCriteria {
|
||||
start:number,
|
||||
length:number,
|
||||
page:number,
|
||||
pageCount:number,
|
||||
type:number,
|
||||
state:string,
|
||||
minPrice:number,
|
||||
maxPrice:number,
|
||||
realEstateChecked:boolean,
|
||||
title:string,
|
||||
category:'professional|broker'
|
||||
start: number;
|
||||
length: number;
|
||||
page: number;
|
||||
pageCount: number;
|
||||
type: number;
|
||||
state: string;
|
||||
minPrice: number;
|
||||
maxPrice: number;
|
||||
realEstateChecked: boolean;
|
||||
title: string;
|
||||
category: 'professional|broker';
|
||||
}
|
||||
|
||||
export interface KeycloakUser {
|
||||
id: string
|
||||
createdTimestamp: number
|
||||
username: string
|
||||
enabled: boolean
|
||||
totp: boolean
|
||||
emailVerified: boolean
|
||||
firstName: string
|
||||
lastName: string
|
||||
email: string
|
||||
disableableCredentialTypes: any[]
|
||||
requiredActions: any[]
|
||||
notBefore: number
|
||||
access: Access
|
||||
id: string;
|
||||
createdTimestamp: number;
|
||||
username: string;
|
||||
enabled: boolean;
|
||||
totp: boolean;
|
||||
emailVerified: boolean;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
disableableCredentialTypes: any[];
|
||||
requiredActions: any[];
|
||||
notBefore: number;
|
||||
access: Access;
|
||||
}
|
||||
export interface Access {
|
||||
manageGroupMembership: boolean
|
||||
view: boolean
|
||||
mapRoles: boolean
|
||||
impersonate: boolean
|
||||
manage: boolean
|
||||
}
|
||||
manageGroupMembership: boolean;
|
||||
view: boolean;
|
||||
mapRoles: boolean;
|
||||
impersonate: boolean;
|
||||
manage: boolean;
|
||||
}
|
||||
export interface Subscription {
|
||||
id: string;
|
||||
userId:string
|
||||
level: string;
|
||||
start: Date;
|
||||
modified: Date;
|
||||
end: Date;
|
||||
status: string;
|
||||
invoices: Array<Invoice>;
|
||||
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
|
||||
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;
|
||||
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;
|
||||
account: Realmaccess;
|
||||
}
|
||||
interface Realmaccess {
|
||||
roles: string[];
|
||||
roles: string[];
|
||||
}
|
||||
export interface PageEvent {
|
||||
first: number;
|
||||
rows: number;
|
||||
page: number;
|
||||
pageCount: number;
|
||||
first: number;
|
||||
rows: number;
|
||||
page: number;
|
||||
pageCount: number;
|
||||
}
|
||||
export interface AutoCompleteCompleteEvent {
|
||||
originalEvent: Event;
|
||||
query: string;
|
||||
originalEvent: Event;
|
||||
query: string;
|
||||
}
|
||||
export interface MailInfo {
|
||||
sender: Sender;
|
||||
userId: string;
|
||||
}
|
||||
export interface Sender {
|
||||
name?: string;
|
||||
email?: string;
|
||||
phoneNumber?: string;
|
||||
state?: string;
|
||||
comments?: string;
|
||||
}
|
||||
export interface ImageProperty {
|
||||
id:string;
|
||||
code:string;
|
||||
name:string;
|
||||
}
|
||||
sender: Sender;
|
||||
userId: string;
|
||||
}
|
||||
export interface Sender {
|
||||
name?: string;
|
||||
email?: string;
|
||||
phoneNumber?: string;
|
||||
state?: string;
|
||||
comments?: string;
|
||||
}
|
||||
export interface ImageProperty {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@@ -51,8 +51,11 @@ export class UserService {
|
||||
const start = criteria.start ? criteria.start : 0;
|
||||
const length = criteria.length ? criteria.length : 12;
|
||||
const conditions = this.getConditions(criteria)
|
||||
const users = await this.conn.select().from(schema.users).where(and(...conditions)).offset(start).limit(length)
|
||||
return users
|
||||
const [data, total] = await Promise.all([
|
||||
this.conn.select().from(schema.users).where(and(...conditions)).offset(start).limit(length),
|
||||
this.conn.select({ count: sql`count(*)` }).from(schema.users).where(and(...conditions)).then((result) => Number(result[0].count)),
|
||||
]);
|
||||
return { total, data };
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user