Add automatic synchronization scheduler that allows users to configure periodic sync intervals for LoTW and DCL via the settings page. Features: - Users can enable/disable auto-sync per service (LoTW/DCL) - Configurable sync intervals (1-720 hours) - Settings page UI for managing auto-sync preferences - Dashboard shows upcoming scheduled auto-sync jobs - Scheduler runs every minute, triggers syncs when due - Survives server restarts via database persistence - Graceful shutdown support (SIGINT/SIGTERM) Backend: - New autoSyncSettings table with user preferences - auto-sync.service.js for CRUD operations and scheduling logic - scheduler.service.js for periodic tick processing - API endpoints: GET/PUT /auto-sync/settings, GET /auto-sync/scheduler/status Frontend: - Auto-sync settings section in settings page - Upcoming auto-sync section on dashboard with scheduled job cards - Purple-themed UI for scheduled jobs with countdown animation Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
3.3 KiB
JavaScript
112 lines
3.3 KiB
JavaScript
/**
|
|
* Migration: Add auto_sync_settings table
|
|
*
|
|
* This script creates the auto_sync_settings table for managing
|
|
* automatic sync intervals for DCL and LoTW services.
|
|
* Users can enable/disable auto-sync and configure sync intervals.
|
|
*/
|
|
|
|
import Database from 'bun:sqlite';
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
// ES module equivalent of __dirname
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const dbPath = join(__dirname, '../award.db');
|
|
const sqlite = new Database(dbPath);
|
|
|
|
async function migrate() {
|
|
console.log('Starting migration: Add auto-sync settings...');
|
|
|
|
try {
|
|
// Check if auto_sync_settings table already exists
|
|
const tableExists = sqlite.query(`
|
|
SELECT name FROM sqlite_master
|
|
WHERE type='table' AND name='auto_sync_settings'
|
|
`).get();
|
|
|
|
if (tableExists) {
|
|
console.log('Table auto_sync_settings already exists. Skipping...');
|
|
} else {
|
|
// Create auto_sync_settings table
|
|
sqlite.exec(`
|
|
CREATE TABLE auto_sync_settings (
|
|
user_id INTEGER PRIMARY KEY,
|
|
lotw_enabled INTEGER NOT NULL DEFAULT 0,
|
|
lotw_interval_hours INTEGER NOT NULL DEFAULT 24,
|
|
lotw_last_sync_at INTEGER,
|
|
lotw_next_sync_at INTEGER,
|
|
dcl_enabled INTEGER NOT NULL DEFAULT 0,
|
|
dcl_interval_hours INTEGER NOT NULL DEFAULT 24,
|
|
dcl_last_sync_at INTEGER,
|
|
dcl_next_sync_at INTEGER,
|
|
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),
|
|
updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
)
|
|
`);
|
|
|
|
// Create index for faster queries on next_sync_at
|
|
sqlite.exec(`
|
|
CREATE INDEX idx_auto_sync_settings_lotw_next_sync_at
|
|
ON auto_sync_settings(lotw_next_sync_at)
|
|
WHERE lotw_enabled = 1
|
|
`);
|
|
|
|
sqlite.exec(`
|
|
CREATE INDEX idx_auto_sync_settings_dcl_next_sync_at
|
|
ON auto_sync_settings(dcl_next_sync_at)
|
|
WHERE dcl_enabled = 1
|
|
`);
|
|
|
|
console.log('Created auto_sync_settings table with indexes');
|
|
}
|
|
|
|
console.log('Migration complete! Auto-sync settings table added to database.');
|
|
} catch (error) {
|
|
console.error('Migration failed:', error);
|
|
sqlite.close();
|
|
process.exit(1);
|
|
}
|
|
|
|
sqlite.close();
|
|
}
|
|
|
|
async function rollback() {
|
|
console.log('Starting rollback: Remove auto-sync settings...');
|
|
|
|
try {
|
|
// Drop indexes first
|
|
sqlite.exec(`DROP INDEX IF EXISTS idx_auto_sync_settings_lotw_next_sync_at`);
|
|
sqlite.exec(`DROP INDEX IF EXISTS idx_auto_sync_settings_dcl_next_sync_at`);
|
|
|
|
// Drop table
|
|
sqlite.exec(`DROP TABLE IF EXISTS auto_sync_settings`);
|
|
|
|
console.log('Rollback complete! Auto-sync settings table removed from database.');
|
|
} catch (error) {
|
|
console.error('Rollback failed:', error);
|
|
sqlite.close();
|
|
process.exit(1);
|
|
}
|
|
|
|
sqlite.close();
|
|
}
|
|
|
|
// Check if this is a rollback
|
|
const args = process.argv.slice(2);
|
|
if (args.includes('--rollback') || args.includes('-r')) {
|
|
rollback().then(() => {
|
|
console.log('Rollback script completed successfully');
|
|
process.exit(0);
|
|
});
|
|
} else {
|
|
// Run migration
|
|
migrate().then(() => {
|
|
console.log('Migration script completed successfully');
|
|
process.exit(0);
|
|
});
|
|
}
|