eletrotupi / tcc/ api/src/routes/users.jsba9ebeebe13950cdc2b168d63fe2ec5b3be67d11
5.4 KB | 218 lines Raw
1
import express from "express";
2
import bcrypt from "bcryptjs";
3
import {
4
  isValidEmail,
5
  isValidPassword,
6
  sanitizeString,
7
  validateRequiredFields
8
} from "../utils/validators.js";
9

10
const router = express.Router();
11

12
// Create user
13
router.post("/", (req, res) => {
14
  const { email, password, first_name, last_name, timezone } = req.body;
15

16
  // Validate required fields
17
  const requiredValidation = validateRequiredFields(req.body, [
18
    'email', 'password', 'first_name', 'last_name'
19
  ]);
20

21
  if (!requiredValidation.valid) {
22
    return res.status(400).json({
23
      error: "Campos faltantes",
24
      missing: requiredValidation.missing
25
    });
26
  }
27

28
  // Validate email format
29
  if (!isValidEmail(email)) {
30
    return res.status(400).json({ error: "Email inválido" });
31
  }
32

33
  // Validate password strength
34
  if (!isValidPassword(password)) {
35
    return res.status(400).json({ error: "Senha deve ter pelo menos 6 caracteres" });
36
  }
37

38
  const hashed = bcrypt.hashSync(password, 10);
39
  const db = req.db;
40

41
  try {
42
    const stmt = db.prepare(`
43
      INSERT INTO users (email, password, first_name, last_name, timezone)
44
      VALUES (?, ?, ?, ?, ?)
45
    `);
46

47
    const result = stmt.run(
48
      email.toLowerCase(),
49
      hashed,
50
      sanitizeString(first_name),
51
      sanitizeString(last_name),
52
      timezone || 'UTC'
53
    );
54

55
    res.status(201).json({ id: result.lastInsertRowid });
56
  } catch (err) {
57
    if (err.message.includes('UNIQUE')) {
58
      res.status(400).json({ error: "Email já cadastrado" });
59
    } else {
60
      console.error('Error creating user:', err);
61
      res.status(500).json({ error: "Erro ao criar usuário" });
62
    }
63
  }
64
});
65

66
// User login
67
router.post("/login", (req, res) => {
68
  const { email, password } = req.body;
69

70
  // Validate required fields
71
  if (!email || !password) {
72
    return res.status(400).json({ error: "Email e senha são obrigatórios" });
73
  }
74

75
  const db = req.db;
76

77
  const user = db.prepare(`
78
    SELECT id, email, password, first_name, last_name, timezone
79
    FROM users
80
    WHERE email = ?
81
  `).get(email.toLowerCase());
82

83
  if (!user) {
84
    return res.status(401).json({ error: "Credenciais inválidas" });
85
  }
86

87
  const passwordMatch = bcrypt.compareSync(password, user.password);
88

89
  if (!passwordMatch) {
90
    return res.status(401).json({ error: "Credenciais inválidas" });
91
  }
92

93
  // Don't send password in response
94
  delete user.password;
95

96
  res.json({
97
    success: true,
98
    user
99
  });
100
});
101

102
// Get user profile
103
router.get("/:user_id", (req, res) => {
104
  const userId = req.params.user_id;
105
  const db = req.db;
106

107
  const user = db.prepare(`
108
    SELECT id, email, first_name, last_name, timezone, created_at, updated_at
109
    FROM users
110
    WHERE id = ?
111
  `).get(userId);
112

113
  if (!user) {
114
    return res.status(404).json({ error: "Usuário não encontrado" });
115
  }
116

117
  // Get user's mood count
118
  const moodStats = db.prepare(`
119
    SELECT COUNT(*) as total_moods
120
    FROM mood
121
    WHERE user_id = ?
122
  `).get(userId);
123

124
  user.total_moods = moodStats.total_moods;
125

126
  res.json(user);
127
});
128

129
// Update user
130
router.put("/:user_id", (req, res) => {
131
  const userId = req.params.user_id;
132
  const { email, password, first_name, last_name, timezone } = req.body;
133
  const db = req.db;
134

135
  // Check if user exists
136
  const existingUser = db.prepare("SELECT id FROM users WHERE id = ?").get(userId);
137
  if (!existingUser) {
138
    return res.status(404).json({ error: "Usuário não encontrado" });
139
  }
140

141
  const updates = [];
142
  const values = [];
143

144
  if (email !== undefined) {
145
    if (!isValidEmail(email)) {
146
      return res.status(400).json({ error: "Email inválido" });
147
    }
148

149
    // Check if email is already taken by another user
150
    const emailCheck = db.prepare("SELECT id FROM users WHERE email = ? AND id != ?")
151
      .get(email.toLowerCase(), userId);
152

153
    if (emailCheck) {
154
      return res.status(400).json({ error: "Email já está em uso" });
155
    }
156

157
    updates.push("email = ?");
158
    values.push(email.toLowerCase());
159
  }
160

161
  if (password !== undefined) {
162
    if (!isValidPassword(password)) {
163
      return res.status(400).json({ error: "Senha deve ter pelo menos 6 caracteres" });
164
    }
165
    updates.push("password = ?");
166
    values.push(bcrypt.hashSync(password, 10));
167
  }
168

169
  if (first_name !== undefined) {
170
    updates.push("first_name = ?");
171
    values.push(sanitizeString(first_name));
172
  }
173

174
  if (last_name !== undefined) {
175
    updates.push("last_name = ?");
176
    values.push(sanitizeString(last_name));
177
  }
178

179
  if (timezone !== undefined) {
180
    updates.push("timezone = ?");
181
    values.push(timezone);
182
  }
183

184
  if (updates.length === 0) {
185
    return res.status(400).json({ error: "Nenhum campo para atualizar" });
186
  }
187

188
  updates.push("updated_at = CURRENT_TIMESTAMP");
189

190
  try {
191
    const updateQuery = `UPDATE users SET ${updates.join(', ')} WHERE id = ?`;
192
    values.push(userId);
193

194
    db.prepare(updateQuery).run(...values);
195

196
    res.json({ success: true, id: userId });
197
  } catch (err) {
198
    console.error('Error updating user:', err);
199
    res.status(500).json({ error: "Erro ao atualizar usuário" });
200
  }
201
});
202

203
// Delete user
204
router.delete("/:user_id", (req, res) => {
205
  const userId = req.params.user_id;
206
  const db = req.db;
207

208
  // This will cascade delete all moods and mood_components
209
  const result = db.prepare("DELETE FROM users WHERE id = ?").run(userId);
210

211
  if (result.changes === 0) {
212
    return res.status(404).json({ error: "Usuário não encontrado" });
213
  }
214

215
  res.json({ success: true, deleted: userId });
216
});
217

218
export default router;