geo coding, user service, listing for business
This commit is contained in:
10
bizmatch-server/src/account/account.module.ts
Normal file
10
bizmatch-server/src/account/account.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AccountController } from './account.controller.js';
|
||||
import { AccountService } from './account.service.js';
|
||||
import { FileService } from '../file/file.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [AccountController],
|
||||
providers: [AccountService,FileService]
|
||||
})
|
||||
export class AccountModule {}
|
||||
@@ -20,11 +20,16 @@ import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-win
|
||||
import * as winston from 'winston';
|
||||
import { MailModule } from './mail/mail.module.js';
|
||||
import { AuthModule } from './auth/auth.module.js';
|
||||
import { GeoModule } from './geo/geo.module.js';
|
||||
import { UserModule } from './user/user.module.js';
|
||||
import { ListingsModule } from './listings/listings.module.js';
|
||||
import { AccountModule } from './account/account.module.js';
|
||||
import { SelectOptionsModule } from './select-options/select-options.module.js';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule.forRoot(), RedisModule, MailModule, AuthModule,
|
||||
imports: [ConfigModule.forRoot(), MailModule, AuthModule,
|
||||
ServeStaticModule.forRoot({
|
||||
rootPath: join(__dirname, '..', 'public'), // `public` ist das Verzeichnis, wo Ihre statischen Dateien liegen
|
||||
}),
|
||||
@@ -43,9 +48,15 @@ const __dirname = path.dirname(__filename);
|
||||
// other transports...
|
||||
],
|
||||
// other options
|
||||
})
|
||||
}),
|
||||
GeoModule,
|
||||
UserModule,
|
||||
ListingsModule,
|
||||
AccountModule,
|
||||
SelectOptionsModule,
|
||||
RedisModule
|
||||
],
|
||||
controllers: [AppController, ListingsController, SelectOptionsController, SubscriptionsController, AccountController],
|
||||
providers: [AppService, FileService, SelectOptionsService, ListingsService, AccountService],
|
||||
controllers: [AppController, SubscriptionsController],
|
||||
providers: [AppService, FileService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
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
18
bizmatch-server/src/geo/geo.controller.ts
Normal file
18
bizmatch-server/src/geo/geo.controller.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Controller, Get, Param } from '@nestjs/common';
|
||||
import { GeoService } from './geo.service.js';
|
||||
|
||||
@Controller('geo')
|
||||
export class GeoController {
|
||||
constructor(private geoService:GeoService){}
|
||||
|
||||
@Get(':prefix')
|
||||
findByPrefix(@Param('prefix') prefix:string): any {
|
||||
return this.geoService.findCitiesStartingWith(prefix);
|
||||
}
|
||||
|
||||
@Get(':prefix/:state')
|
||||
findByPrefixAndState(@Param('prefix') prefix:string,@Param('state') state:string): any {
|
||||
return this.geoService.findCitiesStartingWith(prefix,state);
|
||||
}
|
||||
|
||||
}
|
||||
9
bizmatch-server/src/geo/geo.module.ts
Normal file
9
bizmatch-server/src/geo/geo.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GeoController } from './geo.controller.js';
|
||||
import { GeoService } from './geo.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [GeoController],
|
||||
providers: [GeoService]
|
||||
})
|
||||
export class GeoModule {}
|
||||
40
bizmatch-server/src/geo/geo.service.ts
Normal file
40
bizmatch-server/src/geo/geo.service.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { readFileSync } from 'fs';
|
||||
import path, { join } from 'path';
|
||||
import { City, Geo, State } from 'src/models/server.model.js';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
@Injectable()
|
||||
export class GeoService {
|
||||
geo:Geo;
|
||||
constructor() {
|
||||
this.loadGeo();
|
||||
}
|
||||
private loadGeo(): void {
|
||||
const filePath = join(__dirname,'..', 'assets', 'geo.json');
|
||||
const rawData = readFileSync(filePath, 'utf8');
|
||||
this.geo = JSON.parse(rawData);
|
||||
}
|
||||
|
||||
findCitiesStartingWith( prefix: string, state?:string): { city: string; state: string; state_code: string }[] {
|
||||
const result: { city: string; state: string; state_code: string }[] = [];
|
||||
|
||||
this.geo.states.forEach((state: State) => {
|
||||
state.cities.forEach((city: City) => {
|
||||
if (city.name.toLowerCase().startsWith(prefix.toLowerCase())) {
|
||||
result.push({
|
||||
city: city.name,
|
||||
state: state.name,
|
||||
state_code: state.state_code
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return state ? result.filter(e=>e.state_code.toLowerCase()===state.toLowerCase()) :result;
|
||||
}
|
||||
}
|
||||
|
||||
9
bizmatch-server/src/listings/listings.module.ts
Normal file
9
bizmatch-server/src/listings/listings.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ListingsController } from './listings.controller.js';
|
||||
import { ListingsService } from './listings.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [ListingsController],
|
||||
providers: [ListingsService]
|
||||
})
|
||||
export class ListingsModule {}
|
||||
@@ -5,55 +5,51 @@ import {
|
||||
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) {}
|
||||
constructor(@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);
|
||||
// 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);
|
||||
//return await this.redisService.getJson(id, LISTINGS);
|
||||
}
|
||||
deleteListing(id: string){
|
||||
this.redisService.delete(id);
|
||||
//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;
|
||||
// const searchResult = await this.redisService.search(LISTINGS, '*');
|
||||
// const listings = searchResult.slice(1).reduce((acc, item, index, array) => {
|
||||
// if (index % 2 === 1) {
|
||||
// try {
|
||||
// const listing = JSON.parse(item[1]);
|
||||
// acc.push(listing);
|
||||
// } catch (error) {
|
||||
// console.error('Fehler beim Parsen des JSON-Strings: ', error);
|
||||
// }
|
||||
// }
|
||||
// return acc;
|
||||
// }, []);
|
||||
// return listings;
|
||||
return [];
|
||||
}
|
||||
//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);
|
||||
|
||||
@@ -14,12 +14,16 @@ const __dirname = path.dirname(__filename);
|
||||
// transport: 'smtps://user@example.com:topsecret@smtp.example.com',
|
||||
// or
|
||||
transport: {
|
||||
host: 'smtp.gmail.com',
|
||||
secure: true,
|
||||
|
||||
host: 'email-smtp.us-east-2.amazonaws.com',
|
||||
secure: false,
|
||||
port:587,
|
||||
// auth: {
|
||||
// user: 'andreas.knuth@gmail.com',
|
||||
// pass: 'ksnh xjae dqbv xana',
|
||||
// },
|
||||
auth: {
|
||||
user: 'andreas.knuth@gmail.com',
|
||||
pass: 'ksnh xjae dqbv xana',
|
||||
user: 'AKIAU6GDWVAQ2QNFLNWN',
|
||||
pass: 'BDE9nZv/ARbpotim1mIOir52WgIbpSi9cv1oJoH8oEf7',
|
||||
},
|
||||
},
|
||||
defaults: {
|
||||
|
||||
@@ -1,11 +1,80 @@
|
||||
import { Entity } from "redis-om";
|
||||
import { UserBase } from "./main.model.js";
|
||||
|
||||
export interface MailInfo {
|
||||
sender:Sender;
|
||||
userId:string;
|
||||
}
|
||||
sender: Sender;
|
||||
userId: string;
|
||||
}
|
||||
export interface Sender {
|
||||
name:string;
|
||||
email:string;
|
||||
phoneNumber:string;
|
||||
state:string;
|
||||
comments:string;
|
||||
name: string;
|
||||
email: string;
|
||||
phoneNumber: string;
|
||||
state: string;
|
||||
comments: string;
|
||||
}
|
||||
export interface Geo {
|
||||
id: number;
|
||||
name: string;
|
||||
iso3: string;
|
||||
iso2: string;
|
||||
numeric_code: string;
|
||||
phone_code: string;
|
||||
capital: string;
|
||||
currency: string;
|
||||
currency_name: string;
|
||||
currency_symbol: string;
|
||||
tld: string;
|
||||
native: string;
|
||||
region: string;
|
||||
region_id: string;
|
||||
subregion: string;
|
||||
subregion_id: string;
|
||||
nationality: string;
|
||||
timezones: Timezone[];
|
||||
translations: Translations;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
emoji: string;
|
||||
emojiU: string;
|
||||
states: State[];
|
||||
}
|
||||
export interface State {
|
||||
id: number;
|
||||
name: string;
|
||||
state_code: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
type: string;
|
||||
cities: City[];
|
||||
}
|
||||
export interface City {
|
||||
id: number;
|
||||
name: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
}
|
||||
export interface Translations {
|
||||
kr: string;
|
||||
'pt-BR': string;
|
||||
pt: string;
|
||||
nl: string;
|
||||
hr: string;
|
||||
fa: string;
|
||||
de: string;
|
||||
es: string;
|
||||
fr: string;
|
||||
ja: string;
|
||||
it: string;
|
||||
cn: string;
|
||||
tr: string;
|
||||
}
|
||||
export interface Timezone {
|
||||
zoneName: string;
|
||||
gmtOffset: number;
|
||||
gmtOffsetName: string;
|
||||
abbreviation: string;
|
||||
tzName: string;
|
||||
}
|
||||
export interface UserEntity extends UserBase, Entity {
|
||||
licensedIn?: string[];
|
||||
}
|
||||
@@ -6,13 +6,4 @@ import { RedisService } from './redis.service.js';
|
||||
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);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -2,15 +2,30 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
@Module({
|
||||
providers: [RedisService],
|
||||
exports: [RedisService],
|
||||
controllers: [RedisController],
|
||||
providers: [
|
||||
{
|
||||
provide: 'REDIS_OPTIONS',
|
||||
useValue: {
|
||||
url: 'redis://localhost:6379'
|
||||
}
|
||||
},
|
||||
{
|
||||
inject: ['REDIS_OPTIONS'],
|
||||
provide: 'REDIS_CLIENT',
|
||||
useFactory: async (options: { url: string }) => {
|
||||
const client = createClient(options);
|
||||
await client.connect();
|
||||
return client;
|
||||
}
|
||||
}],
|
||||
exports:['REDIS_CLIENT']
|
||||
})
|
||||
export class RedisModule {}
|
||||
|
||||
export const REDIS_CLIENT = "REDIS_CLIENT";
|
||||
// redis.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RedisService } from './redis.service.js';
|
||||
import { RedisController } from './redis.controller.js';
|
||||
import { createClient } from 'redis';
|
||||
|
||||
|
||||
|
||||
@@ -1,48 +1,50 @@
|
||||
// redis.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Redis } from 'ioredis';
|
||||
import { BusinessListing, InvestmentsListing,ProfessionalsBrokersListing } from '../models/main.model.js';
|
||||
import fs from 'fs-extra';
|
||||
import { createClient } from 'redis';
|
||||
|
||||
export const LISTINGS = 'LISTINGS';
|
||||
export const SUBSCRIPTIONS = 'SUBSCRIPTIONS';
|
||||
export const USERS = 'USERS'
|
||||
|
||||
export const redis = createClient({ url: 'redis://localhost:6379' })
|
||||
@Injectable()
|
||||
export class RedisService {
|
||||
// private redis = new Redis(); // Verbindungsparameter nach Bedarf anpassen
|
||||
private redis = new Redis({
|
||||
port: 6379, // Der TLS-Port von Redis
|
||||
host: '2.56.188.138',
|
||||
password: 'bizmatchRedis:5600Wuppertal11', // ACL Benutzername und Passwort
|
||||
//private redis = new Redis(); // Verbindungsparameter nach Bedarf anpassen
|
||||
// private redis = new Redis({
|
||||
// port: 6379, // Der TLS-Port von Redis
|
||||
//host: '2.56.188.138',
|
||||
// host: '127.0.0.1',
|
||||
//password: 'bizmatchRedis:5600Wuppertal11', // ACL Benutzername und Passwort
|
||||
// tls: {
|
||||
// key: fs.readFileSync('/home/aknuth/ssl/private/redis.key'),
|
||||
// cert: fs.readFileSync('/home/aknuth/ssl/certs/redis.crt')
|
||||
// }
|
||||
});
|
||||
// });
|
||||
|
||||
|
||||
|
||||
// ######################################
|
||||
// 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 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 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;
|
||||
}
|
||||
// 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;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { SelectOptionsController } from './select-options.controller.js';
|
||||
import { SelectOptionsService } from './select-options.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [SelectOptionsController],
|
||||
providers: [SelectOptionsService]
|
||||
})
|
||||
export class SelectOptionsModule {}
|
||||
28
bizmatch-server/src/user/user.controller.ts
Normal file
28
bizmatch-server/src/user/user.controller.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Body, Controller, Get, Inject, Param, Post, Put } from '@nestjs/common';
|
||||
import { UserService } from './user.service.js';
|
||||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||
import { Logger } from 'winston';
|
||||
import { UserEntity } from 'src/models/server.model.js';
|
||||
|
||||
@Controller('user')
|
||||
export class UserController {
|
||||
|
||||
constructor(private userService:UserService,@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger){}
|
||||
|
||||
@Get(':id')
|
||||
findById(@Param('id') id:string): any {
|
||||
return this.userService.getUserById(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
save(@Body() user: any):Promise<UserEntity>{
|
||||
this.logger.info(`User persisted: `);
|
||||
return this.userService.saveUser(user);
|
||||
}
|
||||
|
||||
// @Put()
|
||||
// update(@Body() user: any):Promise<UserEntity>{
|
||||
// this.logger.info(`update User`);
|
||||
// return this.userService.saveUser(user);
|
||||
// }
|
||||
}
|
||||
12
bizmatch-server/src/user/user.module.ts
Normal file
12
bizmatch-server/src/user/user.module.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UserController } from './user.controller.js';
|
||||
import { UserService } from './user.service.js';
|
||||
import { RedisModule } from '../redis/redis.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [RedisModule],
|
||||
controllers: [UserController],
|
||||
providers: [UserService]
|
||||
})
|
||||
export class UserModule {
|
||||
}
|
||||
46
bizmatch-server/src/user/user.service.ts
Normal file
46
bizmatch-server/src/user/user.service.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Get, Inject, Injectable, Param } from '@nestjs/common';
|
||||
import { createClient } from 'redis';
|
||||
import { Entity, Repository, Schema } from 'redis-om';
|
||||
import { User } from '../models/main.model.js';
|
||||
import { REDIS_CLIENT } from '../redis/redis.module.js';
|
||||
import { UserEntity } from '../models/server.model.js';
|
||||
// export const redis = createClient({ url: 'redis://localhost:6379' })
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
userRepository:Repository;
|
||||
userSchema = new Schema('user',{
|
||||
// id: string;
|
||||
firstname: { type: 'string' },
|
||||
lastname: { type: 'string' },
|
||||
email: { type: 'string' },
|
||||
phoneNumber: { type: 'string' },
|
||||
companyOverview:{ type: 'string' },
|
||||
companyWebsite:{ type: 'string' },
|
||||
companyLocation:{ type: 'string' },
|
||||
offeredServices:{ type: 'string' },
|
||||
areasServed:{ type: 'string' },
|
||||
names:{ type: 'string[]', path:'$.licensedIn.name' },
|
||||
values:{ type: 'string[]', path:'$.licensedIn.value' }
|
||||
}, {
|
||||
dataStructure: 'JSON'
|
||||
})
|
||||
constructor(@Inject(REDIS_CLIENT) private readonly client: any){
|
||||
// const redis = createClient({ url: 'redis://localhost:6379' })
|
||||
this.userRepository = new Repository(this.userSchema, client)
|
||||
}
|
||||
|
||||
async getUserById( id:string){
|
||||
return await this.userRepository.fetch(id);
|
||||
}
|
||||
async saveUser(user:any):Promise<UserEntity>{
|
||||
return await this.userRepository.save(user.id,user) as UserEntity
|
||||
}
|
||||
// createUser(){
|
||||
|
||||
// }
|
||||
|
||||
// updateById(id:string){
|
||||
|
||||
// }
|
||||
}
|
||||
Reference in New Issue
Block a user