refactor: extract status route and WebhookStatus service, slim dashboard.js
- Extract /status route to server/routes/status.js - Create server/services/WebhookStatus.js with checkWebhookConfigured and aggregateMetrics - Slim dashboard.js to pure HTTP orchestration (559→283 lines, 49.4% reduction) - Remove /user-summary and /webhook-metrics routes from dashboard.js - Mount status router at /api/status in server/index.js and server/app.js - Update tests to use new /api/status/status endpoint - Fix test expectation for speed field (number vs string) All 571 tests passing.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2026 Gordon Bolton. MIT License.
|
||||
const axios = require('axios');
|
||||
const { getSonarrInstances, getRadarrInstances } = require('../utils/config');
|
||||
|
||||
/**
|
||||
* Check if Sofarr webhook is configured in a Sonarr/Radarr instance.
|
||||
* @param {Object} instance - The Sonarr/Radarr instance config
|
||||
* @param {string} type - 'Sonarr' or 'Radarr'
|
||||
* @returns {Promise<boolean>} true if webhook is configured
|
||||
*/
|
||||
async function checkWebhookConfigured(instance, type) {
|
||||
try {
|
||||
const response = await axios.get(`${instance.url}/api/v3/notification`, {
|
||||
headers: { 'X-Api-Key': instance.apiKey },
|
||||
timeout: 5000
|
||||
});
|
||||
const notifications = response.data || [];
|
||||
return notifications.some(n => n.name === 'Sofarr' && n.implementation === 'Webhook');
|
||||
} catch (err) {
|
||||
console.log(`[WebhookStatus] Failed to check ${type} webhook config: ${err.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregate webhook metrics for a service type.
|
||||
* @param {Object} metricsMap - Map of instance URLs to their metrics
|
||||
* @param {boolean} configured - Whether the service is configured
|
||||
* @returns {Object|null} Aggregated metrics or null if not configured
|
||||
*/
|
||||
function aggregateMetrics(metricsMap, configured) {
|
||||
const values = Object.values(metricsMap);
|
||||
if (values.length === 0) {
|
||||
// Return default metrics if configured but no events yet
|
||||
return configured ? {
|
||||
enabled: true,
|
||||
eventsReceived: 0,
|
||||
pollsSkipped: 0,
|
||||
lastEvent: null
|
||||
} : null;
|
||||
}
|
||||
return {
|
||||
enabled: true,
|
||||
eventsReceived: values.reduce((sum, m) => sum + (m.eventsReceived || 0), 0),
|
||||
pollsSkipped: values.reduce((sum, m) => sum + (m.pollsSkipped || 0), 0),
|
||||
lastEvent: values.reduce((latest, m) => {
|
||||
return m.lastWebhookTimestamp > latest ? m.lastWebhookTimestamp : latest;
|
||||
}, 0)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkWebhookConfigured,
|
||||
aggregateMetrics
|
||||
};
|
||||
Reference in New Issue
Block a user