eletrotupi / tcc/ api/src/routes/users.jsfa3b53dc37fc3993c67af93384787de99c007de3
5.4 KB | 219 lines Raw
1
import express from "express";
2
import bcrypt from "bcryptjs";
3

4
import {
5
  isValidEmail,
6
  isValidPassword,
7
  sanitizeString,
8
  validateRequiredFields
9
} from "../utils/validators.js";
10

11
const router = express.Router();
12

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

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

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

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

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

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

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

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

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

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

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

76
  const db = req.db;
77

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

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

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

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

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

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

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

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

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

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

125
  user.total_moods = moodStats.total_moods;
126

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

219
export default router;