const express = require('express'); const { authenticateToken } = require('../middleware/auth'); const db = require('../database'); const { triggerWebhook } = require('../utils/webhooks'); const router = express.Router(); // Get all webhooks (admin only) router.get('/', authenticateToken, (req, res) => { try { const webhooks = db.prepare(` SELECT id, name, url, events, enabled, created_at FROM webhooks ORDER BY created_at DESC `).all(); // Parse events JSON for each webhook const webhooksWithParsedEvents = webhooks.map(webhook => ({ ...webhook, events: JSON.parse(webhook.events), enabled: webhook.enabled === 1 })); res.json(webhooksWithParsedEvents); } catch (error) { res.status(500).json({ error: error.message }); } }); // Get single webhook by ID (admin only) router.get('/:id', authenticateToken, (req, res) => { try { const webhook = db.prepare(` SELECT id, name, url, events, enabled, created_at FROM webhooks WHERE id = ? `).get(req.params.id); if (!webhook) { return res.status(404).json({ error: 'Webhook not found' }); } res.json({ ...webhook, events: JSON.parse(webhook.events), enabled: webhook.enabled === 1 }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Create new webhook (admin only) router.post('/', authenticateToken, (req, res) => { try { const { name, url, secret, events } = req.body; // Validate required fields if (!name || !url || !secret || !events) { return res.status(400).json({ error: 'Missing required fields: name, url, secret, events' }); } // Validate events is an array if (!Array.isArray(events)) { return res.status(400).json({ error: 'events must be an array' }); } // Validate URL format try { new URL(url); } catch (err) { return res.status(400).json({ error: 'Invalid URL format' }); } // Insert webhook const stmt = db.prepare(` INSERT INTO webhooks (name, url, secret, events, enabled) VALUES (?, ?, ?, ?, 1) `); const result = stmt.run(name, url, secret, JSON.stringify(events)); const newWebhook = db.prepare(` SELECT id, name, url, events, enabled, created_at FROM webhooks WHERE id = ? `).get(result.lastInsertRowid); res.status(201).json({ ...newWebhook, events: JSON.parse(newWebhook.events), enabled: newWebhook.enabled === 1, message: 'Webhook created successfully' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Update webhook (admin only) router.patch('/:id', authenticateToken, (req, res) => { try { const { name, url, secret, events, enabled } = req.body; const webhookId = req.params.id; // Check if webhook exists const webhook = db.prepare('SELECT * FROM webhooks WHERE id = ?').get(webhookId); if (!webhook) { return res.status(404).json({ error: 'Webhook not found' }); } // Build update query dynamically based on provided fields const updates = []; const params = []; if (name !== undefined) { updates.push('name = ?'); params.push(name); } if (url !== undefined) { // Validate URL format try { new URL(url); } catch (err) { return res.status(400).json({ error: 'Invalid URL format' }); } updates.push('url = ?'); params.push(url); } if (secret !== undefined) { updates.push('secret = ?'); params.push(secret); } if (events !== undefined) { if (!Array.isArray(events)) { return res.status(400).json({ error: 'events must be an array' }); } updates.push('events = ?'); params.push(JSON.stringify(events)); } if (enabled !== undefined) { updates.push('enabled = ?'); params.push(enabled ? 1 : 0); } if (updates.length === 0) { return res.status(400).json({ error: 'No fields to update' }); } params.push(webhookId); const stmt = db.prepare(` UPDATE webhooks SET ${updates.join(', ')} WHERE id = ? `); stmt.run(...params); const updatedWebhook = db.prepare(` SELECT id, name, url, events, enabled, created_at FROM webhooks WHERE id = ? `).get(webhookId); res.json({ ...updatedWebhook, events: JSON.parse(updatedWebhook.events), enabled: updatedWebhook.enabled === 1, message: 'Webhook updated successfully' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Delete webhook (admin only) router.delete('/:id', authenticateToken, (req, res) => { try { const webhook = db.prepare('SELECT * FROM webhooks WHERE id = ?').get(req.params.id); if (!webhook) { return res.status(404).json({ error: 'Webhook not found' }); } // Delete webhook (logs will be cascade deleted) db.prepare('DELETE FROM webhooks WHERE id = ?').run(req.params.id); res.json({ message: 'Webhook deleted successfully', webhookId: parseInt(req.params.id) }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Test webhook (admin only) router.post('/test/:id', authenticateToken, async (req, res) => { try { const webhook = db.prepare('SELECT * FROM webhooks WHERE id = ?').get(req.params.id); if (!webhook) { return res.status(404).json({ error: 'Webhook not found' }); } // Send a test payload const testData = { session: { id: 0, is_active: true, games_played: 0 }, game: { id: 0, title: 'Test Game', pack_name: 'Test Pack', min_players: 2, max_players: 8, manually_added: false } }; // Trigger the webhook asynchronously triggerWebhook('game.added', testData); res.json({ message: 'Test webhook sent', note: 'Check webhook_logs table for delivery status' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Get webhook logs (admin only) router.get('/:id/logs', authenticateToken, (req, res) => { try { const { limit = 50 } = req.query; const logs = db.prepare(` SELECT * FROM webhook_logs WHERE webhook_id = ? ORDER BY created_at DESC LIMIT ? `).all(req.params.id, parseInt(limit)); // Parse payload JSON for each log const logsWithParsedPayload = logs.map(log => ({ ...log, payload: JSON.parse(log.payload) })); res.json(logsWithParsedPayload); } catch (error) { res.status(500).json({ error: error.message }); } }); module.exports = router;