// Rotas para gerenciamento de políticas MDM const express = require('express'); const router = express.Router(); const { Pool } = require('pg'); const pool = new Pool({ connectionString: process.env.DATABASE_URL }); // Listar todas as políticas router.get('/', async (req, res) => { try { const result = await pool.query(` SELECT p.*, COUNT(DISTINCT dp.device_id) as devices_count, COUNT(DISTINCT pe.id) FILTER (WHERE pe.status = 'success') as success_count, COUNT(DISTINCT pe.id) FILTER (WHERE pe.status = 'failed') as failed_count FROM policies p LEFT JOIN device_policies dp ON p.id = dp.policy_id LEFT JOIN policy_executions pe ON p.id = pe.policy_id GROUP BY p.id ORDER BY p.created_at DESC `); res.json({ success: true, policies: result.rows }); } catch (error) { console.error('Erro ao listar políticas:', error); res.status(500).json({ success: false, message: error.message }); } }); // Criar nova política router.post('/', async (req, res) => { try { const { name, description, type, config, enabled, schedule, priority } = req.body; const result = await pool.query(` INSERT INTO policies ( name, description, type, config, enabled, schedule, priority ) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING * `, [name, description, type, JSON.stringify(config), enabled, schedule, priority || 5]); console.log(`✅ Política criada: ${name} (${type})`); res.json({ success: true, policy: result.rows[0] }); } catch (error) { console.error('Erro ao criar política:', error); res.status(500).json({ success: false, message: error.message }); } }); // Atualizar política router.put('/:id', async (req, res) => { try { const { id } = req.params; const { name, description, type, config, enabled, schedule, priority } = req.body; const result = await pool.query(` UPDATE policies SET name = $1, description = $2, type = $3, config = $4, enabled = $5, schedule = $6, priority = $7, updated_at = NOW() WHERE id = $8 RETURNING * `, [name, description, type, JSON.stringify(config), enabled, schedule, priority, id]); if (result.rows.length === 0) { return res.status(404).json({ success: false, message: 'Política não encontrada' }); } console.log(`✅ Política atualizada: ${name}`); res.json({ success: true, policy: result.rows[0] }); } catch (error) { console.error('Erro ao atualizar política:', error); res.status(500).json({ success: false, message: error.message }); } }); // Deletar política router.delete('/:id', async (req, res) => { try { const { id } = req.params; // Remover associações com dispositivos await pool.query('DELETE FROM device_policies WHERE policy_id = $1', [id]); // Remover política const result = await pool.query('DELETE FROM policies WHERE id = $1 RETURNING *', [id]); if (result.rows.length === 0) { return res.status(404).json({ success: false, message: 'Política não encontrada' }); } console.log(`✅ Política deletada: ${result.rows[0].name}`); res.json({ success: true, message: 'Política deletada com sucesso' }); } catch (error) { console.error('Erro ao deletar política:', error); res.status(500).json({ success: false, message: error.message }); } }); // Associar política a dispositivos router.post('/:id/devices', async (req, res) => { try { const { id } = req.params; const { device_ids } = req.body; // Array de device_ids if (!Array.isArray(device_ids) || device_ids.length === 0) { return res.status(400).json({ success: false, message: 'device_ids deve ser um array não vazio' }); } // Inserir associações const values = device_ids.map(device_id => `('${device_id}', ${id})`).join(','); await pool.query(` INSERT INTO device_policies (device_id, policy_id) VALUES ${values} ON CONFLICT (device_id, policy_id) DO NOTHING `); console.log(`✅ Política ${id} associada a ${device_ids.length} dispositivo(s)`); res.json({ success: true, message: `Política aplicada a ${device_ids.length} dispositivo(s)` }); } catch (error) { console.error('Erro ao associar política:', error); res.status(500).json({ success: false, message: error.message }); } }); // Remover política de dispositivos router.delete('/:id/devices', async (req, res) => { try { const { id } = req.params; const { device_ids } = req.body; if (!Array.isArray(device_ids) || device_ids.length === 0) { return res.status(400).json({ success: false, message: 'device_ids deve ser um array não vazio' }); } const result = await pool.query(` DELETE FROM device_policies WHERE policy_id = $1 AND device_id = ANY($2) `, [id, device_ids]); console.log(`✅ Política ${id} removida de ${result.rowCount} dispositivo(s)`); res.json({ success: true, message: `Política removida de ${result.rowCount} dispositivo(s)` }); } catch (error) { console.error('Erro ao remover política:', error); res.status(500).json({ success: false, message: error.message }); } }); // Executar política agora (forçar execução imediata) router.post('/:id/execute', async (req, res) => { try { const { id } = req.params; const { device_ids } = req.body; // Se não fornecido, executa em todos os dispositivos com a política // Buscar política const policyResult = await pool.query('SELECT * FROM policies WHERE id = $1', [id]); if (policyResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Política não encontrada' }); } const policy = policyResult.rows[0]; // Buscar dispositivos let devicesQuery; if (device_ids && device_ids.length > 0) { devicesQuery = await pool.query(` SELECT DISTINCT d.device_id, d.device_name FROM devices d WHERE d.device_id = ANY($1) AND d.status = 'online' `, [device_ids]); } else { devicesQuery = await pool.query(` SELECT DISTINCT d.device_id, d.device_name FROM devices d INNER JOIN device_policies dp ON d.device_id = dp.device_id WHERE dp.policy_id = $1 AND d.status = 'online' `, [id]); } if (devicesQuery.rows.length === 0) { return res.json({ success: false, message: 'Nenhum dispositivo online encontrado para executar a política' }); } // Criar comandos de execução para cada dispositivo const commands = []; for (const device of devicesQuery.rows) { const commandResult = await pool.query(` INSERT INTO policy_commands ( device_id, policy_id, command_type, command_data, status ) VALUES ($1, $2, $3, $4, 'pending') RETURNING id `, [ device.device_id, id, policy.type, JSON.stringify(policy.config) ]); commands.push({ command_id: commandResult.rows[0].id, device_id: device.device_id, device_name: device.device_name }); } console.log(`✅ Política ${policy.name} enfileirada para ${commands.length} dispositivo(s)`); res.json({ success: true, message: `Política enfileirada para ${commands.length} dispositivo(s)`, commands }); } catch (error) { console.error('Erro ao executar política:', error); res.status(500).json({ success: false, message: error.message }); } }); // Ver histórico de execuções de uma política router.get('/:id/executions', async (req, res) => { try { const { id } = req.params; const { limit = 50, offset = 0 } = req.query; const result = await pool.query(` SELECT pe.*, d.device_name, d.hostname FROM policy_executions pe INNER JOIN devices d ON pe.device_id = d.device_id WHERE pe.policy_id = $1 ORDER BY pe.executed_at DESC LIMIT $2 OFFSET $3 `, [id, limit, offset]); const countResult = await pool.query( 'SELECT COUNT(*) FROM policy_executions WHERE policy_id = $1', [id] ); res.json({ success: true, executions: result.rows, total: parseInt(countResult.rows[0].count) }); } catch (error) { console.error('Erro ao buscar execuções:', error); res.status(500).json({ success: false, message: error.message }); } }); // Ver dispositivos com a política aplicada router.get('/:id/devices', async (req, res) => { try { const { id } = req.params; const result = await pool.query(` SELECT d.*, dp.assigned_at, pe.last_execution, pe.last_status FROM devices d INNER JOIN device_policies dp ON d.device_id = dp.device_id LEFT JOIN LATERAL ( SELECT executed_at as last_execution, status as last_status FROM policy_executions WHERE device_id = d.device_id AND policy_id = $1 ORDER BY executed_at DESC LIMIT 1 ) pe ON true WHERE dp.policy_id = $1 ORDER BY d.device_name `, [id]); res.json({ success: true, devices: result.rows }); } catch (error) { console.error('Erro ao buscar dispositivos:', error); res.status(500).json({ success: false, message: error.message }); } }); module.exports = router;