From 34c64bda9aaae75f267b133215d06c2e77eab195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Fri, 29 May 2026 10:56:02 -0300 Subject: [PATCH] Extract backend team routes --- backend/index.js | 91 ++-------------------------------- backend/routes/teamsRoutes.js | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 88 deletions(-) create mode 100644 backend/routes/teamsRoutes.js diff --git a/backend/index.js b/backend/index.js index 1b164eb..9b84e01 100644 --- a/backend/index.js +++ b/backend/index.js @@ -13,6 +13,7 @@ const { allowedOrigins, getBaseUrl, getStartupBaseUrl, isProduction, jwtSecret: const { authenticateToken, requireRole } = require('./middleware/auth'); const { createAuthRouter } = require('./routes/authRoutes'); const { createUsersRouter } = require('./routes/usersRoutes'); +const { createTeamsRouter } = require('./routes/teamsRoutes'); const { canReadAttendance } = require('./policies/accessPolicy'); const app = express(); @@ -72,6 +73,8 @@ apiRouter.use(createAuthRouter({ pool, transporter, getBaseUrl, jwtSecret: JWT_S apiRouter.use(createUsersRouter({ pool, upload, transporter, getBaseUrl })); +apiRouter.use(createTeamsRouter({ pool })); + // --- Notifications Routes --- apiRouter.get('/notifications', async (req, res) => { try { @@ -736,94 +739,6 @@ apiRouter.get('/tenants', requireRole(['super_admin']), async (req, res) => { } catch (error) { res.status(500).json({ error: error.message }); } }); -// --- Team Routes --- -apiRouter.get('/teams', async (req, res) => { - try { - const { tenantId } = req.query; - const effectiveTenantId = req.user.role === 'super_admin' ? tenantId : req.user.tenant_id; - - let q = 'SELECT * FROM teams'; - const params = []; - if (effectiveTenantId && effectiveTenantId !== 'all') { - q += ' WHERE tenant_id = ?'; - params.push(effectiveTenantId); - } - - // Strict RBAC: Managers can only see their own team - if (req.user.role === 'manager') { - if (req.user.team_id) { - q += (params.length > 0 ? ' AND' : ' WHERE') + ' id = ?'; - params.push(req.user.team_id); - } else { - // If a manager doesn't have a team, return nothing to prevent showing all teams - q += (params.length > 0 ? ' AND' : ' WHERE') + ' 1=0'; - } - } - - const [rows] = await pool.query(q, params); - res.json(rows); - } catch (error) { - res.status(500).json({ error: error.message }); - } -}); - -apiRouter.post('/teams', requireRole(['admin', 'super_admin']), async (req, res) => { - const { name, description, tenantId } = req.body; - const effectiveTenantId = req.user.role === 'super_admin' ? tenantId : req.user.tenant_id; - try { - const tid = `team_${crypto.randomUUID().split('-')[0]}`; - await pool.query( - 'INSERT INTO teams (id, tenant_id, name, description) VALUES (?, ?, ?, ?)', - [tid, effectiveTenantId, name, description || null] - ); - res.status(201).json({ id: tid, message: 'Time criado com sucesso.' }); - } catch (error) { - console.error('Create team error:', error); - res.status(500).json({ error: error.message }); - } -}); - -apiRouter.put('/teams/:id', requireRole(['admin', 'super_admin']), async (req, res) => { - const { name, description } = req.body; - try { - const [existing] = await pool.query('SELECT tenant_id FROM teams WHERE id = ?', [req.params.id]); - if (existing.length === 0) return res.status(404).json({ error: 'Not found' }); - if (req.user.role !== 'super_admin' && existing[0].tenant_id !== req.user.tenant_id) { - return res.status(403).json({ error: 'Acesso negado.' }); - } - - await pool.query( - 'UPDATE teams SET name = ?, description = ? WHERE id = ?', - [name, description || null, req.params.id] - ); - res.json({ message: 'Team updated successfully.' }); - } catch (error) { - console.error('Update team error:', error); - res.status(500).json({ error: error.message }); - } -}); - -apiRouter.delete('/teams/:id', requireRole(['admin', 'super_admin']), async (req, res) => { - try { - const [existing] = await pool.query('SELECT tenant_id FROM teams WHERE id = ?', [req.params.id]); - if (existing.length === 0) return res.status(404).json({ error: 'Not found' }); - if (req.user.role !== 'super_admin' && existing[0].tenant_id !== req.user.tenant_id) { - return res.status(403).json({ error: 'Acesso negado.' }); - } - - // Set users team_id to NULL to prevent orphan foreign key issues if constrained - await pool.query('UPDATE users SET team_id = NULL WHERE team_id = ?', [req.params.id]); - await pool.query('DELETE FROM teams WHERE id = ?', [req.params.id]); - - res.json({ message: 'Team deleted successfully.' }); - } catch (error) { - console.error('Delete team error:', error); - res.status(500).json({ error: error.message }); - } -}); - - - apiRouter.post('/tenants', requireRole(['super_admin']), async (req, res) => { const { name, slug, admin_email, status } = req.body; const connection = await pool.getConnection(); diff --git a/backend/routes/teamsRoutes.js b/backend/routes/teamsRoutes.js new file mode 100644 index 0000000..bb76c0a --- /dev/null +++ b/backend/routes/teamsRoutes.js @@ -0,0 +1,93 @@ +const express = require('express'); +const crypto = require('crypto'); +const { requireRole } = require('../middleware/auth'); + +const createTeamsRouter = ({ pool }) => { + const router = express.Router(); + + router.get('/teams', async (req, res) => { + try { + const { tenantId } = req.query; + const effectiveTenantId = req.user.role === 'super_admin' ? tenantId : req.user.tenant_id; + + let q = 'SELECT * FROM teams'; + const params = []; + if (effectiveTenantId && effectiveTenantId !== 'all') { + q += ' WHERE tenant_id = ?'; + params.push(effectiveTenantId); + } + + if (req.user.role === 'manager') { + if (req.user.team_id) { + q += (params.length > 0 ? ' AND' : ' WHERE') + ' id = ?'; + params.push(req.user.team_id); + } else { + q += (params.length > 0 ? ' AND' : ' WHERE') + ' 1=0'; + } + } + + const [rows] = await pool.query(q, params); + res.json(rows); + } catch (error) { + res.status(500).json({ error: error.message }); + } + }); + + router.post('/teams', requireRole(['admin', 'super_admin']), async (req, res) => { + const { name, description, tenantId } = req.body; + const effectiveTenantId = req.user.role === 'super_admin' ? tenantId : req.user.tenant_id; + try { + const tid = `team_${crypto.randomUUID().split('-')[0]}`; + await pool.query( + 'INSERT INTO teams (id, tenant_id, name, description) VALUES (?, ?, ?, ?)', + [tid, effectiveTenantId, name, description || null] + ); + res.status(201).json({ id: tid, message: 'Time criado com sucesso.' }); + } catch (error) { + console.error('Create team error:', error); + res.status(500).json({ error: error.message }); + } + }); + + router.put('/teams/:id', requireRole(['admin', 'super_admin']), async (req, res) => { + const { name, description } = req.body; + try { + const [existing] = await pool.query('SELECT tenant_id FROM teams WHERE id = ?', [req.params.id]); + if (existing.length === 0) return res.status(404).json({ error: 'Not found' }); + if (req.user.role !== 'super_admin' && existing[0].tenant_id !== req.user.tenant_id) { + return res.status(403).json({ error: 'Acesso negado.' }); + } + + await pool.query( + 'UPDATE teams SET name = ?, description = ? WHERE id = ?', + [name, description || null, req.params.id] + ); + res.json({ message: 'Team updated successfully.' }); + } catch (error) { + console.error('Update team error:', error); + res.status(500).json({ error: error.message }); + } + }); + + router.delete('/teams/:id', requireRole(['admin', 'super_admin']), async (req, res) => { + try { + const [existing] = await pool.query('SELECT tenant_id FROM teams WHERE id = ?', [req.params.id]); + if (existing.length === 0) return res.status(404).json({ error: 'Not found' }); + if (req.user.role !== 'super_admin' && existing[0].tenant_id !== req.user.tenant_id) { + return res.status(403).json({ error: 'Acesso negado.' }); + } + + await pool.query('UPDATE users SET team_id = NULL WHERE team_id = ?', [req.params.id]); + await pool.query('DELETE FROM teams WHERE id = ?', [req.params.id]); + + res.json({ message: 'Team deleted successfully.' }); + } catch (error) { + console.error('Delete team error:', error); + res.status(500).json({ error: error.message }); + } + }); + + return router; +}; + +module.exports = { createTeamsRouter };