const express = require('express'); const router = express.Router(); const bcrypt = require('bcrypt'); const { query } = require('../config/database'); const { authenticateToken } = require('../middleware/auth'); router.get('/', authenticateToken, async (req, res) => { try { console.log('GET /api/users - User:', req.user); console.log('GET /api/users - Company ID:', req.user.company_id); // Buscar usuários const usersResult = await query( `SELECT id, email, name, role, is_active, created_at FROM users WHERE company_id = $1 ORDER BY created_at DESC`, [req.user.company_id] ); // Buscar contagem de dispositivos por usuário const devicesCountResult = await query( `SELECT user_id, COUNT(*) as devices_count FROM devices WHERE company_id = $1 AND user_id IS NOT NULL GROUP BY user_id`, [req.user.company_id] ); // Criar mapa de contagem de dispositivos const devicesCountMap = {}; devicesCountResult.rows.forEach(row => { devicesCountMap[row.user_id] = parseInt(row.devices_count) || 0; }); // Adicionar contagem de dispositivos aos usuários const users = usersResult.rows.map(user => ({ id: user.id, email: user.email, name: user.name, role: user.role, is_active: user.is_active, created_at: user.created_at, devices_count: devicesCountMap[user.id] || 0 })); console.log('GET /api/users - Resultados encontrados:', users.length); res.json({ success: true, users: users }); } catch (error) { console.error('Erro ao listar usuários:', error); console.error('Erro detalhado:', error.message); console.error('Stack:', error.stack); res.status(500).json({ error: 'Erro ao listar usuários', details: error.message }); } }); router.post('/', authenticateToken, async (req, res) => { try { const { email, name, password } = req.body; if (!email || !name || !password) { return res.status(400).json({ error: 'Email, nome e senha são obrigatórios' }); } // Verificar se o email já existe const existingUser = await query( 'SELECT id FROM users WHERE email = $1', [email.toLowerCase()] ); if (existingUser.rows.length > 0) { return res.status(409).json({ error: 'Este email já está cadastrado' }); } const hashedPassword = await bcrypt.hash(password, 10); const result = await query( 'INSERT INTO users (email, name, password, company_id, is_active) VALUES ($1, $2, $3, $4, true) RETURNING id, email, name, role, is_active', [email.toLowerCase(), name, hashedPassword, req.user.company_id] ); res.status(201).json({ success: true, user: result.rows[0] }); } catch (error) { console.error('Erro ao criar usuário:', error); // Tratamento específico para erros conhecidos if (error.code === '23505') { // Violação de constraint única return res.status(409).json({ error: 'Este email já está cadastrado' }); } res.status(500).json({ error: 'Erro ao criar usuário', details: error.message }); } }); // Rota para obter o perfil do usuário logado (admin) router.get('/me', authenticateToken, async (req, res) => { try { const result = await query( 'SELECT id, email, name, role, company_id, is_active, created_at FROM admin_users WHERE id = $1', [req.user.id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Usuário não encontrado' }); } res.json({ success: true, user: result.rows[0] }); } catch (error) { console.error('Erro ao obter perfil:', error); res.status(500).json({ error: 'Erro ao obter perfil' }); } }); // Rota para alterar a senha do próprio usuário (admin) router.put('/me/password', authenticateToken, async (req, res) => { try { const { currentPassword, newPassword } = req.body; if (!currentPassword || !newPassword) { return res.status(400).json({ error: 'Senha atual e nova senha são obrigatórias' }); } if (newPassword.length < 6) { return res.status(400).json({ error: 'A nova senha deve ter pelo menos 6 caracteres' }); } // Buscar o usuário atual const userResult = await query( 'SELECT id, password FROM admin_users WHERE id = $1', [req.user.id] ); if (userResult.rows.length === 0) { return res.status(404).json({ error: 'Usuário não encontrado' }); } const user = userResult.rows[0]; // Verificar senha atual const validPassword = await bcrypt.compare(currentPassword, user.password); if (!validPassword) { return res.status(401).json({ error: 'Senha atual incorreta' }); } // Hash da nova senha const hashedPassword = await bcrypt.hash(newPassword, 10); // Atualizar senha await query( 'UPDATE admin_users SET password = $1 WHERE id = $2', [hashedPassword, req.user.id] ); res.json({ success: true, message: 'Senha alterada com sucesso' }); } catch (error) { console.error('Erro ao alterar senha:', error); res.status(500).json({ error: 'Erro ao alterar senha' }); } }); // Rota para atualizar perfil do próprio usuário (admin) router.put('/me', authenticateToken, async (req, res) => { try { const { name, email } = req.body; if (!name) { return res.status(400).json({ error: 'Nome é obrigatório' }); } // Se email foi fornecido, verificar se não está em uso por outro usuário if (email) { const existingUser = await query( 'SELECT id FROM admin_users WHERE email = $1 AND id != $2', [email.toLowerCase(), req.user.id] ); if (existingUser.rows.length > 0) { return res.status(409).json({ error: 'Este email já está em uso' }); } } // Atualizar perfil const updateFields = []; const updateValues = []; let paramCount = 1; if (name) { updateFields.push(`name = $${paramCount++}`); updateValues.push(name); } if (email) { updateFields.push(`email = $${paramCount++}`); updateValues.push(email.toLowerCase()); } if (updateFields.length === 0) { return res.status(400).json({ error: 'Nenhum campo para atualizar' }); } updateValues.push(req.user.id); const queryText = `UPDATE admin_users SET ${updateFields.join(', ')} WHERE id = $${paramCount} RETURNING id, email, name, role, company_id, is_active`; const result = await query(queryText, updateValues); res.json({ success: true, user: result.rows[0] }); } catch (error) { console.error('Erro ao atualizar perfil:', error); res.status(500).json({ error: 'Erro ao atualizar perfil' }); } }); // TROCAR SENHA DE UM USUÁRIO (admin pode trocar senha de qualquer usuário) // IMPORTANTE: Esta rota deve vir ANTES de /:id para não ser capturada pela rota genérica router.put('/:id/password', authenticateToken, async (req, res) => { try { const { id } = req.params; const { newPassword } = req.body; const company_id = req.user.company_id; const loggedUserId = req.user.id; // ID do usuário logado (da tabela admin_users) console.log(`🔵 PUT /api/users/${id}/password - Requisição recebida`); console.log(`🔵 Body recebido:`, JSON.stringify({ newPassword: newPassword ? '***' : null }, null, 2)); console.log(`🔵 Company ID:`, company_id); console.log(`🔵 ID do usuário logado:`, loggedUserId); console.log(`🔵 ID do usuário a alterar:`, id); if (!newPassword) { return res.status(400).json({ error: 'Nova senha é obrigatória' }); } if (newPassword.length < 6) { return res.status(400).json({ error: 'A senha deve ter pelo menos 6 caracteres' }); } // IMPORTANTE: Verificar se o usuário a alterar é o próprio usuário logado // Se for, alterar na tabela admin_users. Caso contrário, alterar na tabela users const idNum = parseInt(id); const loggedIdNum = parseInt(loggedUserId); // Buscar email do usuário logado const loggedUserResult = await query( 'SELECT email FROM admin_users WHERE id = $1', [loggedIdNum] ); if (loggedUserResult.rows.length === 0) { return res.status(404).json({ error: 'Usuário logado não encontrado' }); } const loggedUserEmail = loggedUserResult.rows[0].email; // Buscar email do usuário a ser alterado const userToChangeResult = await query( 'SELECT id, email FROM users WHERE id = $1 AND company_id = $2', [idNum, company_id] ); if (userToChangeResult.rows.length === 0) { return res.status(404).json({ error: 'Usuário não encontrado' }); } const userToChangeEmail = userToChangeResult.rows[0].email; // Se o email corresponde ao usuário logado, alterar na tabela admin_users if (userToChangeEmail.toLowerCase() === loggedUserEmail.toLowerCase()) { console.log(`🔵 Email corresponde ao usuário logado - alterando na tabela admin_users`); const adminCheck = await query( 'SELECT id FROM admin_users WHERE email = $1', [loggedUserEmail] ); if (adminCheck.rows.length === 0) { return res.status(404).json({ error: 'Usuário admin não encontrado' }); } const adminId = adminCheck.rows[0].id; // Hash da nova senha const hashedPassword = await bcrypt.hash(newPassword, 10); // Atualizar senha na tabela admin_users await query( 'UPDATE admin_users SET password = $1 WHERE id = $2', [hashedPassword, adminId] ); console.log(`✅ Senha do admin_user ${adminId} (${loggedUserEmail}) alterada com sucesso na tabela admin_users`); } else { // Alterar senha de outro usuário (users) console.log(`🔵 Alterando senha de outro usuário na tabela users`); // Hash da nova senha const hashedPassword = await bcrypt.hash(newPassword, 10); // Atualizar senha na tabela users await query( 'UPDATE users SET password = $1 WHERE id = $2 AND company_id = $3', [hashedPassword, idNum, company_id] ); console.log(`✅ Senha do usuário ${idNum} (${userToChangeEmail}) alterada com sucesso na tabela users`); } res.json({ success: true, message: 'Senha alterada com sucesso' }); } catch (error) { console.error('Erro ao alterar senha do usuário:', error); res.status(500).json({ error: 'Erro ao alterar senha', details: error.message }); } }); // EDITAR USUÁRIO router.put('/:id', authenticateToken, async (req, res) => { try { const { id } = req.params; const { name, email, role, is_active } = req.body; const company_id = req.user.company_id; console.log(`🔵 PUT /api/users/${id} - Requisição recebida`); console.log(`🔵 Body recebido:`, JSON.stringify({ name, email, role, is_active }, null, 2)); console.log(`🔵 Company ID:`, company_id); console.log(`🔵 User ID do token:`, req.user.id); // Verificar se o usuário existe e pertence à company const userCheck = await query( 'SELECT id FROM users WHERE id = $1 AND company_id = $2', [id, company_id] ); if (userCheck.rows.length === 0) { return res.status(404).json({ error: 'Usuário não encontrado' }); } // Se email foi fornecido, verificar se não está em uso por outro usuário if (email) { const existingUser = await query( 'SELECT id FROM users WHERE email = $1 AND id != $2 AND company_id = $3', [email.toLowerCase(), id, company_id] ); if (existingUser.rows.length > 0) { return res.status(409).json({ error: 'Este email já está em uso' }); } } // Construir query dinamicamente const updateFields = []; const updateValues = []; let paramCount = 1; if (name !== undefined) { updateFields.push(`name = $${paramCount++}`); updateValues.push(name); } if (email !== undefined) { updateFields.push(`email = $${paramCount++}`); updateValues.push(email.toLowerCase()); } if (role !== undefined) { updateFields.push(`role = $${paramCount++}`); updateValues.push(role); } if (is_active !== undefined) { updateFields.push(`is_active = $${paramCount++}`); updateValues.push(is_active); } if (updateFields.length === 0) { return res.status(400).json({ error: 'Nenhum campo para atualizar' }); } updateValues.push(id, company_id); const queryText = `UPDATE users SET ${updateFields.join(', ')} WHERE id = $${paramCount++} AND company_id = $${paramCount} RETURNING id, email, name, role, is_active, created_at`; const result = await query(queryText, updateValues); console.log(`✅ Usuário ${id} atualizado com sucesso`); res.json({ success: true, user: result.rows[0] }); } catch (error) { console.error('Erro ao atualizar usuário:', error); console.error('Erro detalhado:', error.message); res.status(500).json({ error: 'Erro ao atualizar usuário', details: error.message }); } }); router.delete('/:id', authenticateToken, async (req, res) => { try { const result = await query( 'DELETE FROM users WHERE id = $1 AND company_id = $2 RETURNING *', [req.params.id, req.user.company_id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Usuário não encontrado' }); } res.json({ success: true, message: 'Usuário deletado' }); } catch (error) { console.error('Erro ao deletar usuário:', error); res.status(500).json({ error: 'Erro ao deletar usuário' }); } }); module.exports = router;