// Rotas MDM para cliente Windows buscar e executar comandos const express = require('express'); const router = express.Router(); const { query } = require('../config/database'); // Cliente busca comandos pendentes router.post('/commands/poll', async (req, res) => { try { const { device_id } = req.body; if (!device_id) { return res.status(400).json({ success: false, message: 'device_id é obrigatório' }); } // Buscar comandos pendentes ordenados por prioridade const result = await pool.query(` SELECT pc.*, p.name as policy_name, p.description as policy_description FROM policy_commands pc INNER JOIN policies p ON pc.policy_id = p.id WHERE pc.device_id = $1 AND pc.status IN ('pending', 'sent') AND pc.retry_count < pc.max_retries ORDER BY pc.priority DESC, pc.created_at ASC LIMIT 10 `, [device_id]); if (result.rows.length > 0) { // Marcar comandos como 'sent' const commandIds = result.rows.map(r => r.id); await pool.query(` UPDATE policy_commands SET status = 'sent', sent_at = NOW() WHERE id = ANY($1) AND status = 'pending' `, [commandIds]); console.log(`📤 Enviando ${result.rows.length} comando(s) para ${device_id}`); } res.json({ success: true, commands: result.rows.map(cmd => ({ command_id: cmd.id, policy_id: cmd.policy_id, policy_name: cmd.policy_name, policy_description: cmd.policy_description, command_type: cmd.command_type, command_data: cmd.command_data, priority: cmd.priority })) }); } catch (error) { console.error('Erro ao buscar comandos:', error); res.status(500).json({ success: false, message: error.message }); } }); // Cliente reporta início de execução router.post('/commands/:id/start', async (req, res) => { try { const { id } = req.params; await pool.query(` UPDATE policy_commands SET status = 'executing' WHERE id = $1 `, [id]); res.json({ success: true, message: 'Execução iniciada' }); } catch (error) { console.error('Erro ao iniciar execução:', error); res.status(500).json({ success: false, message: error.message }); } }); // Cliente reporta resultado da execução router.post('/commands/:id/result', async (req, res) => { try { const { id } = req.params; const { status, // 'success' ou 'failed' result, error_message, duration_seconds } = req.body; // Buscar informações do comando const commandResult = await pool.query(` SELECT device_id, policy_id FROM policy_commands WHERE id = $1 `, [id]); if (commandResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Comando não encontrado' }); } const { device_id, policy_id } = commandResult.rows[0]; // Atualizar comando if (status === 'success') { await pool.query(` UPDATE policy_commands SET status = $1, completed_at = NOW(), result = $2 WHERE id = $3 `, [status, JSON.stringify(result), id]); } else { // Se falhou, incrementar retry_count await pool.query(` UPDATE policy_commands SET status = $1, completed_at = NOW(), result = $2, error_message = $3, retry_count = retry_count + 1 WHERE id = $4 `, [status, JSON.stringify(result), error_message, id]); } // Registrar no histórico await pool.query(` INSERT INTO policy_executions ( device_id, policy_id, command_id, status, duration_seconds, result, error_message ) VALUES ($1, $2, $3, $4, $5, $6, $7) `, [ device_id, policy_id, id, status, duration_seconds, JSON.stringify(result), error_message ]); console.log(`${status === 'success' ? '✅' : '❌'} Comando ${id} executado: ${status}`); res.json({ success: true, message: 'Resultado registrado' }); } catch (error) { console.error('Erro ao registrar resultado:', error); res.status(500).json({ success: false, message: error.message }); } }); // Buscar políticas aplicadas ao dispositivo router.get('/policies/:device_id', async (req, res) => { try { const { device_id } = req.params; const result = await pool.query(` SELECT p.*, dp.assigned_at, pe.last_execution, pe.last_status FROM policies p INNER JOIN device_policies dp ON p.id = dp.policy_id LEFT JOIN LATERAL ( SELECT executed_at as last_execution, status as last_status FROM policy_executions WHERE device_id = $1 AND policy_id = p.id ORDER BY executed_at DESC LIMIT 1 ) pe ON true WHERE dp.device_id = $1 AND p.enabled = true ORDER BY p.priority DESC, p.name `, [device_id]); res.json({ success: true, policies: result.rows }); } catch (error) { console.error('Erro ao buscar políticas:', error); res.status(500).json({ success: false, message: error.message }); } }); // Listar templates de políticas disponíveis router.get('/templates', async (req, res) => { try { const { category } = req.query; let sqlQuery = 'SELECT * FROM policy_templates'; const params = []; if (category) { sqlQuery += ' WHERE category = $1'; params.push(category); } sqlQuery += ' ORDER BY category, name'; const result = await query(sqlQuery, params); res.json({ success: true, templates: result.rows }); } catch (error) { console.error('Erro ao buscar templates:', error); res.status(500).json({ success: false, message: error.message }); } }); // Estatísticas de comandos por dispositivo router.get('/stats/:device_id', async (req, res) => { try { const { device_id } = req.params; const stats = await pool.query(` SELECT COUNT(*) FILTER (WHERE status = 'pending') as pending, COUNT(*) FILTER (WHERE status = 'sent') as sent, COUNT(*) FILTER (WHERE status = 'executing') as executing, COUNT(*) FILTER (WHERE status = 'success') as success, COUNT(*) FILTER (WHERE status = 'failed') as failed FROM policy_commands WHERE device_id = $1 AND created_at > NOW() - INTERVAL '7 days' `, [device_id]); const recentExecutions = await pool.query(` SELECT status, COUNT(*) as count FROM policy_executions WHERE device_id = $1 AND executed_at > NOW() - INTERVAL '30 days' GROUP BY status `, [device_id]); res.json({ success: true, commands: stats.rows[0], recent_executions: recentExecutions.rows }); } catch (error) { console.error('Erro ao buscar estatísticas:', error); res.status(500).json({ success: false, message: error.message }); } }); module.exports = router;