eletrotupi / tcc/ api/src/models/user.tsb13456d98a5b20510f062a4d4fb619887728bd8f
3.4 KB | 164 lines Raw
1
import bcrypt from "bcryptjs";
2
import { prisma } from '../lib/prisma'
3
import {
4
  generateToken as createJWT,
5
  generatePasswordResetToken,
6
  getPasswordResetExpiration,
7
  isTokenExpired
8
} from '@app/lib/jwt';
9

10
import {
11
  isValidEmail,
12
  isValidPassword,
13
  sanitizeString,
14
  validateRequiredFields
15
} from "@app/utils/validators";
16

17
import { InvalidEmailError, ShortPasswordError } from '@app/lib/errors/UserErrors'
18

19
type UserOptions = {
20
  email: string;
21
  firstName: string;
22
  lastName: string;
23
};
24

25
const createUser = async (email: string, firstName: string, lastName: string, password: string) => {
26
  // Validate email format
27
  if (!isValidEmail(email)) {
28
    throw new InvalidEmailError()
29
  }
30

31
  // Validate password strength
32
  if (!isValidPassword(password)) {
33
    throw new ShortPasswordError()
34
  }
35

36
  const encryptedPassword = bcrypt.hashSync(password, 10);
37

38
  try {
39
    const user = await prisma.user.create({
40
      data: {
41
        email,
42
        firstName,
43
        lastName,
44
        encryptedPassword
45
      }
46
    });
47

48
    return user;
49
  } catch (err: any) {
50
    throw err;
51
  }
52
}
53

54
const generateToken = (userId: number, email: string) => {
55
  return createJWT(userId, email);
56
}
57

58
const findUserById = async (id: number) => {
59
  return await prisma.user.findUnique({
60
    where: { id }
61
  });
62
};
63

64
const findUserByEmail = async (email: string) => {
65
  return await prisma.user.findUnique({
66
    where: { email }
67
  });
68
};
69

70
const authenticateUser = async (email: string, password: string) => {
71
  const user = await findUserByEmail(email);
72

73
  if (!user) {
74
    throw new Error('Invalid credentials');
75
  }
76

77
  const isPasswordValid = bcrypt.compareSync(password, user.encryptedPassword);
78

79
  if (!isPasswordValid) {
80
    throw new Error('Invalid credentials');
81
  }
82

83
  return user;
84
};
85

86
const initiatePasswordReset = async (email: string) => {
87
  const user = await findUserByEmail(email);
88

89
  if (!user) {
90
    // Don't reveal whether email exists
91
    return { success: true };
92
  }
93

94
  const resetToken = generatePasswordResetToken();
95
  const resetExpires = getPasswordResetExpiration();
96

97
  await prisma.user.update({
98
    where: { id: user.id },
99
    data: {
100
      passwordResetToken: resetToken,
101
      passwordResetExpires: resetExpires
102
    }
103
  });
104

105
  // In production, send email with reset link
106
  // For now, return token for testing
107
  return {
108
    success: true,
109
    token: resetToken,
110
    email: user.email
111
  };
112
};
113

114
const resetPassword = async (token: string, newPassword: string) => {
115
  const user = await prisma.user.findFirst({
116
    where: {
117
      passwordResetToken: token,
118
      passwordResetExpires: { not: null }
119
    }
120
  });
121

122
  if (!user || !user.passwordResetExpires) {
123
    throw new Error('Invalid or expired reset token');
124
  }
125

126
  if (isTokenExpired(user.passwordResetExpires)) {
127
    throw new Error('Reset token has expired');
128
  }
129

130
  if (!isValidPassword(newPassword)) {
131
    throw new ShortPasswordError();
132
  }
133

134
  const encryptedPassword = bcrypt.hashSync(newPassword, 10);
135

136
  await prisma.user.update({
137
    where: { id: user.id },
138
    data: {
139
      encryptedPassword,
140
      passwordResetToken: null,
141
      passwordResetExpires: null
142
    }
143
  });
144

145
  return { success: true };
146
};
147

148
const updateUser = async (user: any, data: UserOptions) => {
149
  return await prisma.user.update({
150
    where: { id: user.id },
151
    data
152
  });
153
}
154

155
export {
156
  createUser,
157
  findUserById,
158
  generateToken,
159
  findUserByEmail,
160
  authenticateUser,
161
  initiatePasswordReset,
162
  resetPassword,
163
  updateUser
164
}