fix: Settings persistence - save to database and process.env

This commit is contained in:
nmemmert committed 2026-01-14 15:24:42 -05:00
1 parent db85573986
commit 64b3852d53
1 file changed
+102 -36
+102 -36
View File
@@ -516,41 +516,84 @@ app.post('/api/notifications/clear', (req, res) => {
// Get settings // Get settings
app.get('/api/settings', (req, res) => { app.get('/api/settings', (req, res) => {
const settings = { // Try to get settings from database first, fallback to process.env
email_enabled: process.env.EMAIL_ENABLED === 'true', try {
email_host: process.env.EMAIL_HOST || 'smtp.gmail.com', const dbSettings = {};
email_port: parseInt(process.env.EMAIL_PORT) || 587, const rows = db.prepare('SELECT key, value FROM settings').all();
email_user: process.env.EMAIL_USER || '', for (const row of rows) {
email_pass: '', // Don't send password to client dbSettings[row.key] = row.value;
email_from: process.env.EMAIL_FROM || '', }
email_to: process.env.EMAIL_TO || '',
webhook_enabled: process.env.WEBHOOK_ENABLED === 'true', // Build response with database values taking precedence over env vars
webhook_url: process.env.WEBHOOK_URL || '', const settings = {
check_interval: parseInt(process.env.CHECK_INTERVAL) || 60000, email_enabled: (dbSettings.email_enabled || process.env.EMAIL_ENABLED) === 'true',
timeout: parseInt(process.env.TIMEOUT) || 5000, email_host: dbSettings.email_host || process.env.EMAIL_HOST || 'smtp.gmail.com',
timezone: process.env.TIMEZONE || 'UTC', email_port: parseInt(dbSettings.email_port || process.env.EMAIL_PORT) || 587,
// Data retention settings email_user: dbSettings.email_user || process.env.EMAIL_USER || '',
retention_days: parseInt(process.env.RETENTION_DAYS) || 7, email_pass: '', // Don't send password to client
auto_cleanup_enabled: process.env.AUTO_CLEANUP_ENABLED === 'true', email_from: dbSettings.email_from || process.env.EMAIL_FROM || '',
// Incident thresholds email_to: dbSettings.email_to || process.env.EMAIL_TO || '',
consecutive_failures: parseInt(process.env.CONSECUTIVE_FAILURES) || 3, webhook_enabled: (dbSettings.webhook_enabled || process.env.WEBHOOK_ENABLED) === 'true',
grace_period: parseInt(process.env.GRACE_PERIOD) || 300, webhook_url: dbSettings.webhook_url || process.env.WEBHOOK_URL || '',
downtime_threshold: parseInt(process.env.DOWNTIME_THRESHOLD) || 600, check_interval: parseInt(dbSettings.check_interval || process.env.CHECK_INTERVAL) || 60000,
// Alert retry logic timeout: parseInt(dbSettings.timeout || process.env.TIMEOUT) || 5000,
alert_retry_count: parseInt(process.env.ALERT_RETRY_COUNT) || 3, timezone: dbSettings.timezone || process.env.TIMEZONE || 'UTC',
alert_retry_delay: parseInt(process.env.ALERT_RETRY_DELAY) || 60, // Data retention settings
fallback_webhook: process.env.FALLBACK_WEBHOOK || '', retention_days: parseInt(dbSettings.retention_days || process.env.RETENTION_DAYS) || 7,
// Alert scheduling auto_cleanup_enabled: (dbSettings.auto_cleanup_enabled || process.env.AUTO_CLEANUP_ENABLED) === 'true',
global_quiet_hours_start: process.env.GLOBAL_QUIET_HOURS_START || '', // Incident thresholds
global_quiet_hours_end: process.env.GLOBAL_QUIET_HOURS_END || '', consecutive_failures: parseInt(dbSettings.consecutive_failures || process.env.CONSECUTIVE_FAILURES) || 3,
escalation_hours: parseInt(process.env.ESCALATION_HOURS) || 4, grace_period: parseInt(dbSettings.grace_period || process.env.GRACE_PERIOD) || 300,
// Dashboard customization downtime_threshold: parseInt(dbSettings.downtime_threshold || process.env.DOWNTIME_THRESHOLD) || 600,
default_sort: process.env.DEFAULT_SORT || 'name', // Alert retry logic
items_per_page: parseInt(process.env.ITEMS_PER_PAGE) || 20, alert_retry_count: parseInt(dbSettings.alert_retry_count || process.env.ALERT_RETRY_COUNT) || 3,
refresh_interval: parseInt(process.env.REFRESH_INTERVAL) || 5000, alert_retry_delay: parseInt(dbSettings.alert_retry_delay || process.env.ALERT_RETRY_DELAY) || 60,
theme: process.env.THEME || 'light', fallback_webhook: dbSettings.fallback_webhook || process.env.FALLBACK_WEBHOOK || '',
}; // Alert scheduling
res.json(settings); global_quiet_hours_start: dbSettings.global_quiet_hours_start || process.env.GLOBAL_QUIET_HOURS_START || '',
global_quiet_hours_end: dbSettings.global_quiet_hours_end || process.env.GLOBAL_QUIET_HOURS_END || '',
escalation_hours: parseInt(dbSettings.escalation_hours || process.env.ESCALATION_HOURS) || 4,
// Dashboard customization
default_sort: dbSettings.default_sort || process.env.DEFAULT_SORT || 'name',
items_per_page: parseInt(dbSettings.items_per_page || process.env.ITEMS_PER_PAGE) || 20,
refresh_interval: parseInt(dbSettings.refresh_interval || process.env.REFRESH_INTERVAL) || 5000,
theme: dbSettings.theme || process.env.THEME || 'light',
};
res.json(settings);
} catch (error) {
console.error('Error reading settings:', error);
// Fallback to env vars only if database read fails
const settings = {
email_enabled: process.env.EMAIL_ENABLED === 'true',
email_host: process.env.EMAIL_HOST || 'smtp.gmail.com',
email_port: parseInt(process.env.EMAIL_PORT) || 587,
email_user: process.env.EMAIL_USER || '',
email_pass: '', // Don't send password to client
email_from: process.env.EMAIL_FROM || '',
email_to: process.env.EMAIL_TO || '',
webhook_enabled: process.env.WEBHOOK_ENABLED === 'true',
webhook_url: process.env.WEBHOOK_URL || '',
check_interval: parseInt(process.env.CHECK_INTERVAL) || 60000,
timeout: parseInt(process.env.TIMEOUT) || 5000,
timezone: process.env.TIMEZONE || 'UTC',
retention_days: parseInt(process.env.RETENTION_DAYS) || 7,
auto_cleanup_enabled: process.env.AUTO_CLEANUP_ENABLED === 'true',
consecutive_failures: parseInt(process.env.CONSECUTIVE_FAILURES) || 3,
grace_period: parseInt(process.env.GRACE_PERIOD) || 300,
downtime_threshold: parseInt(process.env.DOWNTIME_THRESHOLD) || 600,
alert_retry_count: parseInt(process.env.ALERT_RETRY_COUNT) || 3,
alert_retry_delay: parseInt(process.env.ALERT_RETRY_DELAY) || 60,
fallback_webhook: process.env.FALLBACK_WEBHOOK || '',
global_quiet_hours_start: process.env.GLOBAL_QUIET_HOURS_START || '',
global_quiet_hours_end: process.env.GLOBAL_QUIET_HOURS_END || '',
escalation_hours: parseInt(process.env.ESCALATION_HOURS) || 4,
default_sort: process.env.DEFAULT_SORT || 'name',
items_per_page: parseInt(process.env.ITEMS_PER_PAGE) || 20,
refresh_interval: parseInt(process.env.REFRESH_INTERVAL) || 5000,
theme: process.env.THEME || 'light',
};
res.json(settings);
}
}); });
// Save settings // Save settings
@@ -657,7 +700,7 @@ THEME=${theme || 'light'}
try { try {
fs.writeFileSync(envPath, envContent); fs.writeFileSync(envPath, envContent);
// Keep runtime config in sync without requiring a restart // Update runtime config in process.env - these changes persist until server restart
process.env.TIMEZONE = timezone || 'UTC'; process.env.TIMEZONE = timezone || 'UTC';
process.env.EMAIL_ENABLED = String(email_enabled); process.env.EMAIL_ENABLED = String(email_enabled);
process.env.EMAIL_HOST = email_host; process.env.EMAIL_HOST = email_host;
@@ -686,6 +729,28 @@ THEME=${theme || 'light'}
process.env.REFRESH_INTERVAL = String(refresh_interval || 5000); process.env.REFRESH_INTERVAL = String(refresh_interval || 5000);
process.env.THEME = theme || 'light'; process.env.THEME = theme || 'light';
// Also save to database for persistence
const settingsTable = [
{ key: 'email_enabled', value: String(email_enabled) },
{ key: 'email_host', value: email_host },
{ key: 'email_port', value: String(email_port) },
{ key: 'email_user', value: email_user },
{ key: 'email_from', value: email_from },
{ key: 'email_to', value: email_to },
{ key: 'webhook_enabled', value: String(webhook_enabled) },
{ key: 'webhook_url', value: webhook_url },
{ key: 'timezone', value: timezone || 'UTC' },
{ key: 'retention_days', value: String(retention_days || 7) },
{ key: 'consecutive_failures', value: String(consecutive_failures || 3) },
];
for (const setting of settingsTable) {
db.prepare(`
INSERT OR REPLACE INTO settings (key, value, updated_at)
VALUES (?, ?, CURRENT_TIMESTAMP)
`).run(setting.key, setting.value);
}
notificationService.setConfig({ notificationService.setConfig({
email_enabled: email_enabled === true || email_enabled === 'true', email_enabled: email_enabled === true || email_enabled === 'true',
email_host, email_host,
@@ -700,6 +765,7 @@ THEME=${theme || 'light'}
res.json({ message: 'Settings saved successfully' }); res.json({ message: 'Settings saved successfully' });
} catch (error) { } catch (error) {
console.error('Failed to save settings:', error);
res.status(500).json({ error: 'Failed to save settings' }); res.status(500).json({ error: 'Failed to save settings' });
} }
}); });