164 lines
6.4 KiB
TypeScript
164 lines
6.4 KiB
TypeScript
import { Inject, Injectable } from '@nestjs/common';
|
|
import { and, asc, count, desc, eq, ilike, inArray, or, SQL, sql } from 'drizzle-orm';
|
|
import { NodePgDatabase } from 'drizzle-orm/node-postgres/driver';
|
|
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
import { Logger } from 'winston';
|
|
import * as schema from '../drizzle/schema';
|
|
import { customerSubTypeEnum, PG_CONNECTION } from '../drizzle/schema';
|
|
import { FileService } from '../file/file.service';
|
|
import { GeoService } from '../geo/geo.service';
|
|
import { User, UserSchema } from '../models/db.model';
|
|
import { createDefaultUser, emailToDirName, JwtUser, UserListingCriteria } from '../models/main.model';
|
|
import { DrizzleUser, getDistanceQuery, splitName } from '../utils';
|
|
|
|
type CustomerSubType = (typeof customerSubTypeEnum.enumValues)[number];
|
|
@Injectable()
|
|
export class UserService {
|
|
constructor(
|
|
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
|
|
@Inject(PG_CONNECTION) private conn: NodePgDatabase<typeof schema>,
|
|
private fileService: FileService,
|
|
private geoService: GeoService,
|
|
) {}
|
|
|
|
private getWhereConditions(criteria: UserListingCriteria): SQL[] {
|
|
const whereConditions: SQL[] = [];
|
|
whereConditions.push(eq(schema.users.customerType, 'professional'));
|
|
if (criteria.city && criteria.searchType === 'exact') {
|
|
whereConditions.push(sql`${schema.users.location}->>'name' ilike ${criteria.city.name}`);
|
|
}
|
|
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
|
|
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city.name);
|
|
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));
|
|
whereConditions.push(inArray(schema.users.customerSubType, criteria.types as CustomerSubType[]));
|
|
}
|
|
|
|
if (criteria.brokerName) {
|
|
const { firstname, lastname } = splitName(criteria.brokerName);
|
|
whereConditions.push(or(ilike(schema.users.firstname, `%${firstname}%`), ilike(schema.users.lastname, `%${lastname}%`)));
|
|
}
|
|
|
|
if (criteria.companyName) {
|
|
whereConditions.push(ilike(schema.users.companyName, `%${criteria.companyName}%`));
|
|
}
|
|
|
|
if (criteria.counties && criteria.counties.length > 0) {
|
|
whereConditions.push(or(...criteria.counties.map(county => sql`EXISTS (SELECT 1 FROM jsonb_array_elements(${schema.users.areasServed}) AS area WHERE area->>'county' ILIKE ${`%${county}%`})`)));
|
|
}
|
|
|
|
if (criteria.state) {
|
|
whereConditions.push(sql`EXISTS (SELECT 1 FROM jsonb_array_elements(${schema.users.areasServed}) AS area WHERE area->>'state' = ${criteria.state})`);
|
|
}
|
|
|
|
//never show user which denied
|
|
whereConditions.push(eq(schema.users.showInDirectory, true))
|
|
|
|
return whereConditions;
|
|
}
|
|
async searchUserListings(criteria: UserListingCriteria): Promise<{ results: User[]; totalCount: number }> {
|
|
const start = criteria.start ? criteria.start : 0;
|
|
const length = criteria.length ? criteria.length : 12;
|
|
const query = this.conn.select().from(schema.users);
|
|
const whereConditions = this.getWhereConditions(criteria);
|
|
|
|
if (whereConditions.length > 0) {
|
|
const whereClause = and(...whereConditions);
|
|
query.where(whereClause);
|
|
}
|
|
// Sortierung
|
|
switch (criteria.sortBy) {
|
|
case 'nameAsc':
|
|
query.orderBy(asc(schema.users.lastname));
|
|
break;
|
|
case 'nameDesc':
|
|
query.orderBy(desc(schema.users.lastname));
|
|
break;
|
|
default:
|
|
// Keine spezifische Sortierung, Standardverhalten kann hier eingefügt werden
|
|
break;
|
|
}
|
|
// Paginierung
|
|
query.limit(length).offset(start);
|
|
|
|
const data = await query;
|
|
const results = data;
|
|
const totalCount = await this.getUserListingsCount(criteria);
|
|
|
|
return {
|
|
results,
|
|
totalCount,
|
|
};
|
|
}
|
|
async getUserListingsCount(criteria: UserListingCriteria): Promise<number> {
|
|
const countQuery = this.conn.select({ value: count() }).from(schema.users);
|
|
const whereConditions = this.getWhereConditions(criteria);
|
|
|
|
if (whereConditions.length > 0) {
|
|
const whereClause = and(...whereConditions);
|
|
countQuery.where(whereClause);
|
|
}
|
|
|
|
const [{ value: totalCount }] = await countQuery;
|
|
return totalCount;
|
|
}
|
|
async getUserByMail(email: string, jwtuser?: JwtUser) {
|
|
const users = (await this.conn
|
|
.select()
|
|
.from(schema.users)
|
|
.where(sql`email = ${email}`)) as User[];
|
|
if (users.length === 0) {
|
|
const user: User = { id: undefined, customerType: 'professional', ...createDefaultUser(email, jwtuser.firstname ? jwtuser.firstname : '', jwtuser.lastname ? jwtuser.lastname : '', null) };
|
|
const u = await this.saveUser(user, false);
|
|
return u;
|
|
} else {
|
|
const user = users[0];
|
|
user.hasCompanyLogo = this.fileService.hasCompanyLogo(emailToDirName(user.email));
|
|
user.hasProfile = this.fileService.hasProfile(emailToDirName(user.email));
|
|
return user;
|
|
}
|
|
}
|
|
async getUserById(id: string) {
|
|
const users = (await this.conn
|
|
.select()
|
|
.from(schema.users)
|
|
.where(sql`id = ${id}`)) as User[];
|
|
|
|
const user = users[0];
|
|
user.hasCompanyLogo = this.fileService.hasCompanyLogo(emailToDirName(user.email));
|
|
user.hasProfile = this.fileService.hasProfile(emailToDirName(user.email));
|
|
return user;
|
|
}
|
|
async getAllUser() {
|
|
const users = await this.conn.select().from(schema.users);
|
|
return users;
|
|
}
|
|
async saveUser(user: User, processValidation = true): Promise<User> {
|
|
try {
|
|
user.updated = new Date();
|
|
if (user.id) {
|
|
user.created = new Date(user.created);
|
|
} else {
|
|
user.created = new Date();
|
|
}
|
|
let validatedUser = user;
|
|
if (processValidation) {
|
|
validatedUser = UserSchema.parse(user);
|
|
}
|
|
//const drizzleUser = convertUserToDrizzleUser(validatedUser);
|
|
const drizzleUser = validatedUser as DrizzleUser;
|
|
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 [newUser] = await this.conn.insert(schema.users).values(drizzleUser).returning();
|
|
return newUser as User;
|
|
}
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|