api: rework mood and user routes to match improvements on model design
Pedro Lucas Porcellis porcellis@eletrotupi.com · 10 months ago
ba9ebeebe13950cdc2b168d63fe2ec5b3be67d11 Browse filesParents
06314a5Changed files
2
Additions
+687
Deletions
-31
api/src/routes/mood.js
1 1
import express from "express";
2 +
import {
3 +
validateMoodComponents,
4 +
isValidLevel,
5 +
isValidRating,
6 +
calculateEmotionStats
7 +
} from "../utils/emotions.js";
8 +
import {
9 +
validateRequiredFields,
10 +
isValidDate,
11 +
isNotFutureDate,
12 +
isValidDateRange,
13 +
sanitizeString,
14 +
validatePagination
15 +
} from "../utils/validators.js";
2 16
3 17
const router = express.Router();
4 18
19 +
// Create new mood entry with components
5 20
router.post("/", (req, res) => {
6 -
const { user_id, stress_level, anxiety_level, title, description } = req.body;
21 +
const {
22 +
user_id,
23 +
rating,
24 +
stress_level,
25 +
anxiety_level,
26 +
energy_level,
27 +
title,
28 +
description,
29 +
recorded_at,
30 +
mood_components
31 +
} = req.body;
32 +
33 +
// Validate required fields
34 +
const requiredValidation = validateRequiredFields(req.body, [
35 +
'user_id', 'stress_level', 'anxiety_level', 'energy_level', 'recorded_at'
36 +
]);
37 +
38 +
if (!requiredValidation.valid) {
39 +
return res.status(400).json({
40 +
error: "Campos faltantes",
41 +
missing: requiredValidation.missing
42 +
});
43 +
}
44 +
45 +
// Validate levels
46 +
if (!isValidLevel(stress_level)) {
47 +
return res.status(400).json({ error: "stress_level deve ser entre 1 e 10" });
48 +
}
49 +
if (!isValidLevel(anxiety_level)) {
50 +
return res.status(400).json({ error: "anxiety_level deve ser entre 1 e 10" });
51 +
}
52 +
if (!isValidLevel(energy_level)) {
53 +
return res.status(400).json({ error: "energy_level deve ser entre 1 e 10" });
54 +
}
55 +
56 +
// Validate optional rating
57 +
if (rating && !isValidRating(rating)) {
58 +
return res.status(400).json({ error: "rating deve ser entre 1 e 10" });
59 +
}
60 +
61 +
// Validate date
62 +
if (!isValidDate(recorded_at)) {
63 +
return res.status(400).json({ error: "recorded_at deve ser uma data válida" });
64 +
}
65 +
66 +
if (!isNotFutureDate(recorded_at)) {
67 +
return res.status(400).json({ error: "recorded_at não pode ser no futuro" });
68 +
}
69 +
70 +
// Validate mood components if provided
71 +
if (mood_components) {
72 +
const componentValidation = validateMoodComponents(mood_components);
73 +
if (!componentValidation.valid) {
74 +
return res.status(400).json({ error: componentValidation.error });
75 +
}
76 +
}
77 +
78 +
const db = req.db;
79 +
80 +
try {
81 +
// Start transaction
82 +
db.prepare("BEGIN").run();
83 +
84 +
// Insert mood entry
85 +
const moodStmt = db.prepare(`
86 +
INSERT INTO mood (
87 +
user_id, rating, stress_level, anxiety_level, energy_level,
88 +
title, description, recorded_at
89 +
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
90 +
`);
91 +
92 +
const moodResult = moodStmt.run(
93 +
user_id,
94 +
rating || null,
95 +
stress_level,
96 +
anxiety_level,
97 +
energy_level,
98 +
sanitizeString(title) || null,
99 +
sanitizeString(description) || null,
100 +
recorded_at
101 +
);
7 102
8 -
if (!user_id || !stress_level || !anxiety_level)
9 -
return res.status(400).json({ error: "Campos faltantes" });
103 +
const moodId = moodResult.lastInsertRowid;
10 104
11 -
const stmt = req.db.prepare(
12 -
`
13 -
INSERT INTO mood (user_id, stress_level, anxiety_level, title, description)
14 -
VALUES (?, ?, ?, ?, ?)
15 -
`
16 -
);
105 +
// Insert mood components if provided
106 +
if (mood_components && mood_components.length > 0) {
107 +
const componentStmt = db.prepare(`
108 +
INSERT INTO mood_components (mood_id, emotion, intensity)
109 +
VALUES (?, ?, ?)
110 +
`);
111 +
112 +
for (const component of mood_components) {
113 +
componentStmt.run(
114 +
moodId,
115 +
component.emotion.toLowerCase(),
116 +
component.intensity
117 +
);
118 +
}
119 +
}
17 120
18 -
const result = stmt.run(
19 -
user_id, stress_level, anxiety_level, title || null, description || null
20 -
);
121 +
// Commit transaction
122 +
db.prepare("COMMIT").run();
21 123
22 -
res.status(201).json({ id: result.lastInsertRowid });
124 +
res.status(201).json({ id: moodId });
125 +
} catch (err) {
126 +
// Rollback on error
127 +
db.prepare("ROLLBACK").run();
128 +
console.error('Error creating mood:', err);
129 +
res.status(500).json({ error: "Erro ao criar registro de humor" });
130 +
}
23 131
});
24 132
25 -
router.get("/:user_id", (req, res) => {
26 -
const stmt = req.db.prepare("SELECT * FROM mood WHERE user_id = ?");
27 -
const rows = stmt.all(req.params.user_id);
133 +
// Get single mood entry with components
134 +
router.get("/:mood_id", (req, res) => {
135 +
const moodId = req.params.mood_id;
136 +
const db = req.db;
137 +
138 +
const moodStmt = db.prepare(`
139 +
SELECT m.*, u.first_name, u.last_name
140 +
FROM mood m
141 +
JOIN users u ON m.user_id = u.id
142 +
WHERE m.id = ?
143 +
`);
144 +
145 +
const mood = moodStmt.get(moodId);
146 +
147 +
if (!mood) {
148 +
return res.status(404).json({ error: "Humor não encontrado" });
149 +
}
150 +
151 +
// Get mood components
152 +
const componentsStmt = db.prepare(`
153 +
SELECT emotion, intensity
154 +
FROM mood_components
155 +
WHERE mood_id = ?
156 +
`);
157 +
158 +
const components = componentsStmt.all(moodId);
159 +
mood.mood_components = components;
28 160
29 -
res.json(rows);
161 +
// Calculate emotion stats
162 +
if (components.length > 0) {
163 +
mood.emotion_stats = calculateEmotionStats(components);
164 +
}
165 +
166 +
res.json(mood);
30 167
});
31 168
32 -
export default router;
169 +
// Update mood entry
170 +
router.put("/:mood_id", (req, res) => {
171 +
const moodId = req.params.mood_id;
172 +
const {
173 +
rating,
174 +
stress_level,
175 +
anxiety_level,
176 +
energy_level,
177 +
title,
178 +
description,
179 +
recorded_at,
180 +
mood_components
181 +
} = req.body;
182 +
183 +
const db = req.db;
33 184
185 +
// Check if mood exists
186 +
const existingMood = db.prepare("SELECT id FROM mood WHERE id = ?").get(moodId);
187 +
if (!existingMood) {
188 +
return res.status(404).json({ error: "Humor não encontrado" });
189 +
}
190 +
191 +
// Build update query dynamically
192 +
const updates = [];
193 +
const values = [];
194 +
195 +
if (rating !== undefined) {
196 +
if (!isValidRating(rating)) {
197 +
return res.status(400).json({ error: "rating deve ser entre 1 e 10" });
198 +
}
199 +
updates.push("rating = ?");
200 +
values.push(rating);
201 +
}
202 +
203 +
if (stress_level !== undefined) {
204 +
if (!isValidLevel(stress_level)) {
205 +
return res.status(400).json({ error: "stress_level deve ser entre 1 e 10" });
206 +
}
207 +
updates.push("stress_level = ?");
208 +
values.push(stress_level);
209 +
}
210 +
211 +
if (anxiety_level !== undefined) {
212 +
if (!isValidLevel(anxiety_level)) {
213 +
return res.status(400).json({ error: "anxiety_level deve ser entre 1 e 10" });
214 +
}
215 +
updates.push("anxiety_level = ?");
216 +
values.push(anxiety_level);
217 +
}
218 +
219 +
if (energy_level !== undefined) {
220 +
if (!isValidLevel(energy_level)) {
221 +
return res.status(400).json({ error: "energy_level deve ser entre 1 e 10" });
222 +
}
223 +
updates.push("energy_level = ?");
224 +
values.push(energy_level);
225 +
}
226 +
227 +
if (title !== undefined) {
228 +
updates.push("title = ?");
229 +
values.push(sanitizeString(title) || null);
230 +
}
231 +
232 +
if (description !== undefined) {
233 +
updates.push("description = ?");
234 +
values.push(sanitizeString(description) || null);
235 +
}
236 +
237 +
if (recorded_at !== undefined) {
238 +
if (!isValidDate(recorded_at)) {
239 +
return res.status(400).json({ error: "recorded_at deve ser uma data válida" });
240 +
}
241 +
if (!isNotFutureDate(recorded_at)) {
242 +
return res.status(400).json({ error: "recorded_at não pode ser no futuro" });
243 +
}
244 +
updates.push("recorded_at = ?");
245 +
values.push(recorded_at);
246 +
}
247 +
248 +
updates.push("updated_at = CURRENT_TIMESTAMP");
249 +
250 +
try {
251 +
db.prepare("BEGIN").run();
252 +
253 +
// Update mood if there are changes
254 +
if (updates.length > 0) {
255 +
const updateQuery = `UPDATE mood SET ${updates.join(', ')} WHERE id = ?`;
256 +
values.push(moodId);
257 +
db.prepare(updateQuery).run(...values);
258 +
}
259 +
260 +
// Update mood components if provided
261 +
if (mood_components !== undefined) {
262 +
const componentValidation = validateMoodComponents(mood_components);
263 +
if (!componentValidation.valid) {
264 +
db.prepare("ROLLBACK").run();
265 +
return res.status(400).json({ error: componentValidation.error });
266 +
}
267 +
268 +
// Delete existing components
269 +
db.prepare("DELETE FROM mood_components WHERE mood_id = ?").run(moodId);
270 +
271 +
// Insert new components
272 +
if (mood_components.length > 0) {
273 +
const componentStmt = db.prepare(`
274 +
INSERT INTO mood_components (mood_id, emotion, intensity)
275 +
VALUES (?, ?, ?)
276 +
`);
277 +
278 +
for (const component of mood_components) {
279 +
componentStmt.run(
280 +
moodId,
281 +
component.emotion.toLowerCase(),
282 +
component.intensity
283 +
);
284 +
}
285 +
}
286 +
}
287 +
288 +
db.prepare("COMMIT").run();
289 +
res.json({ success: true, id: moodId });
290 +
} catch (err) {
291 +
db.prepare("ROLLBACK").run();
292 +
console.error('Error updating mood:', err);
293 +
res.status(500).json({ error: "Erro ao atualizar humor" });
294 +
}
295 +
});
296 +
297 +
// Delete mood entry
298 +
router.delete("/:mood_id", (req, res) => {
299 +
const moodId = req.params.mood_id;
300 +
const db = req.db;
301 +
302 +
const result = db.prepare("DELETE FROM mood WHERE id = ?").run(moodId);
303 +
304 +
if (result.changes === 0) {
305 +
return res.status(404).json({ error: "Humor não encontrado" });
306 +
}
307 +
308 +
res.json({ success: true, deleted: moodId });
309 +
});
310 +
311 +
// Get user's moods with optional date range
312 +
router.get("/user/:user_id", (req, res) => {
313 +
const userId = req.params.user_id;
314 +
const { start_date, end_date, page, limit } = req.query;
315 +
const db = req.db;
316 +
317 +
// Validate pagination
318 +
const { page: validPage, limit: validLimit, offset } = validatePagination(page, limit);
319 +
320 +
let query = `
321 +
SELECT m.*,
322 +
COUNT(mc.id) as component_count
323 +
FROM mood m
324 +
LEFT JOIN mood_components mc ON m.id = mc.mood_id
325 +
WHERE m.user_id = ?
326 +
`;
327 +
const params = [userId];
328 +
329 +
// Add date range filtering
330 +
if (start_date && end_date) {
331 +
if (!isValidDateRange(start_date, end_date)) {
332 +
return res.status(400).json({ error: "Intervalo de datas inválido" });
333 +
}
334 +
query += " AND m.recorded_at BETWEEN ? AND ?";
335 +
params.push(start_date, end_date);
336 +
} else if (start_date) {
337 +
if (!isValidDate(start_date)) {
338 +
return res.status(400).json({ error: "Data de início inválida" });
339 +
}
340 +
query += " AND m.recorded_at >= ?";
341 +
params.push(start_date);
342 +
} else if (end_date) {
343 +
if (!isValidDate(end_date)) {
344 +
return res.status(400).json({ error: "Data de fim inválida" });
345 +
}
346 +
query += " AND m.recorded_at <= ?";
347 +
params.push(end_date);
348 +
}
349 +
350 +
query += " GROUP BY m.id ORDER BY m.recorded_at DESC LIMIT ? OFFSET ?";
351 +
params.push(validLimit, offset);
352 +
353 +
const moods = db.prepare(query).all(...params);
354 +
355 +
// Get components for each mood
356 +
const moodIds = moods.map(m => m.id);
357 +
if (moodIds.length > 0) {
358 +
const componentsQuery = `
359 +
SELECT mood_id, emotion, intensity
360 +
FROM mood_components
361 +
WHERE mood_id IN (${moodIds.map(() => '?').join(',')})
362 +
`;
363 +
364 +
const components = db.prepare(componentsQuery).all(...moodIds);
365 +
366 +
// Group components by mood_id
367 +
const componentsByMood = {};
368 +
components.forEach(c => {
369 +
if (!componentsByMood[c.mood_id]) {
370 +
componentsByMood[c.mood_id] = [];
371 +
}
372 +
componentsByMood[c.mood_id].push({
373 +
emotion: c.emotion,
374 +
intensity: c.intensity
375 +
});
376 +
});
377 +
378 +
// Attach components to moods
379 +
moods.forEach(mood => {
380 +
mood.mood_components = componentsByMood[mood.id] || [];
381 +
if (mood.mood_components.length > 0) {
382 +
mood.emotion_stats = calculateEmotionStats(mood.mood_components);
383 +
}
384 +
});
385 +
}
386 +
387 +
// Get total count for pagination
388 +
let countQuery = "SELECT COUNT(*) as total FROM mood WHERE user_id = ?";
389 +
const countParams = [userId];
390 +
391 +
if (start_date && end_date) {
392 +
countQuery += " AND recorded_at BETWEEN ? AND ?";
393 +
countParams.push(start_date, end_date);
394 +
} else if (start_date) {
395 +
countQuery += " AND recorded_at >= ?";
396 +
countParams.push(start_date);
397 +
} else if (end_date) {
398 +
countQuery += " AND recorded_at <= ?";
399 +
countParams.push(end_date);
400 +
}
401 +
402 +
const { total } = db.prepare(countQuery).get(...countParams);
403 +
404 +
res.json({
405 +
moods,
406 +
pagination: {
407 +
page: validPage,
408 +
limit: validLimit,
409 +
total,
410 +
total_pages: Math.ceil(total / validLimit)
411 +
}
412 +
});
413 +
});
414 +
415 +
// Get mood statistics for a user
416 +
router.get("/user/:user_id/stats", (req, res) => {
417 +
const userId = req.params.user_id;
418 +
const { start_date, end_date } = req.query;
419 +
const db = req.db;
420 +
421 +
let baseQuery = "FROM mood WHERE user_id = ?";
422 +
const params = [userId];
423 +
424 +
if (start_date && end_date) {
425 +
if (!isValidDateRange(start_date, end_date)) {
426 +
return res.status(400).json({ error: "Intervalo de datas inválido" });
427 +
}
428 +
baseQuery += " AND recorded_at BETWEEN ? AND ?";
429 +
params.push(start_date, end_date);
430 +
}
431 +
432 +
// Get aggregated stats
433 +
const statsQuery = `
434 +
SELECT
435 +
COUNT(*) as total_entries,
436 +
AVG(rating) as avg_rating,
437 +
AVG(stress_level) as avg_stress,
438 +
AVG(anxiety_level) as avg_anxiety,
439 +
AVG(energy_level) as avg_energy,
440 +
MIN(stress_level) as min_stress,
441 +
MAX(stress_level) as max_stress,
442 +
MIN(anxiety_level) as min_anxiety,
443 +
MAX(anxiety_level) as max_anxiety,
444 +
MIN(energy_level) as min_energy,
445 +
MAX(energy_level) as max_energy
446 +
${baseQuery}
447 +
`;
448 +
449 +
const stats = db.prepare(statsQuery).get(...params);
450 +
451 +
// Get emotion frequency
452 +
const emotionQuery = `
453 +
SELECT
454 +
mc.emotion,
455 +
COUNT(*) as frequency,
456 +
AVG(mc.intensity) as avg_intensity
457 +
FROM mood_components mc
458 +
JOIN mood m ON mc.mood_id = m.id
459 +
WHERE m.user_id = ?
460 +
${start_date && end_date ? 'AND m.recorded_at BETWEEN ? AND ?' : ''}
461 +
GROUP BY mc.emotion
462 +
ORDER BY frequency DESC
463 +
`;
464 +
465 +
const emotionParams = [...params];
466 +
const emotions = db.prepare(emotionQuery).all(...emotionParams);
467 +
468 +
// Get mood trends by day of week
469 +
const dayTrendsQuery = `
470 +
SELECT
471 +
CASE CAST(strftime('%w', recorded_at) AS INTEGER)
472 +
WHEN 0 THEN 'Sunday'
473 +
WHEN 1 THEN 'Monday'
474 +
WHEN 2 THEN 'Tuesday'
475 +
WHEN 3 THEN 'Wednesday'
476 +
WHEN 4 THEN 'Thursday'
477 +
WHEN 5 THEN 'Friday'
478 +
WHEN 6 THEN 'Saturday'
479 +
END as day_of_week,
480 +
AVG(stress_level) as avg_stress,
481 +
AVG(anxiety_level) as avg_anxiety,
482 +
AVG(energy_level) as avg_energy,
483 +
COUNT(*) as entries
484 +
${baseQuery}
485 +
GROUP BY strftime('%w', recorded_at)
486 +
`;
487 +
488 +
const dayTrends = db.prepare(dayTrendsQuery).all(...params);
489 +
490 +
res.json({
491 +
overall: stats,
492 +
emotions: emotions,
493 +
trends: {
494 +
by_day_of_week: dayTrends
495 +
},
496 +
date_range: {
497 +
start: start_date || 'all time',
498 +
end: end_date || 'all time'
499 +
}
500 +
});
501 +
});
502 +
503 +
export default router;
api/src/routes/users.js
1 1
import express from "express";
2 2
import bcrypt from "bcryptjs";
3 +
import {
4 +
isValidEmail,
5 +
isValidPassword,
6 +
sanitizeString,
7 +
validateRequiredFields
8 +
} from "../utils/validators.js";
3 9
4 10
const router = express.Router();
5 11
6 -
// XXX: Needs translations
12 +
// Create user
7 13
router.post("/", (req, res) => {
8 -
const { email, password, first_name, last_name } = req.body;
9 -
if (!email || !password || !first_name || !last_name)
10 -
return res.status(400).json({ error: "Campos faltantes" });
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 +
}
11 37
12 38
const hashed = bcrypt.hashSync(password, 10);
39 +
const db = req.db;
13 40
14 41
try {
15 -
const stmt = req.db.prepare(
16 -
`
17 -
INSERT INTO users (email, password, first_name, last_name)
18 -
VALUES (?, ?, ?, ?)
19 -
`
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'
20 53
);
21 54
22 -
const result = stmt.run(email, hashed, first_name, last_name);
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 +
}
23 148
24 -
res.status(201).json({ id: result.lastInsertRowid });
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 });
25 197
} catch (err) {
26 -
res.status(400).json({ error: "Email já cadastrado" });
198 +
console.error('Error updating user:', err);
199 +
res.status(500).json({ error: "Erro ao atualizar usuário" });
27 200
}
28 201
});
29 202
30 -
export default router;
203 +
// Delete user
204 +
router.delete("/:user_id", (req, res) => {
205 +
const userId = req.params.user_id;
206 +
const db = req.db;
31 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;