const express = require('express'); const router = express.Router(); const Joi = require('joi'); const { validateRequest } = require('../middleware/validation'); const { Device, Heartbeat, DroneDetection } = require('../models'); const { Op } = require('sequelize'); // Validation schemas const approveDeviceSchema = Joi.object({ device_id: Joi.number().integer().required(), approved: Joi.boolean().required() }); const updateDeviceSchema = Joi.object({ name: Joi.string().optional(), geo_lat: Joi.number().min(-90).max(90).optional(), geo_lon: Joi.number().min(-180).max(180).optional(), location_description: Joi.string().optional(), is_active: Joi.boolean().optional(), heartbeat_interval: Joi.number().integer().min(30).optional(), notes: Joi.string().allow('').optional() }); // GET /api/devices - List all devices with approval status router.get('/', async (req, res) => { try { const devices = await Device.findAll({ attributes: [ 'id', 'name', 'geo_lat', 'geo_lon', 'location_description', 'is_active', 'is_approved', 'last_heartbeat', 'heartbeat_interval', 'firmware_version', 'installation_date', 'notes', 'created_at' ], order: [['created_at', 'DESC']] }); // Add status information const devicesWithStatus = devices.map(device => { const lastHeartbeat = device.last_heartbeat; const heartbeatInterval = device.heartbeat_interval || 300; const now = new Date(); const timeSinceHeartbeat = lastHeartbeat ? (now - new Date(lastHeartbeat)) / 1000 : null; let status = 'unknown'; if (!device.is_approved) { status = 'pending_approval'; } else if (!device.is_active) { status = 'inactive'; } else if (timeSinceHeartbeat && timeSinceHeartbeat > heartbeatInterval * 2) { status = 'offline'; } else if (timeSinceHeartbeat && timeSinceHeartbeat <= heartbeatInterval * 2) { status = 'online'; } return { ...device.toJSON(), status, time_since_heartbeat: timeSinceHeartbeat }; }); res.json({ success: true, data: devicesWithStatus }); } catch (error) { console.error('Error fetching devices:', error); res.status(500).json({ success: false, error: 'Failed to fetch devices' }); } }); // GET /api/devices/pending - List devices pending approval router.get('/pending', async (req, res) => { try { const pendingDevices = await Device.findAll({ where: { is_approved: false }, attributes: [ 'id', 'name', 'geo_lat', 'geo_lon', 'last_heartbeat', 'created_at', 'firmware_version' ], order: [['created_at', 'DESC']] }); res.json({ success: true, data: pendingDevices }); } catch (error) { console.error('Error fetching pending devices:', error); res.status(500).json({ success: false, error: 'Failed to fetch pending devices' }); } }); // POST /api/devices/:id/approve - Approve or reject a device router.post('/:id/approve', validateRequest(approveDeviceSchema), async (req, res) => { try { const deviceId = parseInt(req.params.id); const { approved } = req.body; const device = await Device.findByPk(deviceId); if (!device) { return res.status(404).json({ success: false, error: 'Device not found' }); } await device.update({ is_approved: approved }); // Emit real-time notification const { io } = require('../index'); if (io) { io.emit('device_approval_updated', { device_id: deviceId, approved: approved, timestamp: new Date().toISOString(), message: approved ? `Device ${deviceId} has been approved` : `Device ${deviceId} approval has been revoked` }); } console.log(`${approved ? '✅' : '❌'} Device ${deviceId} approval ${approved ? 'granted' : 'revoked'}`); res.json({ success: true, data: device, message: approved ? 'Device approved successfully' : 'Device approval revoked' }); } catch (error) { console.error('Error updating device approval:', error); res.status(500).json({ success: false, error: 'Failed to update device approval' }); } }); // PUT /api/devices/:id - Update device information router.put('/:id', validateRequest(updateDeviceSchema), async (req, res) => { try { const deviceId = parseInt(req.params.id); const updateData = req.body; const device = await Device.findByPk(deviceId); if (!device) { return res.status(404).json({ success: false, error: 'Device not found' }); } await device.update(updateData); // Emit real-time notification const { io } = require('../index'); if (io) { io.emit('device_updated', { device_id: deviceId, updates: updateData, timestamp: new Date().toISOString() }); } console.log(`📝 Device ${deviceId} updated`); res.json({ success: true, data: device, message: 'Device updated successfully' }); } catch (error) { console.error('Error updating device:', error); res.status(500).json({ success: false, error: 'Failed to update device' }); } }); // DELETE /api/devices/:id - Delete a device and all its data router.delete('/:id', async (req, res) => { try { const deviceId = parseInt(req.params.id); const device = await Device.findByPk(deviceId); if (!device) { return res.status(404).json({ success: false, error: 'Device not found' }); } // Delete related data first (due to foreign key constraints) await DroneDetection.destroy({ where: { device_id: deviceId } }); await Heartbeat.destroy({ where: { device_id: deviceId } }); // Delete the device await device.destroy(); // Emit real-time notification const { io } = require('../index'); if (io) { io.emit('device_deleted', { device_id: deviceId, timestamp: new Date().toISOString(), message: `Device ${deviceId} has been deleted` }); } console.log(`🗑️ Device ${deviceId} and all related data deleted`); res.json({ success: true, message: 'Device deleted successfully' }); } catch (error) { console.error('Error deleting device:', error); res.status(500).json({ success: false, error: 'Failed to delete device' }); } }); // GET /api/devices/:id/stats - Get device statistics router.get('/:id/stats', async (req, res) => { try { const deviceId = parseInt(req.params.id); const days = parseInt(req.query.days) || 7; const device = await Device.findByPk(deviceId); if (!device) { return res.status(404).json({ success: false, error: 'Device not found' }); } const startDate = new Date(); startDate.setDate(startDate.getDate() - days); // Get heartbeat count const heartbeatCount = await Heartbeat.count({ where: { device_id: deviceId, received_at: { [Op.gte]: startDate } } }); // Get detection count const detectionCount = await DroneDetection.count({ where: { device_id: deviceId, server_timestamp: { [Op.gte]: startDate } } }); // Get latest heartbeat const latestHeartbeat = await Heartbeat.findOne({ where: { device_id: deviceId }, order: [['received_at', 'DESC']], attributes: ['received_at', 'signal_strength', 'battery_level', 'temperature'] }); res.json({ success: true, data: { device_id: deviceId, period_days: days, heartbeat_count: heartbeatCount, detection_count: detectionCount, latest_heartbeat: latestHeartbeat, uptime_percentage: heartbeatCount > 0 ? Math.min(100, (heartbeatCount / (days * 24 * 12)) * 100) : 0 // Assuming 5min intervals } }); } catch (error) { console.error('Error fetching device stats:', error); res.status(500).json({ success: false, error: 'Failed to fetch device statistics' }); } }); module.exports = router;