272 lines
6.7 KiB
JavaScript
272 lines
6.7 KiB
JavaScript
|
|
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;
|
||
|
|
|