92 lines
3.2 KiB
TypeScript
92 lines
3.2 KiB
TypeScript
import { BadRequestException, ConflictException, Injectable } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { User } from './entities/user.entity';
|
|
import { QueryFailedError, Repository } from 'typeorm';
|
|
import { createHash, ECDH } from 'crypto';
|
|
import { v4 as uuid } from 'uuid';
|
|
|
|
type UserFindOptions = Partial<Pick<User, 'userId' | 'username' | 'phone' | 'email'>>;
|
|
|
|
@Injectable()
|
|
export class UserService {
|
|
constructor(
|
|
@InjectRepository(User)
|
|
private readonly userRepository: Repository<User>,
|
|
) { }
|
|
|
|
async findOne(options: UserFindOptions | UserFindOptions[]): Promise<User | null> {
|
|
if (Object.keys(options).length === 0) {
|
|
return null;
|
|
}
|
|
return this.userRepository.findOne({ where: options });
|
|
}
|
|
|
|
async create(user: Partial<User>): Promise<User> {
|
|
try {
|
|
const newUser = this.userRepository.create(user);
|
|
return this.userRepository.save(newUser);
|
|
} catch (error) {
|
|
if (error instanceof QueryFailedError) {
|
|
throw new ConflictException(this.getDuplicateErrorMessage(error));
|
|
}
|
|
throw new BadRequestException('创建用户失败');
|
|
}
|
|
}
|
|
|
|
async update(userId: string, user: Partial<User>): Promise<User> {
|
|
const existingUser = await this.userRepository.findOne({ where: { userId } });
|
|
if (!existingUser) {
|
|
throw new BadRequestException('User not found');
|
|
}
|
|
try {
|
|
Object.assign(existingUser, user);
|
|
return await this.userRepository.save(existingUser);
|
|
} catch (error) {
|
|
if (error instanceof QueryFailedError) {
|
|
throw new ConflictException(this.getDuplicateErrorMessage(error));
|
|
}
|
|
}
|
|
}
|
|
|
|
async delete(userId: string): Promise<void> {
|
|
const existingUser = await this.userRepository.findOne({ where: { userId } });
|
|
if (!existingUser) {
|
|
throw new BadRequestException('User not found');
|
|
}
|
|
await this.userRepository.softDelete(existingUser.userId);
|
|
}
|
|
|
|
hashPassword(password: string, salt: string): string {
|
|
return createHash('sha256').update(`${password}${salt}`).digest('hex');
|
|
}
|
|
|
|
generateSalt(): string {
|
|
return uuid().replace(/-/g, '');
|
|
}
|
|
|
|
async setPassword(userId: string, password: string): Promise<User> {
|
|
const user = await this.userRepository.findOne({ where: { userId } });
|
|
if (!user) {
|
|
throw new BadRequestException('User not found');
|
|
}
|
|
const salt = this.generateSalt();
|
|
user.password_hash = this.hashPassword(password, salt);
|
|
user.salt = salt;
|
|
return this.userRepository.save(user);
|
|
}
|
|
|
|
private getDuplicateErrorMessage(error: QueryFailedError): string {
|
|
// 根据具体的错误信息返回友好的提示
|
|
if (error.message.includes('IDX_user_username')) {
|
|
return '用户名已被使用';
|
|
}
|
|
if (error.message.includes('IDX_user_email')) {
|
|
return '邮箱已被使用';
|
|
}
|
|
if (error.message.includes('IDX_user_phone')) {
|
|
return '手机号已被使用';
|
|
}
|
|
return '数据已存在,请检查输入';
|
|
}
|
|
}
|