user-service.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import { eq, and } from 'drizzle-orm';
  2. import { db } from './db';
  3. import { users, verificationTokens, type User, type NewUser, type NewVerificationToken } from './schema';
  4. import { hashPassword, generateVerificationToken, generateExpirationTime } from './auth-utils';
  5. // 根据邮箱查找用户
  6. export async function findUserByEmail(email: string): Promise<User | null> {
  7. try {
  8. const [user] = await db.select().from(users).where(eq(users.email, email));
  9. return user || null;
  10. } catch (error) {
  11. console.error('查找用户失败:', error);
  12. return null;
  13. }
  14. }
  15. // 根据ID查找用户
  16. export async function findUserById(id: string): Promise<User | null> {
  17. try {
  18. const [user] = await db.select().from(users).where(eq(users.id, id));
  19. return user || null;
  20. } catch (error) {
  21. console.error('查找用户失败:', error);
  22. return null;
  23. }
  24. }
  25. // 创建新用户
  26. export async function createUser(userData: Omit<NewUser, 'id' | 'createdAt' | 'updatedAt'>): Promise<User | null> {
  27. try {
  28. // 检查用户是否已存在
  29. const existingUser = await findUserByEmail(userData.email);
  30. if (existingUser) {
  31. throw new Error('邮箱已被注册');
  32. }
  33. // 哈希密码
  34. const hashedPassword = userData.password ? await hashPassword(userData.password) : null;
  35. const [newUser] = await db.insert(users).values({
  36. ...userData,
  37. password: hashedPassword,
  38. isEmailVerified: false,
  39. }).returning();
  40. return newUser;
  41. } catch (error) {
  42. console.error('创建用户失败:', error);
  43. return null;
  44. }
  45. }
  46. // 更新用户
  47. export async function updateUser(userId: string, updates: Partial<User>): Promise<User | null> {
  48. try {
  49. const [updatedUser] = await db
  50. .update(users)
  51. .set({ ...updates, updatedAt: new Date() })
  52. .where(eq(users.id, userId))
  53. .returning();
  54. return updatedUser || null;
  55. } catch (error) {
  56. console.error('更新用户失败:', error);
  57. return null;
  58. }
  59. }
  60. // 验证用户邮箱
  61. export async function verifyUserEmail(userId: string): Promise<boolean> {
  62. try {
  63. const [updatedUser] = await db
  64. .update(users)
  65. .set({
  66. isEmailVerified: true,
  67. emailVerified: new Date(),
  68. updatedAt: new Date()
  69. })
  70. .where(eq(users.id, userId))
  71. .returning();
  72. return !!updatedUser;
  73. } catch (error) {
  74. console.error('验证邮箱失败:', error);
  75. return false;
  76. }
  77. }
  78. // 创建验证令牌
  79. export async function createVerificationToken(
  80. email: string,
  81. type: 'email_verification' | 'password_reset',
  82. expirationHours: number = 24
  83. ): Promise<string | null> {
  84. try {
  85. const token = generateVerificationToken();
  86. const expires = generateExpirationTime(expirationHours);
  87. // 删除旧的相同类型的令牌
  88. await db.delete(verificationTokens).where(
  89. and(
  90. eq(verificationTokens.email, email),
  91. eq(verificationTokens.type, type)
  92. )
  93. );
  94. // 创建新令牌 - 使用原有的字段结构
  95. await db.insert(verificationTokens).values({
  96. email,
  97. token,
  98. expires,
  99. type,
  100. });
  101. return token;
  102. } catch (error) {
  103. console.error('创建验证令牌失败:', error);
  104. return null;
  105. }
  106. }
  107. // 验证令牌
  108. export async function verifyToken(token: string, type: 'email_verification' | 'password_reset'): Promise<{
  109. isValid: boolean;
  110. email?: string;
  111. }> {
  112. try {
  113. const [verificationToken] = await db
  114. .select()
  115. .from(verificationTokens)
  116. .where(
  117. and(
  118. eq(verificationTokens.token, token),
  119. eq(verificationTokens.type, type)
  120. )
  121. );
  122. if (!verificationToken) {
  123. return { isValid: false };
  124. }
  125. // 检查是否过期
  126. if (new Date() > verificationToken.expires) {
  127. // 删除过期令牌
  128. await db.delete(verificationTokens).where(eq(verificationTokens.token, token));
  129. return { isValid: false };
  130. }
  131. return { isValid: true, email: verificationToken.email || undefined };
  132. } catch (error) {
  133. console.error('验证令牌失败:', error);
  134. return { isValid: false };
  135. }
  136. }
  137. // 删除验证令牌
  138. export async function deleteVerificationToken(token: string): Promise<boolean> {
  139. try {
  140. await db.delete(verificationTokens).where(eq(verificationTokens.token, token));
  141. return true;
  142. } catch (error) {
  143. console.error('删除令牌失败:', error);
  144. return false;
  145. }
  146. }
  147. // 更新用户密码
  148. export async function updateUserPassword(email: string, newPassword: string): Promise<boolean> {
  149. try {
  150. const hashedPassword = await hashPassword(newPassword);
  151. const [updatedUser] = await db
  152. .update(users)
  153. .set({
  154. password: hashedPassword,
  155. updatedAt: new Date()
  156. })
  157. .where(eq(users.email, email))
  158. .returning();
  159. return !!updatedUser;
  160. } catch (error) {
  161. console.error('更新密码失败:', error);
  162. return false;
  163. }
  164. }