159 lines
3.1 KiB
TypeScript
159 lines
3.1 KiB
TypeScript
import { prisma } from '../database'
|
|
import { User, Prisma } from '@prisma/client'
|
|
import bcrypt from 'bcrypt'
|
|
|
|
export interface CreateUserData {
|
|
email: string
|
|
name?: string
|
|
password?: string
|
|
image?: string
|
|
}
|
|
|
|
export interface UpdateUserData {
|
|
name?: string
|
|
email?: string
|
|
image?: string
|
|
}
|
|
|
|
export interface UserProfile {
|
|
id: string
|
|
name: string | null
|
|
email: string | null
|
|
image: string | null
|
|
createdAt: Date
|
|
updatedAt: Date
|
|
}
|
|
|
|
export class UserService {
|
|
/**
|
|
* 创建新用户
|
|
*/
|
|
static async createUser(data: CreateUserData): Promise<User> {
|
|
const { email, name, password, image } = data
|
|
|
|
// 验证邮箱格式
|
|
if (!this.isValidEmail(email)) {
|
|
throw new Error('邮箱格式不正确')
|
|
}
|
|
|
|
// 检查邮箱是否已存在
|
|
const existingUser = await prisma.user.findUnique({
|
|
where: { email }
|
|
})
|
|
|
|
if (existingUser) {
|
|
throw new Error('邮箱已被注册')
|
|
}
|
|
|
|
// 哈希密码(如果提供)
|
|
let hashedPassword: string | undefined
|
|
if (password) {
|
|
if (password.length < 6) {
|
|
throw new Error('密码长度至少6位')
|
|
}
|
|
hashedPassword = await bcrypt.hash(password, 12)
|
|
}
|
|
|
|
return prisma.user.create({
|
|
data: {
|
|
email,
|
|
name,
|
|
image,
|
|
hashedPassword
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 根据ID获取用户
|
|
*/
|
|
static async getUserById(id: string): Promise<UserProfile | null> {
|
|
const user = await prisma.user.findUnique({
|
|
where: { id },
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
image: true,
|
|
createdAt: true,
|
|
updatedAt: true
|
|
}
|
|
})
|
|
|
|
return user
|
|
}
|
|
|
|
/**
|
|
* 根据邮箱获取用户
|
|
*/
|
|
static async getUserByEmail(email: string): Promise<User | null> {
|
|
return prisma.user.findUnique({
|
|
where: { email }
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 更新用户信息
|
|
*/
|
|
static async updateUser(id: string, data: UpdateUserData): Promise<UserProfile> {
|
|
const updateData: Prisma.UserUpdateInput = {}
|
|
|
|
if (data.name !== undefined) {
|
|
updateData.name = data.name
|
|
}
|
|
|
|
if (data.email !== undefined) {
|
|
if (!this.isValidEmail(data.email)) {
|
|
throw new Error('邮箱格式不正确')
|
|
}
|
|
updateData.email = data.email
|
|
}
|
|
|
|
if (data.image !== undefined) {
|
|
updateData.image = data.image
|
|
}
|
|
|
|
const user = await prisma.user.update({
|
|
where: { id },
|
|
data: updateData,
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
image: true,
|
|
createdAt: true,
|
|
updatedAt: true
|
|
}
|
|
})
|
|
|
|
return user
|
|
}
|
|
|
|
/**
|
|
* 验证用户密码
|
|
*/
|
|
static async verifyPassword(user: User, password: string): Promise<boolean> {
|
|
if (!user.hashedPassword) {
|
|
return false
|
|
}
|
|
|
|
return bcrypt.compare(password, user.hashedPassword)
|
|
}
|
|
|
|
/**
|
|
* 删除用户
|
|
*/
|
|
static async deleteUser(id: string): Promise<void> {
|
|
await prisma.user.delete({
|
|
where: { id }
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 验证邮箱格式
|
|
*/
|
|
private static isValidEmail(email: string): boolean {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
return emailRegex.test(email)
|
|
}
|
|
}
|