validatedCity, mask for input, confirmatonService, Version Info,
This commit is contained in:
@@ -114,4 +114,4 @@
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
119805
bizmatch-server/src/assets/geo1.json
Normal file
119805
bizmatch-server/src/assets/geo1.json
Normal file
File diff suppressed because it is too large
Load Diff
119811
bizmatch-server/src/assets/geo_.json
Normal file
119811
bizmatch-server/src/assets/geo_.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,14 @@ import { join } from 'path';
|
||||
import pkg from 'pg';
|
||||
import { rimraf } from 'rimraf';
|
||||
import sharp from 'sharp';
|
||||
import { Geo } from 'src/models/server.model.js';
|
||||
import winston from 'winston';
|
||||
import { BusinessListing, CommercialPropertyListing, User, UserData } from '../models/db.model.js';
|
||||
import { createDefaultUser, emailToDirName, KeyValueStyle } from '../models/main.model.js';
|
||||
import { SelectOptionsService } from '../select-options/select-options.service.js';
|
||||
import { toDrizzleUser } from '../utils.js';
|
||||
import { convertUserToDrizzleUser } from '../utils.js';
|
||||
import * as schema from './schema.js';
|
||||
|
||||
const typesOfBusiness: Array<KeyValueStyle> = [
|
||||
{ name: 'Automotive', value: '1', icon: 'fa-solid fa-car', textColorClass: 'text-green-400' },
|
||||
{ name: 'Industrial Services', value: '2', icon: 'fa-solid fa-industry', textColorClass: 'text-yellow-400' },
|
||||
@@ -47,7 +49,7 @@ await db.delete(schema.businesses);
|
||||
await db.delete(schema.users);
|
||||
let filePath = `./src/assets/geo.json`;
|
||||
const rawData = readFileSync(filePath, 'utf8');
|
||||
const geos = JSON.parse(rawData);
|
||||
const geos = JSON.parse(rawData) as Geo;
|
||||
|
||||
const sso = new SelectOptionsService();
|
||||
//Broker
|
||||
@@ -94,28 +96,22 @@ for (let index = 0; index < usersData.length; index++) {
|
||||
user.companyName = userData.companyName;
|
||||
user.companyOverview = userData.companyOverview;
|
||||
user.companyWebsite = userData.companyWebsite;
|
||||
user.companyLocation = userData.companyLocation;
|
||||
const [city, state] = user.companyLocation.split('-').map(e => e.trim());
|
||||
const [city, state] = userData.companyLocation.split('-').map(e => e.trim());
|
||||
user.companyLocation.city = city;
|
||||
user.companyLocation.state = state;
|
||||
const cityGeo = geos.states.find(s => s.state_code === state).cities.find(c => c.name === city);
|
||||
user.latitude = cityGeo.latitude;
|
||||
user.longitude = cityGeo.longitude;
|
||||
user.companyLocation.latitude = cityGeo.latitude;
|
||||
user.companyLocation.longitude = cityGeo.longitude;
|
||||
user.offeredServices = userData.offeredServices;
|
||||
user.gender = userData.gender;
|
||||
user.customerType = 'professional';
|
||||
user.customerSubType = 'broker';
|
||||
user.created = new Date();
|
||||
user.updated = new Date();
|
||||
// const createUserProfile = (user: User): UserProfile => {
|
||||
// const { id, created, updated, hasCompanyLogo, hasProfile, ...userProfile } = user;
|
||||
// return userProfile;
|
||||
// };
|
||||
// const userProfile = createUserProfile(user);
|
||||
// logger.info(`${index} - ${JSON.stringify(userProfile)}`);
|
||||
// const embedding = await createEmbedding(JSON.stringify(userProfile));
|
||||
//sleep(200);
|
||||
|
||||
const u = await db
|
||||
.insert(schema.users)
|
||||
.values(toDrizzleUser(user))
|
||||
.values(convertUserToDrizzleUser(user))
|
||||
.returning({ insertedId: schema.users.id, gender: schema.users.gender, email: schema.users.email, firstname: schema.users.firstname, lastname: schema.users.lastname });
|
||||
generatedUserData.push(u[0]);
|
||||
i++;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE "users" ADD COLUMN "city" varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE "users" ADD COLUMN "state" char(2);--> statement-breakpoint
|
||||
ALTER TABLE "users" DROP COLUMN IF EXISTS "companyLocation";
|
||||
589
bizmatch-server/src/drizzle/migrations/meta/0003_snapshot.json
Normal file
589
bizmatch-server/src/drizzle/migrations/meta/0003_snapshot.json
Normal file
@@ -0,0 +1,589 @@
|
||||
{
|
||||
"id": "1d2566aa-6103-4520-a648-c0abdda08189",
|
||||
"prevId": "146c197a-0ef7-4b10-84cd-352b88aba859",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.businesses": {
|
||||
"name": "businesses",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"city": {
|
||||
"name": "city",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"state": {
|
||||
"name": "state",
|
||||
"type": "char(2)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"zipCode": {
|
||||
"name": "zipCode",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"county": {
|
||||
"name": "county",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"price": {
|
||||
"name": "price",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"favoritesForUser": {
|
||||
"name": "favoritesForUser",
|
||||
"type": "varchar(30)[]",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"draft": {
|
||||
"name": "draft",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"listingsCategory": {
|
||||
"name": "listingsCategory",
|
||||
"type": "listingsCategory",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"realEstateIncluded": {
|
||||
"name": "realEstateIncluded",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"leasedLocation": {
|
||||
"name": "leasedLocation",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"franchiseResale": {
|
||||
"name": "franchiseResale",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"salesRevenue": {
|
||||
"name": "salesRevenue",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"cashFlow": {
|
||||
"name": "cashFlow",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"supportAndTraining": {
|
||||
"name": "supportAndTraining",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"employees": {
|
||||
"name": "employees",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"established": {
|
||||
"name": "established",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"internalListingNumber": {
|
||||
"name": "internalListingNumber",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"reasonForSale": {
|
||||
"name": "reasonForSale",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"brokerLicencing": {
|
||||
"name": "brokerLicencing",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"internals": {
|
||||
"name": "internals",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"imageName": {
|
||||
"name": "imageName",
|
||||
"type": "varchar(200)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created": {
|
||||
"name": "created",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"updated": {
|
||||
"name": "updated",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"visits": {
|
||||
"name": "visits",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"lastVisit": {
|
||||
"name": "lastVisit",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"latitude": {
|
||||
"name": "latitude",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"longitude": {
|
||||
"name": "longitude",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"businesses_email_users_email_fk": {
|
||||
"name": "businesses_email_users_email_fk",
|
||||
"tableFrom": "businesses",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"email"
|
||||
],
|
||||
"columnsTo": [
|
||||
"email"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"public.commercials": {
|
||||
"name": "commercials",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"serialId": {
|
||||
"name": "serialId",
|
||||
"type": "serial",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"city": {
|
||||
"name": "city",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"state": {
|
||||
"name": "state",
|
||||
"type": "char(2)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"price": {
|
||||
"name": "price",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"favoritesForUser": {
|
||||
"name": "favoritesForUser",
|
||||
"type": "varchar(30)[]",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"listingsCategory": {
|
||||
"name": "listingsCategory",
|
||||
"type": "listingsCategory",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"draft": {
|
||||
"name": "draft",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"zipCode": {
|
||||
"name": "zipCode",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"county": {
|
||||
"name": "county",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"imageOrder": {
|
||||
"name": "imageOrder",
|
||||
"type": "varchar(200)[]",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"imagePath": {
|
||||
"name": "imagePath",
|
||||
"type": "varchar(200)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created": {
|
||||
"name": "created",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"updated": {
|
||||
"name": "updated",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"visits": {
|
||||
"name": "visits",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"lastVisit": {
|
||||
"name": "lastVisit",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"latitude": {
|
||||
"name": "latitude",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"longitude": {
|
||||
"name": "longitude",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"commercials_email_users_email_fk": {
|
||||
"name": "commercials_email_users_email_fk",
|
||||
"tableFrom": "commercials",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"email"
|
||||
],
|
||||
"columnsTo": [
|
||||
"email"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"firstname": {
|
||||
"name": "firstname",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"lastname": {
|
||||
"name": "lastname",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"phoneNumber": {
|
||||
"name": "phoneNumber",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"companyName": {
|
||||
"name": "companyName",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"companyOverview": {
|
||||
"name": "companyOverview",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"companyWebsite": {
|
||||
"name": "companyWebsite",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"city": {
|
||||
"name": "city",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"state": {
|
||||
"name": "state",
|
||||
"type": "char(2)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"offeredServices": {
|
||||
"name": "offeredServices",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"areasServed": {
|
||||
"name": "areasServed",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"hasProfile": {
|
||||
"name": "hasProfile",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"hasCompanyLogo": {
|
||||
"name": "hasCompanyLogo",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"licensedIn": {
|
||||
"name": "licensedIn",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"gender": {
|
||||
"name": "gender",
|
||||
"type": "gender",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"customerType": {
|
||||
"name": "customerType",
|
||||
"type": "customerType",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"customerSubType": {
|
||||
"name": "customerSubType",
|
||||
"type": "customerSubType",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created": {
|
||||
"name": "created",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"updated": {
|
||||
"name": "updated",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"latitude": {
|
||||
"name": "latitude",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"longitude": {
|
||||
"name": "longitude",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"public.customerSubType": {
|
||||
"name": "customerSubType",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"broker",
|
||||
"cpa",
|
||||
"attorney",
|
||||
"titleCompany",
|
||||
"surveyor",
|
||||
"appraiser"
|
||||
]
|
||||
},
|
||||
"public.customerType": {
|
||||
"name": "customerType",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"buyer",
|
||||
"professional"
|
||||
]
|
||||
},
|
||||
"public.gender": {
|
||||
"name": "gender",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"male",
|
||||
"female"
|
||||
]
|
||||
},
|
||||
"public.listingsCategory": {
|
||||
"name": "listingsCategory",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"commercialProperty",
|
||||
"business"
|
||||
]
|
||||
}
|
||||
},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,13 @@
|
||||
"when": 1722853523826,
|
||||
"tag": "0002_chemical_gambit",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1722964164111,
|
||||
"tag": "0003_robust_blockbuster",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,7 +7,7 @@ export const customerSubTypeEnum = pgEnum('customerSubType', ['broker', 'cpa', '
|
||||
export const listingsCategoryEnum = pgEnum('listingsCategory', ['commercialProperty', 'business']);
|
||||
|
||||
export const users = pgTable('users', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
id: uuid('id').primaryKey().defaultRandom().notNull(),
|
||||
firstname: varchar('firstname', { length: 255 }).notNull(),
|
||||
lastname: varchar('lastname', { length: 255 }).notNull(),
|
||||
email: varchar('email', { length: 255 }).notNull().unique(),
|
||||
@@ -16,7 +16,8 @@ export const users = pgTable('users', {
|
||||
companyName: varchar('companyName', { length: 255 }),
|
||||
companyOverview: text('companyOverview'),
|
||||
companyWebsite: varchar('companyWebsite', { length: 255 }),
|
||||
companyLocation: varchar('companyLocation', { length: 255 }),
|
||||
city: varchar('city', { length: 255 }),
|
||||
state: char('state', { length: 2 }),
|
||||
offeredServices: text('offeredServices'),
|
||||
areasServed: jsonb('areasServed').$type<AreasServed[]>(),
|
||||
hasProfile: boolean('hasProfile'),
|
||||
@@ -33,7 +34,7 @@ export const users = pgTable('users', {
|
||||
});
|
||||
|
||||
export const businesses = pgTable('businesses', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
id: uuid('id').primaryKey().defaultRandom().notNull(),
|
||||
email: varchar('email', { length: 255 }).references(() => users.email),
|
||||
type: varchar('type', { length: 255 }),
|
||||
title: varchar('title', { length: 255 }),
|
||||
@@ -69,7 +70,7 @@ export const businesses = pgTable('businesses', {
|
||||
});
|
||||
|
||||
export const commercials = pgTable('commercials', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
id: uuid('id').primaryKey().defaultRandom().notNull(),
|
||||
serialId: serial('serialId'),
|
||||
email: varchar('email', { length: 255 }).references(() => users.email),
|
||||
type: varchar('type', { length: 255 }),
|
||||
|
||||
@@ -53,16 +53,18 @@ export class GeoService {
|
||||
result.push({
|
||||
id: city.id,
|
||||
city: city.name,
|
||||
state: state.name,
|
||||
state_code: state.state_code,
|
||||
state: state.state_code,
|
||||
//state_code: state.state_code,
|
||||
latitude: city.latitude,
|
||||
longitude: city.longitude,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return state ? result.filter(e => e.state_code.toLowerCase() === state.toLowerCase()) : result;
|
||||
return state ? result.filter(e => e.state.toLowerCase() === state.toLowerCase()) : result;
|
||||
}
|
||||
findCitiesAndStatesStartingWith(prefix: string, state?: string): Array<{ id: string; name: string; type: 'city' | 'state'; state_code: string }> {
|
||||
const results: Array<{ id: string; name: string; type: 'city' | 'state'; state_code: string }> = [];
|
||||
findCitiesAndStatesStartingWith(prefix: string, state?: string): Array<{ id: string; name: string; type: 'city' | 'state'; state: string }> {
|
||||
const results: Array<{ id: string; name: string; type: 'city' | 'state'; state: string }> = [];
|
||||
|
||||
const lowercasePrefix = prefix.toLowerCase();
|
||||
|
||||
@@ -74,7 +76,7 @@ export class GeoService {
|
||||
id: state.id.toString(),
|
||||
name: state.name,
|
||||
type: 'state',
|
||||
state_code: state.state_code,
|
||||
state: state.state_code,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ export class GeoService {
|
||||
id: city.id.toString(),
|
||||
name: city.name,
|
||||
type: 'city',
|
||||
state_code: state.state_code,
|
||||
state: state.state_code,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export class BusinessListingService {
|
||||
}
|
||||
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
|
||||
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city);
|
||||
whereConditions.push(sql`${getDistanceQuery(businesses, parseFloat(cityGeo.latitude), parseFloat(cityGeo.longitude))} <= ${criteria.radius}`);
|
||||
whereConditions.push(sql`${getDistanceQuery(businesses, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
|
||||
}
|
||||
if (criteria.types && criteria.types.length > 0) {
|
||||
whereConditions.push(inArray(businesses.type, criteria.types));
|
||||
|
||||
@@ -28,7 +28,7 @@ export class CommercialPropertyService {
|
||||
}
|
||||
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
|
||||
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city);
|
||||
whereConditions.push(sql`${getDistanceQuery(commercials, parseFloat(cityGeo.latitude), parseFloat(cityGeo.longitude))} <= ${criteria.radius}`);
|
||||
whereConditions.push(sql`${getDistanceQuery(commercials, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
|
||||
}
|
||||
if (criteria.types && criteria.types.length > 0) {
|
||||
whereConditions.push(inArray(schema.commercials.type, criteria.types));
|
||||
|
||||
@@ -109,8 +109,27 @@ export const LicensedInSchema = z.object({
|
||||
registerNo: z.string().nonempty('Registration number is required'),
|
||||
state: z.string().nonempty('State is required'),
|
||||
});
|
||||
|
||||
const phoneRegex = /^\+1 \(\d{3}\) \d{3}-\d{4}$/;
|
||||
export const GeoSchema = z.object({
|
||||
city: z.string(),
|
||||
state: z.string(),
|
||||
latitude: z.number().refine(
|
||||
value => {
|
||||
return value >= -90 && value <= 90;
|
||||
},
|
||||
{
|
||||
message: 'Latitude muss zwischen -90 und 90 liegen',
|
||||
},
|
||||
),
|
||||
longitude: z.number().refine(
|
||||
value => {
|
||||
return value >= -180 && value <= 180;
|
||||
},
|
||||
{
|
||||
message: 'Longitude muss zwischen -180 und 180 liegen',
|
||||
},
|
||||
),
|
||||
});
|
||||
const phoneRegex = /^\(\d{3}\)\s\d{3}-\d{4}$/;
|
||||
|
||||
export const UserSchema = z
|
||||
.object({
|
||||
@@ -123,7 +142,7 @@ export const UserSchema = z
|
||||
companyName: z.string().optional().nullable(),
|
||||
companyOverview: z.string().optional().nullable(),
|
||||
companyWebsite: z.string().url({ message: 'Invalid URL format' }).optional().nullable(),
|
||||
companyLocation: z.string().optional().nullable(),
|
||||
companyLocation: GeoSchema,
|
||||
offeredServices: z.string().optional().nullable(),
|
||||
areasServed: z.array(AreasServedSchema).optional().nullable(),
|
||||
hasProfile: z.boolean().optional().nullable(),
|
||||
@@ -134,8 +153,6 @@ export const UserSchema = z
|
||||
customerSubType: CustomerSubTypeEnum.optional().nullable(),
|
||||
created: z.date().optional().nullable(),
|
||||
updated: z.date().optional().nullable(),
|
||||
latitude: z.number().optional().nullable(),
|
||||
longitude: z.number().optional().nullable(),
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (data.customerType === 'professional') {
|
||||
@@ -150,7 +167,7 @@ export const UserSchema = z
|
||||
if (!data.phoneNumber || !phoneRegex.test(data.phoneNumber)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Phone number is required and must be in US format (+1 (XXX) XXX-XXXX) for professional customers',
|
||||
message: 'Phone number is required and must be in US format (XXX) XXX-XXXX for professional customers',
|
||||
path: ['phoneNumber'],
|
||||
});
|
||||
}
|
||||
@@ -236,8 +253,22 @@ export const BusinessListingSchema = z.object({
|
||||
updated: z.date(),
|
||||
visits: z.number().int().positive().optional().nullable(),
|
||||
lastVisit: z.date().optional().nullable(),
|
||||
latitude: z.number().optional().nullable(),
|
||||
longitude: z.number().optional().nullable(),
|
||||
latitude: z.number().refine(
|
||||
value => {
|
||||
return value >= -90 && value <= 90;
|
||||
},
|
||||
{
|
||||
message: 'Latitude muss zwischen -90 und 90 liegen',
|
||||
},
|
||||
),
|
||||
longitude: z.number().refine(
|
||||
value => {
|
||||
return value >= -180 && value <= 180;
|
||||
},
|
||||
{
|
||||
message: 'Longitude muss zwischen -180 und 180 liegen',
|
||||
},
|
||||
),
|
||||
});
|
||||
export type BusinessListing = z.infer<typeof BusinessListingSchema>;
|
||||
|
||||
@@ -268,8 +299,22 @@ export const CommercialPropertyListingSchema = z
|
||||
updated: z.date(),
|
||||
visits: z.number().int().positive().nullable().optional(),
|
||||
lastVisit: z.date().nullable().optional(),
|
||||
latitude: z.number().nullable().optional(),
|
||||
longitude: z.number().nullable().optional(),
|
||||
latitude: z.number().refine(
|
||||
value => {
|
||||
return value >= -90 && value <= 90;
|
||||
},
|
||||
{
|
||||
message: 'Latitude muss zwischen -90 und 90 liegen',
|
||||
},
|
||||
),
|
||||
longitude: z.number().refine(
|
||||
value => {
|
||||
return value >= -180 && value <= 180;
|
||||
},
|
||||
{
|
||||
message: 'Longitude muss zwischen -180 und 180 liegen',
|
||||
},
|
||||
),
|
||||
})
|
||||
.strict();
|
||||
|
||||
|
||||
@@ -228,13 +228,15 @@ export interface GeoResult {
|
||||
id: number;
|
||||
city: string;
|
||||
state: string;
|
||||
state_code: string;
|
||||
// state_code: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
export interface CityAndStateResult {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
state_code: string;
|
||||
state: string;
|
||||
}
|
||||
export interface CountyResult {
|
||||
id: number;
|
||||
|
||||
@@ -18,8 +18,8 @@ export interface Geo {
|
||||
nationality: string;
|
||||
timezones: Timezone[];
|
||||
translations: Translations;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
emoji: string;
|
||||
emojiU: string;
|
||||
states: State[];
|
||||
@@ -28,16 +28,16 @@ export interface State {
|
||||
id: number;
|
||||
name: string;
|
||||
state_code: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
type: string;
|
||||
cities: City[];
|
||||
}
|
||||
export interface City {
|
||||
id: number;
|
||||
name: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
export interface Translations {
|
||||
kr: string;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { FileService } from '../file/file.service.js';
|
||||
import { GeoService } from '../geo/geo.service.js';
|
||||
import { User, UserSchema } from '../models/db.model.js';
|
||||
import { createDefaultUser, emailToDirName, JwtUser, UserListingCriteria } from '../models/main.model.js';
|
||||
import { getDistanceQuery, toDrizzleUser } from '../utils.js';
|
||||
import { convertDrizzleUserToUser, convertUserToDrizzleUser, getDistanceQuery } from '../utils.js';
|
||||
|
||||
type CustomerSubType = (typeof customerSubTypeEnum.enumValues)[number];
|
||||
@Injectable()
|
||||
@@ -26,11 +26,11 @@ export class UserService {
|
||||
const whereConditions: SQL[] = [];
|
||||
whereConditions.push(eq(schema.users.customerType, 'professional'));
|
||||
if (criteria.city && criteria.searchType === 'exact') {
|
||||
whereConditions.push(ilike(schema.users.companyLocation, `%${criteria.city}%`));
|
||||
whereConditions.push(ilike(schema.users.city, `%${criteria.city}%`));
|
||||
}
|
||||
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
|
||||
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city);
|
||||
whereConditions.push(sql`${getDistanceQuery(schema.users, parseFloat(cityGeo.latitude), parseFloat(cityGeo.longitude))} <= ${criteria.radius}`);
|
||||
whereConditions.push(sql`${getDistanceQuery(schema.users, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
|
||||
}
|
||||
if (criteria.types && criteria.types.length > 0) {
|
||||
// whereConditions.push(inArray(schema.users.customerSubType, criteria.types));
|
||||
@@ -99,12 +99,13 @@ export class UserService {
|
||||
.where(sql`email = ${email}`)) as User[];
|
||||
if (users.length === 0) {
|
||||
const user: User = { id: undefined, customerType: 'buyer', ...createDefaultUser(email, jwtuser.firstname, jwtuser.lastname) };
|
||||
return await this.saveUser(user);
|
||||
const u = await this.saveUser(user);
|
||||
return convertDrizzleUserToUser(u);
|
||||
} else {
|
||||
const user = users[0];
|
||||
user.hasCompanyLogo = this.fileService.hasCompanyLogo(emailToDirName(user.email));
|
||||
user.hasProfile = this.fileService.hasProfile(emailToDirName(user.email));
|
||||
return user;
|
||||
return convertDrizzleUserToUser(user);
|
||||
}
|
||||
}
|
||||
async getUserById(id: string) {
|
||||
@@ -127,14 +128,13 @@ export class UserService {
|
||||
user.created = new Date();
|
||||
}
|
||||
const validatedUser = UserSchema.parse(user);
|
||||
const drizzleUser = toDrizzleUser(validatedUser);
|
||||
const drizzleUser = convertUserToDrizzleUser(validatedUser);
|
||||
if (user.id) {
|
||||
const [updateUser] = await this.conn.update(schema.users).set(drizzleUser).where(eq(schema.users.id, user.id)).returning();
|
||||
return updateUser as User;
|
||||
} else {
|
||||
const drizzleUser = toDrizzleUser(user);
|
||||
const [newUser] = await this.conn.insert(schema.users).values(drizzleUser).returning();
|
||||
return newUser as User;
|
||||
return convertDrizzleUserToUser(newUser) as User;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { sql } from 'drizzle-orm';
|
||||
import { z } from 'zod';
|
||||
import { businesses, commercials, users } from './drizzle/schema.js';
|
||||
import { AreasServedSchema, CustomerSubTypeEnum, CustomerTypeEnum, GenderEnum, LicensedInSchema, User } from './models/db.model.js';
|
||||
import { User } from './models/db.model.js';
|
||||
export const EARTH_RADIUS_KM = 6371; // Erdradius in Kilometern
|
||||
export const EARTH_RADIUS_MILES = 3959; // Erdradius in Meilen
|
||||
|
||||
export function convertStringToNullUndefined(value) {
|
||||
// Konvertiert den Wert zu Kleinbuchstaben für eine case-insensitive Überprüfung
|
||||
const lowerCaseValue = typeof value === 'boolean' ? value : value?.toLowerCase();
|
||||
@@ -31,32 +29,70 @@ export const getDistanceQuery = (schema: typeof businesses | typeof commercials
|
||||
`;
|
||||
};
|
||||
|
||||
export function toDrizzleUser(user: User): {
|
||||
email: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
phoneNumber?: string;
|
||||
description?: string;
|
||||
companyName?: string;
|
||||
companyOverview?: string;
|
||||
companyWebsite?: string;
|
||||
companyLocation?: string;
|
||||
offeredServices?: string;
|
||||
areasServed?: (typeof AreasServedSchema._type)[];
|
||||
hasProfile?: boolean;
|
||||
hasCompanyLogo?: boolean;
|
||||
licensedIn?: (typeof LicensedInSchema._type)[];
|
||||
gender?: z.infer<typeof GenderEnum>;
|
||||
customerType?: z.infer<typeof CustomerTypeEnum>;
|
||||
customerSubType?: z.infer<typeof CustomerSubTypeEnum>;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
} {
|
||||
const { id, created, updated, ...drizzleUser } = user;
|
||||
type DrizzleUser = typeof users.$inferSelect; //Partial<InferInsertModel<typeof users>>;
|
||||
|
||||
export function convertUserToDrizzleUser(user: Partial<User>): DrizzleUser {
|
||||
const { companyLocation, ...restUser } = user;
|
||||
|
||||
// Ensure all required fields are present
|
||||
if (!user.id || !user.email || !user.firstname || !user.lastname) {
|
||||
throw new Error('Missing required fields: id, email, firstname, or lastname');
|
||||
}
|
||||
|
||||
return {
|
||||
...drizzleUser,
|
||||
email: drizzleUser.email,
|
||||
firstname: drizzleUser.firstname,
|
||||
lastname: drizzleUser.lastname,
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
firstname: user.firstname,
|
||||
lastname: user.lastname,
|
||||
phoneNumber: user.phoneNumber || null,
|
||||
description: user.description || null,
|
||||
companyName: user.companyName || null,
|
||||
companyOverview: user.companyOverview || null,
|
||||
companyWebsite: user.companyWebsite || null,
|
||||
city: companyLocation?.city || null,
|
||||
state: companyLocation?.state || null,
|
||||
offeredServices: user.offeredServices || null,
|
||||
areasServed: user.areasServed || [],
|
||||
hasProfile: user.hasProfile || false,
|
||||
hasCompanyLogo: user.hasCompanyLogo || false,
|
||||
licensedIn: user.licensedIn || [],
|
||||
gender: user.gender || null,
|
||||
customerType: user.customerType || null,
|
||||
customerSubType: user.customerSubType || null,
|
||||
created: user.created || new Date(),
|
||||
updated: user.updated || new Date(),
|
||||
latitude: companyLocation?.latitude || 0,
|
||||
longitude: companyLocation?.longitude || 0,
|
||||
};
|
||||
}
|
||||
|
||||
export function convertDrizzleUserToUser(drizzleUser: Partial<DrizzleUser>): User {
|
||||
const user = {
|
||||
id: drizzleUser.id,
|
||||
firstname: drizzleUser.firstname,
|
||||
lastname: drizzleUser.lastname,
|
||||
email: drizzleUser.email,
|
||||
phoneNumber: drizzleUser.phoneNumber ?? null,
|
||||
description: drizzleUser.description ?? null,
|
||||
companyName: drizzleUser.companyName ?? null,
|
||||
companyOverview: drizzleUser.companyOverview ?? null,
|
||||
companyWebsite: drizzleUser.companyWebsite ?? null,
|
||||
companyLocation: {
|
||||
city: drizzleUser.city,
|
||||
state: drizzleUser.state,
|
||||
latitude: drizzleUser.latitude, // Latitude wird zugewiesen, auch wenn es nicht direkt benötigt wird
|
||||
longitude: drizzleUser.longitude, // Longitude wird zugewiesen, auch wenn es nicht direkt benötigt wird
|
||||
},
|
||||
offeredServices: drizzleUser.offeredServices ?? null,
|
||||
areasServed: drizzleUser.areasServed ?? null,
|
||||
hasProfile: drizzleUser.hasProfile ?? null,
|
||||
hasCompanyLogo: drizzleUser.hasCompanyLogo ?? null,
|
||||
licensedIn: drizzleUser.licensedIn ?? null,
|
||||
gender: drizzleUser.gender ?? null,
|
||||
customerType: drizzleUser.customerType,
|
||||
customerSubType: drizzleUser.customerSubType ?? null,
|
||||
created: drizzleUser.created ?? null,
|
||||
updated: drizzleUser.updated ?? null,
|
||||
};
|
||||
return user;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user