/** * WordPress Monitor API Route * Receives data from Descomplicar Monitor WordPress plugin * POST /api/wp-monitor - Receive site data * GET /api/wp-monitor - List monitored sites * GET /api/wp-monitor?test - Connection test * @author Descomplicar® | @link descomplicar.pt | @copyright 2026 */ import { Router } from 'express' import type { Request, Response } from 'express' import db from '../db.js' const router = Router() // Validação obrigatória da API key const API_KEY = process.env.WP_MONITOR_API_KEY if (!API_KEY) { throw new Error('WP_MONITOR_API_KEY environment variable is required') } // Middleware to validate API key function validateApiKey(req: Request, res: Response, next: Function) { const apiKey = req.headers['x-api-key'] || req.query.key if (apiKey !== API_KEY) { return res.status(401).json({ error: 'Unauthorized', message: 'Invalid API Key' }) } next() } // Test endpoint router.get('/', validateApiKey, async (req: Request, res: Response) => { // Test connection if (req.query.test !== undefined) { return res.json({ success: true, message: 'Connection OK', timestamp: new Date().toISOString() }) } // List all WordPress sites try { const [sites] = await db.query(` SELECT name, status, details, last_check FROM tbl_eal_monitoring WHERE category = 'site' ORDER BY name ASC `) const result = (sites as any[]).map(site => ({ name: site.name, status: site.status, last_check: site.last_check, data: typeof site.details === 'string' ? JSON.parse(site.details) : site.details })) res.json({ success: true, sites: result, total: result.length, timestamp: new Date().toISOString() }) } catch (error) { console.error('WP Monitor GET error:', error) res.status(500).json({ error: 'Database error', message: (error as Error).message }) } }) // Receive data from WordPress plugin router.post('/', validateApiKey, async (req: Request, res: Response) => { const data = req.body if (!data || !data.site_url) { return res.status(400).json({ error: 'Bad Request', message: 'Invalid JSON or missing site_url' }) } try { const siteUrl = data.site_url.replace(/\/$/, '') const siteName = data.site_name || new URL(siteUrl).hostname // Determine status based on data const status = determineStatus(data) const jsonData = JSON.stringify(data) // Check if site exists const [existing] = await db.query( 'SELECT id FROM tbl_eal_monitoring WHERE category = ? AND name = ?', ['site', siteName] ) if ((existing as any[]).length > 0) { // Update existing await db.query( 'UPDATE tbl_eal_monitoring SET details = ?, status = ?, last_check = NOW() WHERE category = ? AND name = ?', [jsonData, status, 'site', siteName] ) } else { // Insert new await db.query( 'INSERT INTO tbl_eal_monitoring (name, category, status, details, last_check) VALUES (?, ?, ?, ?, NOW())', [siteName, 'site', status, jsonData] ) } console.log(`[WP-Monitor] Received data from: ${siteUrl} - Status: ${status}`) res.json({ success: true, message: 'Data received', site: siteName, status, timestamp: new Date().toISOString() }) } catch (error) { console.error('WP Monitor POST error:', error) res.status(500).json({ error: 'Database error', message: (error as Error).message }) } }) /** * Determine status based on WordPress data */ function determineStatus(data: any): string { // Critical conditions if (data.health?.status === 'critical') { return 'failed' } let warnings = 0 // Many pending updates if (data.updates?.counts?.total > 5) warnings++ // Core update pending if (data.updates?.core?.length > 0) warnings++ // Debug mode in production if (data.system?.debug_mode === true) warnings++ // Health issues if (data.health?.issues?.length > 0) { warnings += data.health.issues.length } // Large database (>500MB) if (data.database?.size_mb > 500) warnings++ if (warnings >= 3) return 'warning' return 'ok' } export default router